LCD1602液晶显示模块

这篇具有很好参考价值的文章主要介绍了LCD1602液晶显示模块。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.认识LCD1602

1、概述:

  1. LCD1602(Liquid Crystal Display)是一种工业字符型液晶,能够同时显示 16×02,32个 字符(16列两行)。是我们接触引脚最多的模块。
  2. LCD1602我们的非标准协议(标准协议有IIC、IIS、SPI)中比较容易懂的玩法。

lcd1602液晶显示模块,单片机

2、引脚说明:翻阅LCD1602说明书

  • 共有16根引脚,如下表:
    编号 符号 引脚说明 编号 符号 引脚说明
    1 VSS 电源地 9 D2 双向数据线
    2 VDD 电源正极,接5V正电源 10 D3 双向数据线
    3 V0 液晶显示偏压。是液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高会产生“鬼影”(四方框影像),使用时可以通过一个10K电位器调整对比度。 11 D4 双向数据线
    4 RS 数据/命令寄存器选择,高电平时选择数据寄存器,低电平时选择指令寄存器。一会看时序图 12 D5 双向数据线
    5 R/W 读/写选择。高电平时进行读操作,低电平时进行写操作。一会看时序图 13 D6 双向数据线
    6 E 使能信号。当E端由高电平跳变为低电平时,液晶模块执行命令。 14 D7 双向数据线
    7 D0 双向数据线 15 BLA 背光源正极
    8 D1 双向数据线 16 BLK 背光源负极
  • 数据线占8根,有点像串口的SBUF(8位数据缓冲寄存器),单片机和LCD之间的数据交互也需要类似于SBUF的东西,但是不幸的是LCD1602没有串口,所以我们用一组I/O口(D0~D7)表示。

  • RS和R/W引脚可以配合使用:
    RS高电平 RS低电平
    R/W高电平 读忙信号
    R/W低电平 写入内容 写入指令或者写入显示地址

3、控制指令:翻阅LCD1602说明书。

  • LCD1602液晶显示模块的读写操作,屏幕和光标的操作都是通过指令编程来实现的。
  • LCD1602液晶显示模块内部的控制器共有11条控制指令,是配合RS、R/W和8根数据线实现的,如下表:
