登录  | 立即注册

游客您好!登录后享受更多精彩

扫一扫,访问微社区

QQ登录

只需一步,快速开始

开启左侧

[寒假笔记] LCD1602时序问题

[复制链接]
发表于 2021-1-30 15:57:56 | 显示全部楼层 |阅读模式
学习笔记
学习科目: 单片机
学习安排: 解决电开开发板的时序问题
开始时间: 2021-01-30
结束时间: 2021-01-30
    更着金沙滩学习单片机,发现按照他的程序打并不能实现液晶屏的显示。然后把书往后翻了一下,发现了问题所在——时序。
之所以金沙滩的没有这个问题是因为他的单片机是12T的(一个机器周期=12个时钟周期)而我们的是1T的速度是他的12倍,所谓机器周期就是完成一个操作的最短时间。由于我们的单片机工作的很快就不得不考虑LCD的时序问题。
    时序问题有两个:
1,顺序问题:这个简单易懂,比如我们在写1602的指令的时候,RS = L;R/W = L;D0~D7 = 指令码;这三个顺序无所谓,但E=高脉冲必须放在这三个之后。
2,时间问题:这个是重点。对于我们LCD来说除了保证顺序问题对之外,还要保证他们之间的间隔要求。

QQ图片20210130145323.jpg QQ图片20210130145347.jpg QQ图片20210130145353.jpg QQ图片20210130145359.jpg

我们的单片机的一个机器周期(完成一个操作的最短时间)差不多是30ns,这上面对每一个时间段解释的都很清楚,我们重点关注在Tpw,Tsp2上也就是E = 高脉冲的前面,和E = 1; E = 0;的中间。Tpw是说E = 高脉冲的持续时间最短是100ns,显然我们是不够的所以我们要在E = 1;与E = 0;之间加一个延迟,让他满足条件。
        Tsp2:他是指在DB总线准备好后至少保持40ns,使能引脚E才能从低电平到高进行使能变化。
#include <STC12C5A60S2.H>
#include <intrins.h>

#define LCD1602_DB  P0
sbit LCD1602_RS = P2^0;
sbit LCD1602_RW = P2^1;
sbit LCD1602_E  = P1^2;

void InitLcd1602();
void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
void Delay1us()                //@33.1776MHz
{
        unsigned char i;

        _nop_();
        _nop_();
        _nop_();
        i = 5;
        while (--i);
}

void main()
{
    unsigned char str[] = "Hello HPUEDD";

    InitLcd1602();
    LcdShowStr(2, 0, str);
    LcdShowStr(0, 1, "Tech & Service");
    while (1);
}
/* 等待液晶准备好 */
void LcdWaitReady()
{
    unsigned char sta;

    LCD1602_DB = 0xFF;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do {
        LCD1602_E = 1;
               
        sta = LCD1602_DB;//读取状态字
                     
        LCD1602_E = 0;
    } while (sta & 0x80); //bit7等于1表示液晶正忙,重复检测直到其等于0为止
}
/* 向LCD1602液晶写入一字节命令,cmd-待写入命令值 */
void LcdWriteCmd(unsigned char cmd)
{
    LcdWaitReady();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
        LCD1602_DB = cmd;
    Delay1us();
        LCD1602_E  = 1;//读取状态字
        Delay1us();
    LCD1602_E  = 0;

       
}
/* 向LCD1602液晶写入一字节数据,dat-待写入数据值 */
void LcdWriteDat(unsigned char dat)
{
    LcdWaitReady();
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DB = dat;
        Delay1us();
    LCD1602_E  = 1;
        Delay1us();
    LCD1602_E  = 0;
       
}
/* 设置显示RAM起始地址,亦即光标位置,(x,y)-对应屏幕上的字符坐标 */
void LcdSetCursor(unsigned char x, unsigned char y)
{
    unsigned char addr;

    if (y == 0)  //由输入的屏幕坐标计算显示RAM的地址
        addr = 0x00 + x;  //第一行字符地址从0x00起始
    else
        addr = 0x40 + x;  //第二行字符地址从0x40起始
    LcdWriteCmd(addr | 0x80);  //设置RAM地址
}
/* 在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,str-字符串指针 */
void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str)
{
    LcdSetCursor(x, y);
    Delay1us();        //设置起始地址
    while (*str != '\0')  //连续写入字符串数据,直到检测到结束符
    {
        LcdWriteDat(*str++);  //先取str指向的数据,然后str自加1
    }
}
/* 初始化1602液晶 */
void InitLcd1602()
{
    LcdWriteCmd(0x38);  //16*2显示,5*7点阵,8位数据接口
    LcdWriteCmd(0x0C);  //显示器开,光标关闭
    LcdWriteCmd(0x06);  //文字不动,地址自动+1
    LcdWriteCmd(0x01);  //清屏
}


    还有一点值得注意的是LCD的3引脚是用来调整对比度的,它可以使我们的显示屏清晰,就位于开发板的左上方,我之前没有调整,就一直没有什么显示,耽误了好长时间。


好懒~~不想说~~~
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表