1 LCD1602简介
LCD分为段式、点阵式两种,其中点阵式又分为字符模式与图形模式两种。段式LCD最常见的应用场景就是计算器,其显示效果类似于LED数码管。点阵式的图形模式LCD最常见的应用场景就是电视、计算机显示屏、手机屏幕等。而我们要介绍的LCD1602就是字符模式的LCD,如下图所示。
可以看到上面由一个个5*8的点阵组成,每个点阵都能够显示一个字符,因此称为字符模式LCD。
LCD1602模块内部包含了一个DDRAM(DataDisplay)、CGRAM(Character generate)、以及CGROM。还包含了一个指令寄存器和一个数据寄存器。"1602"意味着它可以显示两行字符,每行可显示16个字符。
2 LCD1602引脚
引脚图如上图所示。引脚功能描述如下:
第1脚:VSS为电源地
第2脚:VCC接5V电源正极
第3脚:V0(或VEE)为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高。在多数单片机开发板的LCD插口附近会有一个电位器用于调整对比度。
第4脚:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。
第5脚:RW为读写信号线,高电平(1)时进行读操作,低电平(0)时进行写操作。
第6脚:E(或EN)端为使能(enable)端,高电平(1)时读取信息,负跳变时执行指令。
第7~14脚:D0~D7为8位双向数据端。
第15~16脚:空脚或背灯电源。15脚背光正极,16脚背光负极。(这两个引脚在上图中没有标注)
3 LCD1602内部存储器的作用
上面提到,LCD1602模块内部包含了一个DDRAM(DataDisplay)、CGRAM(Character generate)、以及CGROM。下面介绍它们的作用:
1、DDRAM:最终想要在LCD屏上显示的内容,都要写入到DDRAM中,显示屏上显示的内容实际上就是DDRAM中的数据。DDRAM中可寻址的地址有16*2=32个,每个地址对应着显示屏上的一个字符位。
例如00H地址对应显示屏第一行的第一个字符的地址,40H对应显示屏第二行第一个字符的地址,以此类推。但是我们要访问第一行第一个字符的地址,可以直接通过向LCD发送00H来访问吗?答案是否定的。
访问上述的DDRAM地址,是通过向LCD模块发送"置数据存储器地址"指令(见下图中的指令8)来实现,根据下面介绍的指令8,指令的D7位必须是1(80H)。因此,我们如果要访问显示屏上第一行第一个字符对应的DDRAM中的地址,要向LCD模块发送的指令为80H+00H=80H。以此类推,我们在访问显示屏第一行的字符的地址时,要向LCD发送的指令为80H到8FH,而第二行字符对应的指令为C0H到CFH。
2、CGROM:这个ROM中固化了一些我们常用的ASCII字符以及部分日文字符的点阵数据,我们要在LED屏上显示字符,应该向DDRAM中对应位置写入数据,上面提到的指令8告诉LCD模块我要把指令写到DDRAM的哪个位置,在此之后我们就可以向刚才指定的地址中写入点阵数据了。如果要显示的字符是ASCII字符,那么我们可以直接利用CGROM中固化的点阵数据,只要告诉LCD,我们要显示的字符的点阵数据在CGROM中的地址是多少,这样LCD模块自动从CGROM中取出点阵数据放入指定的DDRAM地址。字符与CGROM地址的对应关系表如下
比如字符“A”的地址为01000001即41H=65,这与A字符的ASCII码是一致的,不难发现,表中的ASCII字符的地址与其ASCII码是一致的。这样的编排顺序为我们在LCD上显示字符串提供了便利。比如要在第一行第一列显示字符A,则可以通过下面两条语句实现:
lcd_wcmd(0x80); //指定第一行第一列字符对应的DDRAM地址
lcd_wdata('A'); //C语言自动将'A'转换成对应的ASCII码
3、CGRAM:字符发生器RAM,如果用户要自定义图形的话,必须将点阵数据先写入CGRAM,用于产生图形,随后再将其写入DDRAM,用于显示。CGRAM中只有8个地址可供用户写入数据(分别是00H-07H),写入数据的过程与向DDRAM写入数据类似,首先指定要访问的CGRAM地址,通过下面介绍的指令7来实现。根据指令7,比如要向第一个地址写入数据,则应该先发送指令0100 0000+0000 0000=40H+00H=40H来指定CGRAM地址。以此类推CGRAM中8个地址(00H-07H)对应的指令为40H到47H。自定义字符的显示可以参考这篇博客LCD显示屏入门级应用
4 指令介绍
各指令说明如下:
第2条指令:光标移至左上角,显示内容不变。
第3条指令:我们在指定了一个DDRAM地址,并写入数据后,一般都希望自动跳转到下一个字符的DDRAM的地址,以便写入下一个字符的数据。而I/D位提供了这样一种机制,当I/D=1时,向DDRAM的某一地址写入数据后,DDRAM地址自增1,指向下一个字符的DDRAM地址。当I/D=0时,DDRAM地址自减。而S位指定显示内容整体是否移动,S=1时移动,S=0时不移动。
第4条指令:D=Dispaly,为1时开显示屏,为0时关显示屏。C=Cursor,为1时开光标,为0时不开。B=Blink。为1时光标所在的字符闪烁,为0时不闪烁。
上面显示的下划线就是光标,如果开启了闪烁,则光标所在位置会亮-灭交替。
第5条指令:SC=0,RL=0时,光标左移;SC=0,RL=1时,光标右移;SC=1,RL=0时,字符和光标都左移,SC=1,RL=1时字符和光标都右移。
第6条指令:DL=1代表数据长度为8位,DL=0代表数据长度为4位。N=1代表显示屏的两行字符位都可以用来显示,N=0代表只有第一行字符位可以显示字符。F=1代表一个字符大小为510点阵,F=0代表一个字符大小为57点阵。
这是单行,510点阵(实际数起来应该是511点阵,但很多资料都写的是5*10)效果,(即N=0,F=1)。一般常用设置为N=1,F=0。
第7条指令指定CGRAM地址
第8条指令指定DDRAM地址,DDRAM地址在完成一次数据写入后会自增或自减(由第三条指令I/D位决定),因此不用每写入一个数据,就重新指定下一个要写入数据的DDRAM地址。
5 Proteus仿真
LCD1602只需在元件库搜索LM016即可找到
6 测试程序
LCD.C文件
#include "reg52.h"
#include "delay.h"
#include "lcd.h"
sbit rs=P3^4; //1602的数据/指令选择控制线
sbit rw=P3^6; //1602的读写控制线
sbit en=P3^7; //1602的使能控制线
#define dataPort P2 //P2口接1602的D0~D7
unsigned char code table[]="123456"; //要显示的内容放入数组table
void lcd_wcom(unsigned char com) //1602写命令函数
{
rs=0; //选择指令寄存器
rw=0; //选择写
dataPort=com;//把命令字送入P2
delay_ms(5);//延时一小会儿,让1602准备接收数据
en=1; //使能线电平变化,命令送入1602的8位数据口
en=0;
}
void lcd_wdat(unsigned char dat) //1602写数据函数
{
rs=1;//选择数据寄存器
rw=0;//选择写
dataPort=dat;//把要显示的数据送入P2
delay_ms(5);//延时一小会儿,让1602准备接收数据
en=1;//使能线电平变化,数据送入1602的8位数据口
en=0;
}
void lcd_init() //1602初始化函数
{
lcd_wcom(0x34);//8位数据,双列,5*7字形
//lcd_wcom(0x0c); //开显示屏,关光标,当前字符不闪烁
lcd_wcom(0x0f);//开启显示屏,开光标,当前字符闪烁
lcd_wcom(0x06);//显示地址递增,即写一个数据后,显示位置右移一位
lcd_wcom(0x01);//清屏
}
void lcd_clr() //液晶屏清屏
{
lcd_wcom(0x01);//清屏
}
//开显示器,开光标与字符闪烁
//C=Cursor B=Blink
void lcd_onCB()
{
lcd_wcom(0x0f);
lcd_wcom(0xc0);//清屏后将从0x80开始写,由于密码写在第二行,故进行重定位
}
void lcd_on() //开显示器,关光标与闪烁
{
lcd_wcom(0x0c);
lcd_wcom(0xc0); //清屏后将从0x80开始写,由于密码写在第二行,故进行重定位
}
void lcd_off() //关显示器,但DDRAM中内容不丢失,重开后将恢复内容
{
lcd_wcom(0x08);
}
LCD.h文件
#include "reg52.h"
#ifndef __LCD__
#define __LCD__
void lcd_wcom(unsigned char com);
void lcd_wdat(unsigned char dat);
void lcd_init();
void lcd_clr();
void lcd_onCB() ;
void lcd_on();
void lcd_off();
extern unsigned char code table[];
#endif
主函数文件:
#include "reg52.h"
#include "lcd.h"
#include "delay.h"
void main()
{
unsigned char m=0;
lcd_init(); //液晶初始化
lcd_wcom(0x80); //显示地址设为C0H,下排第一位
for(m=0;m<6;m++) //将table[]中的数据依次写入1602显示
{
lcd_wdat(table[m]);
delay_ms(600);
lcd_wcom(0x80+m); //回退
lcd_wdat(0x2A);
delay_ms(300);
}
lcd_wcom(0x0c); //关光标、关字符闪烁
while(1);
}
上面的主函数实现的效果是:按输入密码的效果来显示数字123456,(显示一个数字后,将这个数字变为*号)。
如果使用实物,根据开发板的原理图将上面的dataPort和rs、rw、en改成对应的引脚即可。
实物显示效果