LCD1602介绍

LCD1602简介

  1602 液晶也叫1602字符型液晶,它能显示2行字符信息,每行又能显示16个字符。它是一种专门用来显示字母、数字、符号的点阵型液晶模块。它是由若干个5x7或者5x10的点阵字符位组成,每个点阵字符位都可以用显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用,正因为如此,所以它不能很好的显示图片。其实物图如下所示:

  在上图中可以看到有16个管脚孔,从左至右管脚编号顺序是1-16,其功能定义如下所示:

编号 符号 引脚说明 编号 符号 引脚说明
1 VSS 电源地 9 D2 Data I/O
2 VDD 电源正极 10 D3 Data I/O
3 VL 液晶显示偏压信号 11 D4 Data I/O
4 RS 数据/命令选择端(H/L) 12 D5 Data I/O
5 R/W 读/写选择端(H/L) 13 D6 Data I/O
6 E 使能信号 14 D7 Data I/O
7 D0 Data I/O 15 BLA 背光源正极
8 D1 Data I/O 16 BLK 背光源负极

  下面对几个管脚做下说明:

  • 3脚(VL) : 液晶显示偏压信号,用于调整LCD1602的显示对比度,一般会外接电位器用以调整偏压信号,注意此脚电压为0 时可以得到最强的对比度。
  • 4脚(RS) : 数据/命令选择端,当此脚为高电平时,可以对1602 进行数据字节的传输操作,而为低电平时,则是进行命令字节的传输操作。命令字节,即是来对LCD1602 的一些工作方式作设置的字节;数据字节,即使用以在1602上显示的字节。值得一提的是,LCD1602 的数据是8位的。
  • 5脚(R/W) : 读写选择端。当此脚为高电平可对LCD1602进行读数据操作,反之进行写数据操作。
  • 6脚(E) : 使能信号,其实是LCD1602的数据控制时钟信号,利用该信号的上升沿实现对 LCD1602的数据传输。
  • 7~14脚 : 8 位并行数据口,而51单片机一组IO也是8位,使得对LCD1602的数据读写大为方便。

  在LCD1602 内部含有80个字节的DDRAM,它是用来寄存显示字符的。其地址和屏幕的对应关系如下表:

  从上图可知,不是所有的地址都可以直接用来显示字符数据,只有第一行中的00-0F,第二行中的40-4F才能显示,其他地址只能用于存储。要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,例如第二行第一个字符的地址是 40H,那么是否直接写入 40H 就可以将光标定位在第二行第一个字符的位置呢?这样不行,因为 写入显示地址时要求最高位 D7恒定为高电平 1 所以实际写入的数据应该是01000000B(40H)+10000000B(80H)=11000000B(C0H)。在 1602 中我们就用前 16 个就行了。第二行也一样用前 16 个地址。

LCD1602常用指令

  在使用LCD1602时,我们需要掌握一些常用的指令,这些指令对于LCD1602初始化是必须的。

清屏命令

  • 清除液晶显示器,即将DDRAM的内容全部填入“空白”的ASCII码(20H)
  • 光标归位,即将光标撤回液晶显示屏的左上方
  • 将地址计数器(AC)的值设为0

模式设置指令

  • 设定每次写入1位数据后光标的移位方向,并且设定每次写入的一个字符是否移动
    • I/D :
      • 0 = 写入新数据后光标左移;
      • 1 = 写入新数据后光标右移
    • S :
      • 0 = 写入新数据后显示屏不宜动;
      • 1= 写入新数据后显示屏整体右移一个字符

显示开关控制指令

  • 控制显示器开/关、光标显示/关闭以及光标是否闪烁
    • D :
      • 0 = 显示功能开
      • 1 = 显示功能开
    • C :
      • 0 = 无光标
      • 1 = 有光标
    • B
      • 0 = 光标闪烁
      • 1 = 光标不闪烁

功能设定指令

  • 设定数据总线位数、显示的行数及字型
    • DL :
      • 0 = 数据总线位4位
      • 1 = 数据总线位8位
    • N :
      • 0 = 显示1行
      • 1 = 显示2行
    • F :
      • 0 = 5 × 7 点阵/每字符
      • 1 = 5 × 10 点阵/每字符