序号 指令 RS R/W D7 D6 D5 D4 D3 D2 D1 D0 指令说明
1 清除显示 0 0 0 0 0 0 0 0 0 1 清显示,指令码01H,光标复位到地址00H位置
2 光标返回 0 0 0 0 0 0 0 0 1 * 光标复位,光标返回到地址00H
3 置输入模式 0 0 0 0 0 0 0 1 I/F S 光标和显示模式设置。I/D:光标移动方向,高电平右移,低电平左移。实际上就是控制从左到右写入还是从右至左的写入顺序。S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效。S=1 当写一个字符,整屏显示左移(ID=1)或者右移(I/D=0),以得到光标不移动而屏幕移动的效果。S=0 当写一个字符,整屏显示不移动。
4 显示开/关控制 0 0 0 0 0 0 1 D C B 显示开关控制。D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示.  C:控制光标的开与关,高电平表示有光标,低电平表示无光标. B:控制光标是否闪烁,高电平闪烁,低电平不闪烁
5 光标或字符移位 0 0 0 0 0 1 S/C R/L * * 光标或显示移位S/C:高电平时移动显示的文字,低电平时移动光标。R/L:文字或者光标移动方向,R表示右移,L表示左移
6 置功能 0 0 0 0 1 DL N F * * 功能设置命令DL:高电平时为8位总线,低电平时为4位总线。N:低电平时为单行显示,高电平时双行显示。F:低电平时显示5×8的点阵字符,高电平时显示5×0的点阵字符
7 置字符发生存储器地址 0 0 0 1 字符发生存储器地址(自定义字符) 字符发生器RAM地址设置
8 置数据存储器地址  0  0  1  显示数据存储器地址(在哪里显示 DDRAM地址设置
9 读忙标志或地址  0   1  BF 计算器地址 读忙信号和光标地址。BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
10 写数到CGRAM或DDRAM  1  0 要写的数据内容(显示什么 写数据
11 从CGRAM或DDRAM读数 1 1 读出的数据内容 读数据


2.开发逻辑

1、和单片机的接线方法:lcd1602液晶显示模块,单片机

 

  1. 两组电源线
    1. VSS——GND
    2. VDD——5V
    3. A——5V
    4. K——GND
  2. 对比度:V0——GND
  3. 控制线
    1. RS——P1.0
    2. R/W——P1.1
    3. E——P1.4
  4. 数据线:D0到D7——P0.0到P0.7
    1. 注:之前讲过51单片机的P0口组没有上拉电阻,作为总线扩展不用加上拉电阻,作为I/O口使用时需要上拉电阻。

2、搞清在哪显示:

  • 在哪里显示是依靠D0~D7这8根数据线来实现的。以前PC和51单片机用串口通讯,51单片机上有专门的SBUF寄存器,现在LCD1602上没有专门的SBUF寄存器,所以说只能用8根数据线来替代。
  • 如下左图是LCD的内部显示地址,我们只要告知LCD1602将来要在哪个位置写什么数据就能实现如右图的效果,图中的地址码是16进制的。DDRAM 是显示用RAM,直接和屏幕上的点相对应,屏幕上的一个点和DDRAM中的一个位对应。lcd1602液晶显示模块,单片机

 

  • 注意到LCD1602共有32个字符,而25=32,是否用5bit就能表示显示的地址呢?答:确实是这样的,但是除了屏幕上可以显示的32个字符数据以外,还有我们肉眼看不到的显示地址(如上左图所示),实际上LCD1602通过指令可以实现数据移位的效果(1602液晶屏一行显示16个,对应于00-0F/40-4F,而DDRAM可以储存80个,如果需要显示10-27以及50-67的内容就需要用到左移右移来实现),但是我们目前用不到这么复杂。
  • 真正的显示地址:如上左图的显示地址并不是我们编程时需要的显示地址。真正的地址要求bit7一定是1(在1.3控制指令表中提到:写入显示地址时要求最高位D7恒定为高电平1),剩下的才是我们需要设置的位置,比如我们想在05这个显示地址显示字符'N',05的二进制是0000 0101,但实际上规定显示地址的bit7是1,所以说05位置真正的显示地址是0x80(1000 0000)+ 0x05(0000 0101)= 0x85(1000 0101),所以编程时写0x85。

3、搞清显示什么:

  • 显示什么也是依靠D0~D7这8根数据线来实现的。
  • 如下表是LCD1602模块字库表。1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:阿拉伯数字,英文字母的大小写,常用的符号,和日文假名等,每一个字符都有一个固定的代码,对于我们常用的数字和字母来说,这些代码就是ASCII码。比如小写字母'a',我们查表得到高位是0110,低位是0001。转换成十进制就是97,也就是'a'的ASCII码。所以说让单片机告诉LCD显示模块显示什么就变得很简单,对编程来说只需要直接写字母即可,不需要像显示地址一样写16进制数。lcd1602液晶显示模块,单片机

 

  • CGRAM : 允许用户自建字模区存储器,从LCD1602模块字库表的最左侧可以看见。具体信息可以百度。

4、如何区分显示地址和显示内容:

  • 51单片机的P0这个I/O口组有两个任务,一个是通过LCD上的8根数据线来告诉LCD显示模块在哪里显示,另一个是通过LCD上的8根数据线来告诉LCD显示模块要显示什么字符。那么LCD显示模块如何区分51单片机发送来的显示位置和显示内容呢?答:RS,它是数据/命令选择位。也就是说确定这8位是字符'a'的ASCII码时,把RS配置成1,选择数据寄存器;当确定这8位是显示的地址时,把RS配置成0,选择指令寄存器

3.读/写操作时序

阅读时序图,需要关心以下三点:开始、结束、转折。

0、时序参数:

lcd1602液晶显示模块,单片机

1、写操作时序分析:51单片机无论是给LCD模块输入地址还是内容,LCD显示模块都是被写入的那个,所以我们要学习写操作时序图。

lcd1602液晶显示模块,单片机

  1. RS:引脚功能回看1.2引脚说明:数据/指令寄存器选择位。
    1. 看时序图:写操作时RS可以是高电平也可以是低电平,暂时不确定
    2. 回看1.2引脚说明:RS只看开始和结束,在R/W为0的前提下,RS为1代表写内容,RS为0代表写指令(地址),中间不需要转折。
    3. 根据功能,封装写内容和写指令这两个函数即可。
  2. R/W:引脚功能回看1.2引脚说明:读/写选择位。
    1. 看时序图:写操作开始(可以是高电平也可以是低电平)——> 中间在数据传输时必须是低电平 ——> 写操作结束(可以是高电平也可以是低电平)
    2. 回看1.2引脚说明:只有在R/W是低电平时,才能保证RS在高低电平切换时写入内容或者写入指令(地址)。
    3. 因此,全程把R/W配置成0就可以了,不用去管时序图中的时间。
  3. DB0~DB7:就相当于SBUF(回顾串口的接收/发送时序图),只不过这里LCD写操作的一帧数据是由引脚E控制的。
    1. 看时序图:可高可低,取决于写入的数据。
    2. 看时序图和时序参数图:有一个数据建立时间tSP2,也就是说在E=0(没被拉高前)时,就开始往LCD写数据;同时有一个数据保持时间tHD2,也就是在E变回0后,还保持一段数据写入的时间。
  4. E:引脚功能回看1.2引脚说明。使能信号从高电平到低电平时,LCD模块执行命令。
    1. 看时序图:开始是低电平——> 延时一段时间 ——> 中间转折为高电平(上升时间是tR) ——> 延时一段时间 ——> 中间转折为低电平(下降时间是tF) ——> 结束是低电平。
    2. 看时序参数图,tR和tF都是25ns,转折处持续的时间tpw是150ns。我们知道51单片机在11.0592MHz的晶振频率下的机器周期是1.085μs,所以给一个_nop_()就够了。
    3. 在写入数据(不论内容还是指令)时:E开始为0 ——> _nop_(); 延时1微秒 ——> P0口写数据 ——>  _nop_(); 延时1微秒 ——> E转折为1 ——> _nop_(); 延时1微秒(不够就2微秒) ——> E结束为0 ——> _nop_(); 延时1微秒。

2、读操作时序分析:液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。检测忙信号就是一个让LCD显示模块被读的过程,因此需要学习LCD的读操作时序分析。

lcd1602液晶显示模块,单片机

  1. RS:引脚功能回看1.2引脚说明:数据/指令寄存器选择位。
    1. 看时序图:读操作时RS可以是高电平也可以是低电平,暂时不确定
    2. 回看1.2引脚说明:RS只看开始和结束,在R/W为1的前提下,RS为0代表读忙信号,中间没什么好转折的。
    3. 所以:全程把RS配置成0。
  2. R/W:引脚功能回看1.2引脚说明:读/写选择位。
    1. 看时序图:读操作开始(可以是高电平也可以是低电平)——> 中间在读数据时必须是高电平 ——> 读操作结束(可以是高电平也可以是低电平)
    2. 回看1.2引脚说明:只有在R/W是高电平时,才能保证在读忙信号。
    3. 因此,全程把R/W配置成1就可以了,不用去管时序图中的时间。
  3. DB0~DB7:就相当于SBUF(回顾串口的接收/发送时序图),只不过这里LCD读操作的一帧数据是由引脚E控制的。
    1. 看图:可高可低,取决于读取的数据。
    2. 看时序图和时序参数图:有一个数据建立时间tD,也就是说在E拉高一段时间后才去读数据;同时有一个数据保持时间tHD2,也就是在E变回0后,还保持一段数据读取的时间。
  4. E:引脚功能回看1.2引脚说明。使能信号从高电平到低电平时,LCD模块执行命令。
    1. 看时序图:开始是低电平——> 延时一段时间 ——> 中间转折为高电平(上升时间是tR) ——> 延时一段时间 ——> 中间转折为低电平(下降时间是tF) ——> 结束是低电平。
    2. 看时序参数图,tR和tF都是25ns,转折处持续的时间tpw是150ns。我们知道51单片机在11.0592MHz的晶振频率下的机器周期是1.085μs,所以给一个_nop_()就够了。
    3. 在读忙信号时:E开始为0 ——> _nop_(); 延时1微秒 ——> E转折为1 ——>  _nop_(); 延时1微秒(不够就2微秒)——> P0口读数据 ——>  _nop_(); 延时1微秒 ——> E结束为0 ——> _nop_(); 延时1微秒。

3、忙信号检测:

  • 回看1.3控制指令:指令9中提到忙信号的检测标志位是BF,也就是D7这根数据总线。BF高电平为忙,低电平为不忙,只有在不忙的时候我们才能做动作(写操作,不论是写内容还是写指令)。
  • 编程时判断LCD是否在忙,就是判断51单片机从P0这个I/O口组的P0.7这一位是否是1,有两种方法(我们以下的程序中选用第二种方式):
    • 方式1:由于P0这个寄存器可位寻址,所以直接找到P0.7这一位,对它做判断即可
    • 方式2:不通过位寻址,对P0做位与运算,进行取位操作,方法是将除了bit7以外的位都“置0”,bit7保持不变,即 P0 & 0x80,如果P0 & 0x80 的运算结果是0,说明P0的bit7是0,如果运算结果不是0,说明P0的bit7是1。

4.LCD1602的初始化

1、LCD1602初始化过程(8bit):手册中总结好了,我们一会儿只需要封装一下初始化LCD的函数即可。

(1)延时15ms

(2)写指令38H(不检测忙信号)

(3)延时5ms

(4)以后每次写指令,读/写数据操作均需要检测忙信号

(5)写指令38H:显示模式设置

(6)写指令08H:显示关闭

(7)写指令01H:显示清屏

(8)写指令06H:显示光标移动设置

(9)写指令0CH:显示开及光标设置

5.LCD显示demo

习题1(LCD显示一个字符):在LCD的第一行第六列的位置显示一个字符'N'

lcd1602液晶显示模块,单片机

  • 注:data是关键字,不要去用这个当做变量名
  1. 思路:
    宏定义:
    1. 定义符号dataBuffer,用它代表P0这个I/O口组: #define dataBuffer P0
    //dataBuffer的传递路线为: 
    //路线1:main函数: position ——> API1. LCD_write_cmd(char cmd); ——> cmd ——> dataBuffer ——> LCD
    //路线2:main函数:dataShow ——> API2. LCD_write_data(char datashow); ——> datashow ——> dataBuffer ——> LCD
    //路线3:API6. check_busy() ——> LCD ——> dataBuffer ——> temp
    全局变量:
    1. sbit指令找到P1这个I/O口组的第0位P1^0,把它与LCD的RS(LCD的数据/指令寄存器选择位)相连,用来输出指令给LCD: sbit RS = P1^0;
    2. sbit指令找到P1这个I/O口组的第0位P1^1,把它与LCD的RW(LCD的读/写选择位)相连,用来输出指令给LCD: sbit RW = P1^1;
    3. sbit指令找到P1这个I/O口组的第0位P1^4,把它与LCD的E(LCD的使能信号)相连,用来输出指令给LCD: sbit EN = P1^4;
    1. 根据LCD内部地址码,令显示地址为05H(第一行第六列),保存在字符变量position中:
    	char position = 0x80 + 0x05;
    2. 确认position这个地址上显示的字符是'N',保存在字符变量dataShow中: char dataShow = 'N';
    3. 调用API3. 初始化LCD1602: LCD1602_Init();
    4. 调用API1. 往LCD显示模块中写地址,告诉LCD字符'N'要显示的地址: LCD_write_cmd(position);
    5. 调用API2. 往LCD显示模块中写内容,紧接着告诉LCD显示的内容是'N': LCD_write_data(dataShow);
    /* 一级函数:f1、f2、f3 */
    f1. 封装往LCD液晶显示模块写指令的API: void LCD_write_cmd(char cmd); 
    //形参cmd是要写入的指令(地址)
    	f1.1 调用API6,对LCD操作前检测忙信号: check_busy();
        f1.2 RS低电平时,指令寄存器选择: RS = 0;
    	f1.3 RW低电平,表示写操作: RW = 0;
        f1.4 根据写操作的时序分析,总结出如下过程:
    		EN = 0;
    		_nop_();
    		dataBuffer = cmd;
    		_nop_();
    		EN = 1;
    		_nop_();
    		EN = 0;
    		_nop_();
    f2. 封装往LCD液晶显示模块写内容的API: void LCD_write_data(char datashow);	
    //形参datashow是要写入的内容
    	f2.1 调用API6,对LCD操作前检测忙信号: check_busy();
        f2.2 RS高电平时,数据寄存器选择: RS = 1;
    	f2.3 RW低电平,表示写操作: RW = 0;
        f2.4 根据写操作的时序分析,总结出如下过程:
    		EN = 0;
    		_nop_();
    		dataBuffer = datashow;
    		_nop_();
    		EN = 1;
    		_nop_();
    		EN = 0;
    		_nop_();
    f3. 封装初始化LCD液晶显示模块的API: void LCD1602_Init(); 
    	f3.1 调用API4,软件延时15ms: Delay15ms();
    	f3.2 调用API1,写指令38H(不检测忙信号): LCD_write_cmd(0x38);
    	f3.3 调用API5,软件延时5ms: Delay5ms();
    	f3.4 显示模式设置:
    		调用API6,检测忙信号: check_busy();
    		调用API1,写指令38H: LCD_write_cmd(0x38);	
    	f3.5 显示关闭:
    		调用API6,检测忙信号: check_busy();
    		调用API1,写指令08H: LCD_write_cmd(0x08);
    	f3.6 显示清屏:
    		调用API6,检测忙信号: check_busy();
    		调用API1,写指令01H: LCD_write_cmd(0x01);
    	f3.7 显示光标移动设置:
    		调用API6,检测忙信号: check_busy();
    		调用API1,写指令06H: LCD_write_cmd(0x06);
    	f3.8 显示开机光标设置:
    		调用API6,检测忙信号: check_busy();
    		调用API1,写指令0CH: LCD_write_cmd(0x0C);
    /* 二级函数:f1、f2、f4、f5、f6 */
    f1. 同上,也是一级函数: void LCD_write_cmd(char cmd);
    f2. 同上,也是一级函数: void LCD_write_data(char datashow);
    f4. 封装软件延时15ms的API,用于LCD初始化: void Delay15ms();
    f5. 封装软件延时5ms的API,用于LCD初始化: void Delay5ms();
    f6. 封装检测(读取)忙信号的API: void check_busy();
    	f6.1 将从P0这个I/O口组获取到的LCD的8位数据线的数据,保存在字符变量temp中: char temp = 0x80;
    	//内在逻辑:temp中包含了忙信号的标志位(bit7),标志位是1则表示LCD正忙,我们还没读取前
    	//就让51单片机认为LCD正忙,所以初始化为0x80(1000 0000),这样方便一会儿进入循环
    	f6.2 把LCD的busy这个状态做的更彻底一点,让P0这个I/O口组的bit7是1: dataBuffer = 0x80;
        f6.3 while循环,一直检测忙信号,直到检测到不忙,判据是:!((temp & 0x80)==0)
        //语法逻辑:用!表示“直到”,用 (temp & 0x80)==0 表示不忙。也就是说不忙就退出循环,不再检测
            f6.3.1 RS低电平时,指令寄存器选择: RS = 1;
    		f6.3.2 RW高电平,表示读操作: RW = 1;
            f6.3.3 根据读操作的时序分析,总结出如下过程:
    			EN = 0;
    			_nop_();
    			EN = 1;
    			_nop_();
    			temp = dataBuffer;
    			_nop_();
    			EN = 0;
    			_nop_();
  2. 代码:
    #include "reg52.h"
    #include "intrins.h"
    
    #define dataBuffer P0	//LCD的8位数据线,刚好用dataBuffer这个I/O口组
    sbit RS = P1^0;			//LCD的数据/指令寄存器选择位
    sbit RW = P1^1;			//LCD的读/写选择位
    sbit EN = P1^4;			//LCD的使能信号
    
    /* API1. LCD液晶显示模块写指令 */
    void LCD_write_cmd(char cmd);
    /* API2. LCD液晶显示模块写内容 */
    void LCD_write_data(char datashow);
    /* API3. 初始化LCD1602 */
    void LCD1602_Init();
    /* API4. 软件延时15ms,用于LCD初始化 */
    void Delay15ms();
    /* API5. 软件延时5ms,用于LCD初始化 */
    void Delay5ms();
    /* API6. 检测忙信号 */
    void check_busy();
    
    void main(void)
    {
    	char position = 0x80 + 0x05;	//显示地址:05H,第一行第六列
    	char dataShow = 'N';
    	LCD1602_Init();					//初始化LCD1602
    	LCD_write_cmd(position);		//选择要显示的地址
    	LCD_write_data(dataShow);		//发送要显示的字符
    }
    
    void LCD_write_cmd(char cmd)
    {
    	check_busy();
    	RS = 0;		//RS低电平时,指令寄存器选择,将1个字符写在数据线上告诉LCD这是指令
    	RW = 0;
    	EN = 0;
    	_nop_();
    	dataBuffer = cmd;
    	_nop_();
    	EN = 1;
    	_nop_();
    	EN = 0;
    	_nop_();
    }
    
    void LCD_write_data(char datashow)
    {
    	check_busy();
    	RS = 1;		//RS高电平时,数据寄存器选择,将1个字符写在数据线上告诉LCD这是内容
    	RW = 0;
    	EN = 0;
    	_nop_();
    	dataBuffer = datashow;
    	_nop_();
    	EN = 1;
    	_nop_();
    	EN = 0;
    	_nop_();
    }
    
    void LCD1602_Init()
    {
    	Delay15ms();			//(1)延时15ms
    	LCD_write_cmd(0x38);	//(2)写指令38H(不检测忙信号)
    	Delay5ms();				//(3)延时5ms
    	//(4)以后每次写指令,读/写数据操作均需要检测忙信号
    	check_busy();
    	LCD_write_cmd(0x38);	//(5)写指令38H:显示模式设置
    	check_busy();
    	LCD_write_cmd(0x08);	//(6)写指令08H:显示关闭
    	check_busy();
    	LCD_write_cmd(0x01);	//(7)写指令01H:显示清屏
    	check_busy();
    	LCD_write_cmd(0x06);	//(8)写指令06H:显示光标移动设置
    	check_busy();
    	LCD_write_cmd(0x0C);	//(9)写指令0CH:显示开及光标设置
    }
    
    void Delay15ms()		//@11.0592MHz
    {
    	unsigned char i, j;
    
    	i = 27;
    	j = 226;
    	do
    	{
    		while (--j);
    	} while (--i);
    }
    
    void Delay5ms()		//@11.0592MHz
    {
    	unsigned char i, j;
    
    	i = 9;
    	j = 244;
    	do
    	{
    		while (--j);
    	} while (--i);
    }
    
    void check_busy()
    {
    	char temp = 0x80;				//一开始就busy
    	dataBuffer = 0x80;
    	while( !((temp & 0x80)==0) ){	//一直检测忙信号,直到检测到不忙(temp的bit7为高电平代表忙)
    		RS = 0;
    		RW = 1;
    		EN = 0;
    		_nop_();
    		EN = 1;
    		_nop_();
    		temp = dataBuffer;
    		_nop_();
    		EN = 0;
    		_nop_();
    	}	
    }

习题2(LCD显示一行字符):

lcd1602液晶显示模块,单片机文章来源地址https://www.toymoban.com/news/detail-591934.html

  1. 思路:
    宏定义:
    1. 定义符号dataBuffer,用它代表P0这个I/O口组: #define dataBuffer P0
    //dataBuffer的传递路线为: 
    //路线1:main函数: position ——> API1. LCD_write_cmd(char cmd); ——> cmd ——> dataBuffer ——> LCD
    //路线2:main函数:dataShow ——> API2. LCD_write_data(char datashow); ——> datashow ——> dataBuffer ——> LCD
    //路线3:API6. check_busy() ——> LCD ——> dataBuffer ——> temp
    全局变量:
    1. sbit指令找到P1这个I/O口组的第0位P1^0,把它与LCD的RS(LCD的数据/指令寄存器选择位)相连,用来输出指令给LCD: sbit RS = P1^0;
    2. sbit指令找到P1这个I/O口组的第0位P1^1,把它与LCD的RW(LCD的读/写选择位)相连,用来输出指令给LCD: sbit RW = P1^1;
    3. sbit指令找到P1这个I/O口组的第0位P1^4,把它与LCD的E(LCD的使能信号)相连,用来输出指令给LCD: sbit EN = P1^4;
    1. 调用API3. 初始化LCD1602: LCD1602_Init();
    2. 调用API7. 在LCD模块的第1行的第5列位置开始显示字符串"NO.1": LCD1602_showLine(1,5,"NO.1");
    3. 调用API7. 在LCD模块的第2行的第0列位置开始显示字符串"chenlichen shuai":
    	LCD1602_showLine(2,0,"chenlichen shuai");
    /* 一级函数:f3、f7 */
    f3. 封装初始化LCD液晶显示模块的API: void LCD1602_Init(); 
    	f3.1 调用API4,软件延时15ms: Delay15ms();
    	f3.2 调用API1,写指令38H(不检测忙信号): LCD_write_cmd(0x38);
    	f3.3 调用API5,软件延时5ms: Delay5ms();
    	f3.4 显示模式设置:
    		调用API6,检测忙信号: check_busy();
    		调用API1,写指令38H: LCD_write_cmd(0x38);	
    	f3.5 显示关闭:
    		调用API6,检测忙信号: check_busy();
    		调用API1,写指令08H: LCD_write_cmd(0x08);
    	f3.6 显示清屏:
    		调用API6,检测忙信号: check_busy();
    		调用API1,写指令01H: LCD_write_cmd(0x01);
    	f3.7 显示光标移动设置:
    		调用API6,检测忙信号: check_busy();
    		调用API1,写指令06H: LCD_write_cmd(0x06);
    	f3.8 显示开机光标设置:
    		调用API6,检测忙信号: check_busy();
    		调用API1,写指令0CH: LCD_write_cmd(0x0C);
    f7. 封装在LCD液晶上显示一行字符串的API: void LCD1602_showLine(char row,char column,char *str);
    	形参row是行,column是列,str是要显示的字符串
        f7.1 定义一个字符指针变量p用来保存字符串首地址: char *p = str;
    	f7.2 switch选择语句,表达式为row
        	f7.2.1 当row为1时:表示在第一行显示字符串
            	f7.2.1.1 往LCD显示模块中写起始地址:
    				调用API6,检测忙信号: check_busy();
    				调用API1,告知显示地址为第1行第column列,LCD_write_cmd(0x80+column);
    			f7.2.1.2 while循环,控制循环的变量是*p,当*p != '\0' 时进入循环,发送要显示的内容:
    				调用API6,检测忙信号: check_busy();
    				调用API2. 往LCD显示模块中写当前字符指针p所在位置的字符: LCD_write_data(*p);
    				修改循环变量p的值,让指针p偏移: p++;
    			f7.2.1.3 break提前退出当前选择控制语句: break;
    		f7.2.2 当row为2时:表示在第二行显示字符串
            	f7.2.2.1 往LCD显示模块中写起始地址:
    				调用API6,检测忙信号: check_busy();
    				调用API1,告知显示地址为第2行第column列,LCD_write_cmd(0x80+0x40+column);
    			f7.2.2.2 while循环,控制循环的变量是*p,当*p != '\0' 时进入循环,发送要显示的内容:
    				调用API6,检测忙信号: check_busy();
    				调用API2. 往LCD显示模块中写当前字符指针p所在位置的字符: LCD_write_data(*p);
    				修改循环变量p的值,让指针p偏移: p++;
    			f7.2.2.3 break提前退出当前选择控制语句: break;
    /* 二级函数:f1、f2、f4、f5、f6 */
    f1. 封装往LCD液晶显示模块写指令的API: void LCD_write_cmd(char cmd); 
    //形参cmd是要写入的指令(地址)
    	f1.1 调用API6,对LCD操作前检测忙信号: check_busy();
        f1.2 RS低电平时,指令寄存器选择: RS = 0;
    	f1.3 RW低电平,表示写操作: RW = 0;
        f1.4 根据写操作的时序分析,总结出如下过程:
    		EN = 0;
    		_nop_();
    		dataBuffer = cmd;
    		_nop_();
    		EN = 1;
    		_nop_();
    		EN = 0;
    		_nop_();
    f2. 封装往LCD液晶显示模块写内容的API: void LCD_write_data(char datashow);	
    //形参datashow是要写入的内容
    	f2.1 调用API6,对LCD操作前检测忙信号: check_busy();
        f2.2 RS高电平时,数据寄存器选择: RS = 1;
    	f2.3 RW低电平,表示写操作: RW = 0;
        f2.4 根据写操作的时序分析,总结出如下过程:
    		EN = 0;
    		_nop_();
    		dataBuffer = datashow;
    		_nop_();
    		EN = 1;
    		_nop_();
    		EN = 0;
    		_nop_();
    f4. 封装软件延时15ms的API,用于LCD初始化: void Delay15ms();
    f5. 封装软件延时5ms的API,用于LCD初始化: void Delay5ms();
    f6. 封装检测(读取)忙信号的API: void check_busy();
    	f6.1 将从P0这个I/O口组获取到的LCD的8位数据线的数据,保存在字符变量temp中: char temp = 0x80;
    	//内在逻辑:temp中包含了忙信号的标志位(bit7),标志位是1则表示LCD正忙,我们还没读取前
    	//就让51单片机认为LCD正忙,所以初始化为0x80(1000 0000),这样方便一会儿进入循环
    	f6.2 把LCD的busy这个状态做的更彻底一点,让P0这个I/O口组的bit7是1: dataBuffer = 0x80;
        f6.3 while循环,一直检测忙信号,直到检测到不忙,判据是:!((temp & 0x80)==0)
        //语法逻辑:用!表示“直到”,用 (temp & 0x80)==0 表示不忙。也就是说不忙就退出循环,不再检测
            f6.3.1 RS低电平时,指令寄存器选择: RS = 1;
    		f6.3.2 RW高电平,表示读操作: RW = 1;
            f6.3.3 根据读操作的时序分析,总结出如下过程:
    			EN = 0;
    			_nop_();
    			EN = 1;
    			_nop_();
    			temp = dataBuffer;
    			_nop_();
    			EN = 0;
    			_nop_();
  2. 代码:
    #include "reg52.h"
    #include "intrins.h"
    
    #define dataBuffer P0	//LCD的8位数据线,刚好用dataBuffer这个I/O口组
    sbit RS = P1^0;			//LCD的数据/指令寄存器选择位
    sbit RW = P1^1;			//LCD的读/写选择位
    sbit EN = P1^4;			//LCD的使能信号
    
    /* API1. LCD液晶显示模块写指令 */
    void LCD_write_cmd(char cmd);
    /* API2. LCD液晶显示模块写内容 */
    void LCD_write_data(char datashow);
    /* API3. 初始化LCD1602 */
    void LCD1602_Init();
    /* API4. 软件延时15ms,用于LCD初始化 */
    void Delay15ms();
    /* API5. 软件延时5ms,用于LCD初始化 */
    void Delay5ms();
    /* API6. 检测忙信号 */
    void check_busy();
    /* API7. LCD1602显示一行 */
    void LCD1602_showLine(char row, char column, char *str);
    
    void main(void)
    {
    	LCD1602_Init();			//初始化LCD1602
    	LCD1602_showLine(1,5,"NO.1");
    	LCD1602_showLine(2,0,"chenlichen shuai");
    }
    
    void LCD_write_cmd(char cmd)
    {
    	check_busy();
    	RS = 0;		//RS低电平时,指令寄存器选择,将1个字符写在数据线上告诉LCD这是指令
    	RW = 0;
    	EN = 0;
    	_nop_();
    	dataBuffer = cmd;
    	_nop_();
    	EN = 1;
    	_nop_();
    	EN = 0;
    	_nop_();
    }
    
    void LCD_write_data(char datashow)
    {
    	check_busy();
    	RS = 1;		//RS高电平时,数据寄存器选择,将1个字符写在数据线上告诉LCD这是内容
    	RW = 0;
    	EN = 0;
    	_nop_();
    	dataBuffer = datashow;
    	_nop_();
    	EN = 1;
    	_nop_();
    	EN = 0;
    	_nop_();
    }
    
    void LCD1602_Init()
    {
    	Delay15ms();			//(1)延时15ms
    	LCD_write_cmd(0x38);	//(2)写指令38H(不检测忙信号)
    	Delay5ms();				//(3)延时5ms
    	//(4)以后每次写指令,读/写数据操作均需要检测忙信号
    	check_busy();
    	LCD_write_cmd(0x38);	//(5)写指令38H:显示模式设置
    	check_busy();
    	LCD_write_cmd(0x08);	//(6)写指令08H:显示关闭
    	check_busy();
    	LCD_write_cmd(0x01);	//(7)写指令01H:显示清屏
    	check_busy();
    	LCD_write_cmd(0x06);	//(8)写指令06H:显示光标移动设置
    	check_busy();
    	LCD_write_cmd(0x0C);	//(9)写指令0CH:显示开机光标设置
    }
    
    void Delay15ms()		//@11.0592MHz
    {
    	unsigned char i, j;
    
    	i = 27;
    	j = 226;
    	do
    	{
    		while (--j);
    	} while (--i);
    }
    
    void Delay5ms()		//@11.0592MHz
    {
    	unsigned char i, j;
    
    	i = 9;
    	j = 244;
    	do
    	{
    		while (--j);
    	} while (--i);
    }
    
    void check_busy()
    {
    	char temp = 0x80;				//一开始就busy
    	dataBuffer = 0x80;
    	while( !((temp & 0x80)==0) ){	//一直检测忙信号,直到检测到不忙(temp的bit7为高电平代表忙)
    		RS = 0;
    		RW = 1;
    		EN = 0;
    		_nop_();
    		EN = 1;
    		_nop_();
    		temp = dataBuffer;
    		_nop_();
    		EN = 0;
    		_nop_();
    	}	
    }
    
    void LCD1602_showLine(char row, char column, char *str)
    {
    	char *p = str;
    	switch(row){
    		case 1:
    			check_busy();
    			LCD_write_cmd(0x80+column);			//选择要显示的地址
    			while(*p != '\0'){		
    				check_busy();			
    				LCD_write_data(*p);		//发送要显示的字符(不用发指令让光标移动,光标会自动后移)
    				p++;
    			}
    			break;
    		case 2:
    			check_busy();
    			LCD_write_cmd(0x80+0x40+column);	//选择要显示的地址
    			while(*p != '\0'){
    				check_busy();
    				LCD_write_data(*p);		//发送要显示的字符(不用发指令让光标移动,光标会自动后移)
    				p++;
    			}
    			break;
    		default :
    			break;
    	}
    }

到了这里,关于LCD1602液晶显示模块的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【附报告】51单片机计算器(LCD1602液晶显示)

      由于本文较早,这里推荐一下近期刚优化的:【优化】51单片机计算器(LCD1602液晶显示)_Gxtoeilee的博客-CSDN博客   1 设计目标 设计可选模式的计算器  2 主要功能 功能一:可选两种计算模式,模式一为四则运算,模式二为扩展内容; 功能二:除法的计算结果保留到小数点

    2024年02月11日
    浏览(57)
  • 【C语言】51单片机计算器(LCD1602液晶显示)

      由于本文较早,这里推荐一下近期刚优化的:【优化】51单片机计算器(LCD1602液晶显示)_Gxtoeilee的博客-CSDN博客   1 设计目标 设计可选模式的计算器  2 主要功能 功能一:可选两种计算模式,模式一为四则运算,模式二为扩展内容; 功能二:除法的计算结果保留到小数点

    2024年02月07日
    浏览(57)
  • LCD1602液晶显示模块

    1、概述: LCD1602(Liquid Crystal Display)是一种工业字符型液晶,能够同时显示 16×02,32个 字符(16列两行)。是我们接触引脚最多的模块。 LCD1602我们的非标准协议(标准协议有IIC、IIS、SPI)中比较容易懂的玩法。 2、引脚说明:翻阅LCD1602说明书 共有16根引脚,如下表: 编号 符号

    2024年02月16日
    浏览(50)
  • 51单片机LCD1602液晶屏显示字符,字符串,(有)无符号整数,十六进制数,二进制数等

    LCD1602液晶显示器是广泛使用的一种字符型液晶显示模块。液晶显示模块具有体积小、功耗低、显示内容丰富、超薄轻巧等优点,在嵌入式应用系统中得到越来越广泛的应用,这讲中向大家介绍的LCD1602 液晶显示模块(其内部控制器为HD44780 芯片),它可以显示两行,每行16 个字

    2024年02月04日
    浏览(67)
  • 基于51单片机 + MQ-3酒精传感器 + ADC0832模数转换器 + LCD1602液晶显示器的酒精检测系统

    废话不多说,直接上东西。本文是基于51单片机的酒精检测系统设计,用的元器件有:51单片机、MQ-3酒精传感器、ADC0832模数转换器、 LCD1602液晶显示器、喇叭等元器件。 1、MQ-3 酒精检测传感器,用于检测酒精浓度。当然采集到的数据是模拟的还需要通过ADC0832模数转换器将其转

    2024年02月12日
    浏览(59)
  • STM32显示外设集--液晶显示模块(LCD1602)

    一、介绍 产品图 二、 资源获取 欢迎关注微信公众号--星之援工作室 发送(LCD1602) 三、线路连接图 四、代码编写 LCD1602.h LCD1602.c main.h 五、参考 LCD1602是一种字母数字液晶显示模块,可以显示16个字符和2行文本,因此被命名为LCD1602。它通常用于各种电子项目,特别是

    2024年02月11日
    浏览(49)
  • LCD1602液晶显示屏

    主函数 LCD1602.c LCD1602.h 接线图:   1、1602屏幕=16x2=32个字符,总共有32个字符  2、每个字符由35个像素组成 每个像素由一小块液晶控制 --------------------------------------------------------------------------------------------------------------------------------- 液晶的控制原理: 不施加电压——液晶完

    2024年02月07日
    浏览(50)
  • 字符型液晶显示器LCD 1602的显示控制(Keil+Proteus)

    趁机把LCD 1602的实验完成了,那个电路图有几个地方没弄懂,但是去掉也没有报错,就没管了。 LCD1602_百度百科 (baidu.com) https://baike.baidu.com/item/LCD1602/6014393?fr=ge_ala LCD1602液晶显示屏通过电压来改变填充在两块平行板之间的液晶材料内部分子的排列状况,以达到遮光和透光的目

    2024年02月06日
    浏览(50)
  • 基于51单片机的烟雾检测+温度检测+蜂鸣器报警+光耦+风扇+LCD4602液晶显示(含原理图/PCB/代码)

    讲在前面: 51单片机是大多数电子爱好者的入门级单片机,这款设计是一个比较综合的单片机设计。本文介绍了一个典型的51单片机设计,希望对各位有帮助。 本人也在其他平台开源了一些项目和分享: 点击进入B站传送门 1)产品功能: 使用51单片机作为控制器,与ADC0832(

    2024年01月22日
    浏览(50)
  • 一文读懂使用STM32驱动 LCD1602 液晶显示屏(基于Mbed Studio平台)

    LCD (Liquid Crystal Display) 液晶显示屏是一种广泛使用的一种字符型液晶显示模块。其中型号1602表示每行显示16个字符、一共2行。LCD1602相比于OLED最大的好处就是不用使用SPI或I2C等任何通信协议,而是由mbed直接将命令传给LCD从而实现控制。 LCD1602主要参数如下: 显示字符:16×2个

    2024年02月05日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包