工业字符型液晶,能够同时显示16×02即32个字符。(16列2行)
注:为了表示的方便 ,后文皆以1表示高电平,0表示低电平。
引脚说明
1602字符型LCD通常有14条引脚线或16条引脚线的LCD,多出来的2条线是背光电源线
VCC(15脚)和地线GND(16脚),其控制原理与14脚的LCD完全一样,其中:
引脚
|
符号
|
功能说明
|
1
|
VSS
|
一般接地
|
2
|
VDD
|
接电源(+5V)
|
3
|
V0
|
液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高(对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度)。
|
4
|
RS
|
RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。
|
5
|
R/W
|
R/W为读写信号线,高电平(1)时进行读操作,低电平(0)时进行写操作。
|
6
|
E
|
E(或EN)端为使能(enable)端,
写操作时,下降沿使能。
读操作时,E高电平有效
|
7
|
DB0
|
低4位三态、 双向数据总线 0位(最低位)
|
8
|
DB1
|
低4位三态、 双向数据总线 1位
|
9
|
DB2
|
低4位三态、 双向数据总线 2位
|
10
|
DB3
|
低4位三态、 双向数据总线 3位
|
11
|
DB4
|
高4位三态、 双向数据总线 4位
|
12
|
DB5
|
高4位三态、 双向数据总线 5位
|
13
|
DB6
|
高4位三态、 双向数据总线 6位
|
14
|
DB7
|
高4位三态、 双向数据总线 7位(最高位)(也是busy flag)
|
15
|
BLA
|
背光电源正极
|
16
|
BLK
|
背光 电源负极
|
寄存器选择控制表
RS
|
R/W
|
操作说明
|
0
|
0
|
写入指令寄存器(清除屏等)
|
0
|
1
|
读busy flag(DB7),以及读取位址计数器(DB0~DB6)值
|
1
|
0
|
写入数据寄存器(显示各字型等)
|
1
|
1
|
从数据寄存器读取数据
|
注:关于E=H脉冲——开始时初始化E为0,然后置E为1,再清0.
busy flag(DB7):在此位为1时,LCD忙,将无法再处理其他的指令要求。
1602液晶模块内部的字符发生
存储器(
CGROM)已经存储了160个不同的
点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。
因为1602识别的是ASCII码,试验可以用ASCII码直接赋值,在
单片机编程中还可以用字符型
常量或
变量赋值,如\’A’。
以下是1602的16进制ASCII码表:
读的时候,先读上面那列,再读左边那行,如:感叹号!的ASCII为0x21,字母B的ASCII为0x42(前面加0x表示十六进制)。
1602字符液晶显示可分为上下两部分各16位进行显示,处于不同行时的字符显示地址如下
显示字符
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
…
|
第一行地址
|
00H
|
01H
|
02H
|
03H
|
04H
|
05H
|
06H
|
07H
|
08H
|
09H
|
0AH
|
0BH
|
…
|
第二行地址
|
40H
|
41H
|
42H
|
43H
|
44H
|
45H
|
46H
|
47H
|
48H
|
49H
|
4AH
|
4BH
|
…
|
1602通过D0~D7的8位数据端传输数据和指令。
显示模式设置: (初始化)
0011 1000
[0x38] 设置16×2显示,5×7
点阵,8位数据接口;
0000 1DCB D显示(1有效)、C光标显示(1有效)、B光标闪烁(1有效)
0000 01NS N=1(读或写一个字符后地址
指针加1 &光标加1),
N=0(读或写一个字符后地址
指针减1 &光标减1),
S=1 且 N=1 (当写一个字符后,整屏显示左移)
s=0 当写一个字符后,整屏显示不移动
数据首地址为80H,所以数据地址为80H+
地址码(0-27H,40-67H)
其他设置:
01H(显示清屏,数据
指针=0,所有显示=0);02H(显示回车,数据指针=0)。
通常推荐的初始化过程:
延时15ms
写指令38H
延时5ms
写指令38H
延时5ms
写指令38H
延时5ms
(以上都不检测忙信号)
(以下都要检测忙信号)
写指令38H
写指令08H 关闭显示
写指令01H 显示清屏
写指令0cH 显示开及光标设置
完毕
Proteus仿真
使用Proteus仿真1602–即LM016L–依照数据手册说明可能遇到困难,可以尝试采用以下方案解决:
1、数据手册中可能介绍1602内部D0~D7已有上拉,可以使用P0口直接驱动。在Proteus里LM016L内部可能没有,应该人为
加上拉电阻。建议不要使用排阻,使用普通电阻一个一个拉应该可以解决问题;
2、可能碰到不能检测忙信号的问题,尝试使用延时把忙信号拖过去。
读写操作时序如图1和2所示:
写操作时序:
/#include<intrins.h> //包含NOP空指令的头文件
#define uchar unsigned char
#define uint unsigned int
#define LCD1602_H 1 //宏定义手册中出现的H的定义
#define LCD1602_L 0 //宏定义手册中出现的L的定义
#define LCD1602_DAT 1 //数据
#define LCD1602_COM 0 //命令
#define LCD_15MS 300 //宏定义15MS延时需要的数值
#defineLCD_5MS 100 //宏定义 5MS延时需要的数值
/*显示模式指令*/
#define LCD_Display_mode 0X38 //设置16×2显示 5×7点阵 8位数据接口
/*显示开/关及光标设置*/
#define LCD_shows0 0X0C //开显示 不显示光标 光标不闪烁
#define LCD_shows2 0X0E //开显示 显示光标 光标不闪烁
#define LCD_shows1 0X0F //开显示 显示光标 光标 闪烁
#define LCD_shows3 0X08 //关显示 不显示光标 光标不闪烁
/*指针设置*/
#define LCD_cursor1 0X04 //写一个字符 地址指针减1
#define LCD_cursor2 0X05 //写一个字符 地址指针减1 并屏幕右移
#define LCD_cursor3 0X06 //写一个字符 地址指针加1
#define LCD_cursor4 0X07 //写一个字符 地址指针加1 并屏幕左移
/*清屏指令*/
#define LCD_clear 0x01 //清屏指令 数据指针清零 所有显示清零
/*忙状态字*/
#define LCD_WAY 0x80 //状态字
/*宏定义显示起始地址*/
#define LCD_ADDH 0X80 //第一行地址0x80-0xA7
#define LCD_ADDL 0XC0 //第二行地址0xC0-0xE7
/*IO口定义*/
#define LCD1602_DATA P0 //宏定义8位数据线IO为P0口 D0~D7=P00~P07 8位数据线 D0=P00;
sbit LCD1602_RS=P2^5; //数据/命令选择端(H/L)
sbit LCD1602_RW=P2^6; //读/写选择端(H/L)
sbit LCD1602_E =P2^7; //使能信号
/*函数声明*/
void LCD1602_init(); //液晶初始化函数
void LCD1602_writecd(bit lcd_rs, uchar LCD1602_d);//写命令/数据 函数bit lcd_rs是数据还是命令 uchar LCD1602_d要写入的数据
uchar LCD1602_readway(); //读忙状态函数 由写入和读取函数调用
uchar LCD1602_readata(); //读数据函数
void LCD_DELAY(uchar LCD_delay); //
/*液晶初始化函数*/
void LCD1602_init() //液晶初始化函数
{ LCD_DELAY(LCD_15MS); //延时15MS 初始化
LCD1602_writecd(LCD1602_COM,LCD_Display_mode);//写指令38H 设置16×2显示 5×7点阵 8位数据接口
LCD1602_writecd(LCD1602_COM,LCD_shows0); //开显示 不显示光标 光标不闪烁
LCD1602_writecd(LCD1602_COM,LCD_cursor1); //检查忙状态
LCD1602_writecd(LCD1602_COM,LCD_clear); //写指令01H:显示清屏
}
/*液晶写命令/数据函数*/
void LCD1602_writecd(bit lcd_rs, uchar LCD1602_cd)//写命令/数据 函数
{ uchar LCD1602_NUM; //定义变量用来液晶无忙回答的退出死循环
LCD1602_NUM=255; //忙状态检测次数
while(LCD1602_readway()) //检查忙状态
{LCD1602_NUM–; //检测次数自减
if(LCD1602_NUM==0) //判断检测次数等于0
{break;} //退出循环判断忙
}
LCD1602_RW = LCD1602_L; //读/写选择端(H/L)
LCD1602_RS = lcd_rs; //数据/命令选择端(H/L)
LCD1602_DATA= LCD1602_cd; //IO口赋值
LCD1602_E = LCD1602_H; //拉高使能信号开始传输数据
LCD1602_E = LCD1602_L; //拉低使能信号锁存数据
LCD1602_DATA= 0xff; //IO口数据清除
}
/*忙状态读取函数*/
uchar LCD1602_readway()//读状态函数由写入和读取函数调用
{ uchar LCD1602_way; //状态字变量
LCD1602_DATA=0xff; //IO口数据清除
LCD1602_RS = LCD1602_COM; //数据/命令选择端(H/L) 命令
LCD1602_RW = LCD1602_H; //读/写选择端(H/L)
LCD1602_E = LCD1602_H; //拉高使能信号开始接收状态
LCD1602_way =LCD1602_DATA; //读取状态
LCD1602_E = LCD1602_L; //拉低使能信号锁存数据
LCD1602_way =LCD1602_way&LCD_WAY;//取忙状态字
return(LCD1602_way); //返回状态字
}
/*液晶读数据函数*/
uchar LCD1602_readata()//读数据函数
{ uchar LCD1602_data; //数据暂存变量
while(LCD1602_readway()); //检查忙状态 ——————–
LCD1602_DATA=0xff; //IO口数据清除
LCD1602_RS = LCD1602_DAT; //数据/命令选择端(H/L) 数据
LCD1602_RW = LCD1602_H; //读/写选择端(H/L)
LCD1602_E = LCD1602_H; //拉高使能信号开始接收状态
LCD1602_data= LCD1602_DATA; //读取状态
LCD1602_E = LCD1602_L; //拉低使能信号锁存数据
return(LCD1602_data); //返回数据
}
/*延时函数*/
void LCD_DELAY(uchar LCD_delay)//
{ uchar lcd_del;
while(LCD_delay–) //自减
{lcd_del=100;
while(lcd_del–);}
}