LCD1602使用

  要使用LCD1602,首先需要对其初始化,即通过写入一些特定的指令实现。然后选择要在LCD1602的哪个位置显示并将所要显示的数据发送到LCD的DDRAM。使用LCD1602通常都是用于写数据进去,很少使用读功能。LCD1602操作步骤如下所示:

  1. 初始化
  2. 写命令(RS=L),设置显示坐标
  3. 写数据(RS=H)

  在此,不需要读出它的数据的状态或者数据本身。所以只需要看两个写时序:

  1. 当要写指令字,设置LCD1602的工作方式时:需要把RS置为低电平,RW置为低电平,然后将数据送到数据口D0~D7,最后E引脚一个高脉冲将数据写入。
  2. 当要写入数据字,在1602上实现显示时:需要把RS置为高电平,RW置为低电平,然后将数据送到数据口D0~D7,最后E引脚一个高脉冲将数据写入。

  写指令和写数据,差别仅仅在于RS的电平不一样而已。以下是LCD1602的时序图:

  从上图可以看到,以上给的时间参数全部是ns级别的,而51单片机的机器周期是1us,指令周期是2-4个机器周期,所以即便在程序里不加延时程序,也可以很好的配合LCD1602的时序要求了。

  当要写命令字节的时候,时间由左往右,RS 变为低电平,R/W 变为低电平,注意看是RS的状态先变化完成。然后这时,DB0~DB7 上数据进入有效阶段,接着E引脚有一个整脉冲的跳变,接着要维持时间最小值为tpw=400ns的E脉冲宽度。然后E引脚负跳变,RS电平变化,R/W 电平变化。这样便是一个完整的LCD1602写命令的时序。

硬件设计

  本实验使用到硬件资源如下:

  1. LCD1602液晶显示屏

  从上图中可知,LCD1602的8位数据口DB0-DB7与单片机的P0.0-P0.7管脚连接,LCD1602的RS、RW、E脚与单片机的P2.6、P2.5、P2.7管脚连接。RJ1是一个电位器,用来调节LCD1602对比度即显示亮度。

  注意:这里原理图是使用的8位LCD1602接口设计,是可以兼容4位LCD1602的。对于非标准接口的LCD1602,我们也会通过转接板将其转接为对应开发板接口的。对于4位LCD1602在传输数据的时候需要将 8 位的数据截成两段,先发送高四位,在发送低四位。其它引脚操作方法不变。

软件设计

  本实验所要实现的功能是:在LCD1602液晶上显示字符信息。程序框架如下:

  1. LCD1602显示函数
  2. 主函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**************************************************************************************
实验名称:LCD1602液晶显示实验
接线说明:
实验现象:下载程序后,LCD1602上显示字符信息
注意事项:
***************************************************************************************/
#include "public.h"
#include "lcd1602.h"


/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
lcd1602_init();//LCD1602初始化
lcd1602_show_string(0,0,"Hello World!");//第一行显示
lcd1602_show_string(0,1,"0123456789");//第二行显示
while(1)
{

}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include "lcd1602.h"


/*******************************************************************************
* 函 数 名 : lcd1602_write_cmd
* 函数功能 : LCD1602写命令
* 输 入 : cmd:指令
* 输 出 : 无
*******************************************************************************/
#if (LCD1602_4OR8_DATA_INTERFACE==0)//8位LCD
void lcd1602_write_cmd(u8 cmd)
{
LCD1602_RS=0;//选择命令
LCD1602_RW=0;//选择写
LCD1602_E=0;
LCD1602_DATAPORT=cmd;//准备命令
delay_ms(1);
LCD1602_E=1;//使能脚E先上升沿写入
delay_ms(1);
LCD1602_E=0;//使能脚E后负跳变完成写入
}
#else //4位LCD
void lcd1602_write_cmd(u8 cmd)
{
LCD1602_RS=0;//选择命令
LCD1602_RW=0;//选择写
LCD1602_E=0;
LCD1602_DATAPORT=cmd;//准备命令
delay_ms(1);
LCD1602_E=1;//使能脚E先上升沿写入
delay_ms(1);
LCD1602_E=0;//使能脚E后负跳变完成写入

LCD1602_DATAPORT=cmd<<4;//准备命令
delay_ms(1);
LCD1602_E=1;//使能脚E先上升沿写入
delay_ms(1);
LCD1602_E=0;//使能脚E后负跳变完成写入
}
#endif

/*******************************************************************************
* 函 数 名 : lcd1602_write_data
* 函数功能 : LCD1602写数据
* 输 入 : dat:数据
* 输 出 : 无
*******************************************************************************/
#if (LCD1602_4OR8_DATA_INTERFACE==0)//8位LCD
void lcd1602_write_data(u8 dat)
{
LCD1602_RS=1;//选择数据
LCD1602_RW=0;//选择写
LCD1602_E=0;
LCD1602_DATAPORT=dat;//准备数据
delay_ms(1);
LCD1602_E=1;//使能脚E先上升沿写入
delay_ms(1);
LCD1602_E=0;//使能脚E后负跳变完成写入
}
#else
void lcd1602_write_data(u8 dat)
{
LCD1602_RS=1;//选择数据
LCD1602_RW=0;//选择写
LCD1602_E=0;
LCD1602_DATAPORT=dat;//准备数据
delay_ms(1);
LCD1602_E=1;//使能脚E先上升沿写入
delay_ms(1);
LCD1602_E=0;//使能脚E后负跳变完成写入

LCD1602_DATAPORT=dat<<4;//准备数据
delay_ms(1);
LCD1602_E=1;//使能脚E先上升沿写入
delay_ms(1);
LCD1602_E=0;//使能脚E后负跳变完成写入
}
#endif

/*******************************************************************************
* 函 数 名 : lcd1602_init
* 函数功能 : LCD1602初始化
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
#if (LCD1602_4OR8_DATA_INTERFACE==0)//8位LCD
void lcd1602_init(void)
{
lcd1602_write_cmd(0x38);//数据总线8位,显示2行,5*7点阵/字符
lcd1602_write_cmd(0x0c);//显示功能开,无光标,光标闪烁
lcd1602_write_cmd(0x06);//写入新数据后光标右移,显示屏不移动
lcd1602_write_cmd(0x01);//清屏
}
#else
void lcd1602_init(void)
{
lcd1602_write_cmd(0x28);//数据总线4位,显示2行,5*7点阵/字符
lcd1602_write_cmd(0x0c);//显示功能开,无光标,光标闪烁
lcd1602_write_cmd(0x06);//写入新数据后光标右移,显示屏不移动
lcd1602_write_cmd(0x01);//清屏
}
#endif

/*******************************************************************************
* 函 数 名 : lcd1602_clear
* 函数功能 : LCD1602清屏
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void lcd1602_clear(void)
{
lcd1602_write_cmd(0x01);
}

/*******************************************************************************
* 函 数 名 : lcd1602_show_string
* 函数功能 : LCD1602显示字符
* 输 入 : x,y:显示坐标,x=0~15,y=0~1;
str:显示字符串
* 输 出 : 无
*******************************************************************************/
void lcd1602_show_string(u8 x,u8 y,u8 *str)
{
u8 i=0;

if(y>1||x>15)return;//行列参数不对则强制退出

if(y<1) //第1行显示
{
while(*str!='\0')//字符串是以'\0'结尾,只要前面有内容就显示
{
if(i<16-x)//如果字符长度超过第一行显示范围,则在第二行继续显示
{
lcd1602_write_cmd(0x80+i+x);//第一行显示地址设置
}
else
{
lcd1602_write_cmd(0x40+0x80+i+x-16);//第二行显示地址设置
}
lcd1602_write_data(*str);//显示内容
str++;//指针递增
i++;
}
}
else //第2行显示
{
while(*str!='\0')
{
if(i<16-x) //如果字符长度超过第二行显示范围,则在第一行继续显示
{
lcd1602_write_cmd(0x80+0x40+i+x);
}
else
{
lcd1602_write_cmd(0x80+i+x-16);
}
lcd1602_write_data(*str);
str++;
i++;
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "public.h"

/*******************************************************************************
* 函 数 名 : delay_10us
* 函数功能 : 延时函数,ten_us=1时,大约延时10us
* 输 入 : ten_us
* 输 出 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
while(ten_us--);
}

/*******************************************************************************
* 函 数 名 : delay_ms
* 函数功能 : ms延时函数,ms=1时,大约延时1ms
* 输 入 : ms:ms延时时间
* 输 出 : 无
*******************************************************************************/
void delay_ms(u16 ms)
{
u16 i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}

  相关头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ifndef _lcd1602_H
#define _lcd1602_H

#include "public.h"

//LCD1602数据口4位和8位定义,若为1,则为LCD1602四位数据口驱动,反之为8位
#define LCD1602_4OR8_DATA_INTERFACE 0 //默认使用8位数据口LCD1602

//管脚定义
sbit LCD1602_RS=P2^6;//数据命令选择
sbit LCD1602_RW=P2^5;//读写选择
sbit LCD1602_E=P2^7; //使能信号
#define LCD1602_DATAPORT P0 //宏定义LCD1602数据端口


//函数声明
void lcd1602_init(void);
void lcd1602_clear(void);
void lcd1602_show_string(u8 x,u8 y,u8 *str);

#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef _public_H
#define _public_H

#include "reg52.h"

typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;


void delay_10us(u16 ten_us);
void delay_ms(u16 ms);

#endif