Arduino下LCD1602综合探究(上)——1602的两种驱动方式,如何使LCD的控制编程变得更简单

时间:2024-02-15 21:37:11

本文为大大维原创,最早于博客园发表,转载请注明出处!!!

 

一、前言:

  LCD ( Liquid Crystal Display 的简称)液晶显示器,已经逐渐替代CRT成为主流的显示设备之一,因此也成为了单片机发烧友绕不过的话题之一;而LCD1602更是很多单片机发烧友最早接触的字符型液晶显示器。笔者经过一段时间的深入学习,对其驱动有了些许心得,特地记录于此,以备以后查阅。

  LCD1602,也叫1602液晶,是一种专门用来显示字母、数字、符号等的点阵型液晶模块,工业字符型液晶的一种,能够同时显示16x02即32个字符。主控芯片是HD44780或者其它兼容芯片,而市面上字符液晶大多数是基于HD44780液晶芯片的,控制原理是完全相同的。因此尽管LCD1602可显示的内容十分有限,但在此花点时间是完全值得的。

二、LCD的一些背景知识:

<1>LCD1602基本参数及引脚功能:

1.LCD1602的分类:

  LCD1602分为带背光和不带背光两种,带背光的比不带背光的厚,是否带背光在应用中并无差别,两者尺寸差别如下图10-54所示:

在本文中,笔者选用的是带背光的一种。

  

2.基本参数:

显示容量:16×2个字符

芯片工作电压:4.5—5.5V

工作电流:2.0mA(5.0V)

模块最佳工作电压:5.0V

字符尺寸:2.95×4.35(W×H)mm

2.引脚功能说明

  1602LCD采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如下:

编号

符号

引脚说明

编号

符号

引脚说明

1

VSS

电源地

9

D2

数据

2

VDD

电源正极

10

D3

数据

3

VL

液晶显示偏压

11

D4

数据

4

RS

数据/命令选择

12

D5

数据

5

R/W

读/写选择

13

D6

数据

6

E

使能信号

14

D7

数据

7

D0

数据

15

BLA

背光源正极

8

D1

数据

16

BLK

背光源负极

 

各引脚说明:

第1脚:VSS为地电源。

第2脚:VDD接5V正电源。

第3脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度。

第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。

第5脚:R/W为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或者显示地址,当RS为低电平R/W为高电平时可以读忙信号,当RS为高电平R/W为低电平时可以写入数据。

第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。

第7~14脚:D0~D7为8位双向数据线。

第15脚:背光源正极。

第16脚:背光源负极

<2>LCD1602的指令说明及时序

1.与HD44780相兼容的芯片时序表如下:

读状态

输入

RS=L,R/W=H,E=H

输出

D0—D7=状态字

写指令

输入

RS=L,R/W=L,D0—D7=指令码,E=高脉冲

输出

读数据

输入

RS=H,R/W=H,E=H

输出

D0—D7=数据

写数据

输入

RS=H,R/W=L,D0—D7=数据,E=高脉冲

输出

 

2.LCD1602的指令说明:

  1602液晶模块内部的控制器共有11条控制指令,如表所示:

序号

指令

RS

R/W

D7

D6

D5

D4

D3

D2

D1

D0

1

清显示

0

0

0

0

0

0

0

0

0

1

2

光标返回

0

0

0

0

0

0

0

0

1

*

3

置输入模式

0

0

0

0

0

0

0

1

I/D

S

4

显示开/关控制

0

0

0

0

0

0

1

D

C

B

5

光标或字符移位

0

0

0

0

0

1

S/C

R/L

*

*

6

置功能

0

0

0

0

1

DL

N

F

*

*

7

置字符发生存贮器地址

0

0

0

1

字符发生存贮器地址

8

置数据存贮器地址

0

0

1

显示数据存贮器地址

9

读忙标志或地址

0

1

BF

计数器地址

10

写数到CGRAM或DDRAM

1

0

要写的数据内容

11

从CGRAM或DDRAM读数

1

1

读出的数据内容

 

者在百度文库中发现一个特别好的介绍1602指令集的文章,给大家分享如下:

点击查看

<3>LCD1602的RAM地址映射及标准字库表

1.LCD1602的RAM地址映射

 

  液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效。要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,下图是1602的内部显示地址:

 

在对液晶模块的初始化中要先设置其显示模式,在液晶模块显示字符时光标是自动右移的,无需人工干预。每次输入指令前都要判断液晶模块是否处于忙的状态。

2.LCD1602的标准字库表

  1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,如下图所示,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等。

 

在使用标准字库中的字符图形时,无需自己制作字模即可直接使用,若要显示汉字等标准字库中没有的元素,则需要自己在DDRAM中制作字模。

<4>LCD1602四线驱动的约定流程

1、  写入指令:

1) EN = 0 (LCD使能禁止)

2) 短延时

3) RS = 0  ,RW = 0  (准备写入指令)

4) DATA = 指令的高4位(ATA代表D7、D6、D5、D4,下同)

5) 短延时

6) EN = 1 (LCD使能允许,指令写入)

7) 短延时

8) EN = 0 (LCD使能禁止)

9) DATA = 指令的低4位 

10) 短延时

11) EN = 1 (LCD使能允许,指令写入)

12) 短延时

13) EN = 0 (LCD使能禁止)

14) 短延时

2、  写入数据:

1) EN = 0 (LCD使能禁止)

2) 短延时

3) RS = 1 ,RW = 0 (准备写入数据)

4) DATA = 数据的高4位

5) 短延时

6) EN = 1 (LCD使能允许,数据写入)

7) 短延时

8) EN = 0 (LCD使能禁止)

9) DATA = 数据的低4位

10) 短延时

11) EN = 1 (LCD使能允许,数据写入)

12) 短延时

13) EN = 0 (LCD使能禁止)

14) 短延时

三、关于LCD控制库LiquidCrystal:

  LiquidCrystal是Arduino的官方库之一,他可以控制基于日立公司HD44780(或兼容)芯片集成的字符型LCD。该库可以通过四线或者八线模式控制LCD。

无疑,LiquidCrystal库可以使LCD的控制编程变得十分简单!!!

笔者在学习中,发现了一个比较完整的LiquidCrystal库的中文资料,链接如下:

点击查看

下面,就一些常用的LiquidCrystal库函数做一个简单介绍:

1.LiquidCrystal()构造函数

2.begin()指定显示方式

3.clear()清屏,光标置于左上角

4.home()接下来的字符从左上角显示

5.setCursor(col,row)设置光标位置

6.print()LCD显示字符

四、Arduino下的LCD1602的8线驱动模式:

<1>优缺点

 八线模式的优点是每位数据均从单独的数据线传输,因此数据传输速度快。但缺点也是显然的,需要占掉大量的端口。

<2>接线方式

VL为液晶显示器对比度调整端,有条件的话,最好使用一个10K的电位器来调整对比度。限于条件,笔者通过反复调试,最后选择了4k电阻,效果也还可以。

<3>试验代码

1.不使用LiquidCrystal库

  1 /*Arduino在8位接法下不使用LiquidCrystal库
  2 * 输出欢迎界面和Hello World!
  3 * 作者:大大维
  4 * 2016/10/23
  5 */
  6 
  7 int RS = 12;                             //数据/命令选择器引脚(RS)    
  8 int RW = 11;                            //读/写选择器引脚(R/W)
  9 int DB[] = {3, 4, 5, 6, 7, 8, 9, 10};    //使用数组来定义总线需要的管脚(D0-D7)
 10 int Enable = 2;                            //使能(E)    
 11 
 12 void LcdCommandWrite(int value) {
 13     // 定义所有引脚
 14     int i = 0;
 15     digitalWrite(RS, LOW);
 16     digitalWrite(RW, LOW);
 17     for (i=DB[0]; i <= RS; i++) //总线赋值
 18     {
 19         //这里的&是二进制的“与”运算。取指令码的最低位。
 20        digitalWrite(i,value & 0x01);
 21        value >>= 1;
 22     }
 23     digitalWrite(Enable,LOW);
 24     delayMicroseconds(1);        // 延时1us
 25     digitalWrite(Enable,HIGH);
 26     delayMicroseconds(1);          // 延时1us
 27     digitalWrite(Enable,LOW);
 28     delayMicroseconds(1);          // 延时1us
 29 }
 30 
 31 void LcdDataWrite(int value) {
 32     // 定义所有引脚
 33     int i = 0;
 34     digitalWrite(RS, HIGH);
 35     digitalWrite(RW, LOW);
 36     for (i=DB[0]; i <= DB[7]; i++) {
 37        digitalWrite(i,value & 0x01);
 38        value >>= 1;
 39     }
 40     digitalWrite(Enable,LOW);
 41     delayMicroseconds(1);        // 延时1us
 42     digitalWrite(Enable,HIGH);
 43     delayMicroseconds(1);        // 延时1us
 44     digitalWrite(Enable,LOW);
 45     delayMicroseconds(1);          // 延时1us
 46 }
 47 
 48 void setup (void) {
 49     int i = 0;
 50     for (i=Enable; i <= RS; i++) {
 51        pinMode(i,OUTPUT);   
 52     }
 53     delay(100);
 54     // 短暂的停顿后初始化LCD
 55     // 用于LCD控制需要
 56     LcdCommandWrite(0x38);         // 设置为8-bit接口,2行显示,5x7文字大小                     
 57     delay(20);                      
 58     LcdCommandWrite(0x06);        // 输入方式设定,自动增量,画面没有移位
 59     delay(20);                      
 60     LcdCommandWrite(0x0C);        // 显示设置,开启显示屏,光标关,无闪烁
 61     delay(20);                                  
 62 }
 63 
 64 void loop (void) {
 65   LcdCommandWrite(0x01);           // 屏幕清空,光标位置归零  
 66   delay(10); 
 67   LcdCommandWrite(0x80+5);         // 定义光标位置为第一行第五个位置
 68   delay(10);                     
 69   // 写入欢迎信息 
 70   LcdDataWrite(\'W\');
 71   LcdDataWrite(\'e\');
 72   LcdDataWrite(\'l\');
 73   LcdDataWrite(\'c\');
 74   LcdDataWrite(\'o\');
 75   LcdDataWrite(\'m\');
 76   LcdDataWrite(\'e\');
 77   delay(10);
 78   LcdCommandWrite(0xc0+2);          // 定义光标位置为第二行第二个位置  
 79   delay(10); 
 80   LcdDataWrite(\'I\');
 81   LcdDataWrite(\' \');
 82   LcdDataWrite(\'a\');
 83   LcdDataWrite(\'m\');
 84   LcdDataWrite(\' \');
 85   LcdDataWrite(\'D\');
 86   LcdDataWrite(\'a\');
 87   LcdDataWrite(\'D\');
 88   LcdDataWrite(\'a\');
 89   LcdDataWrite(\'W\');
 90   LcdDataWrite(\'e\');
 91   LcdDataWrite(\'i\');
 92   delay(3000);
 93   LcdCommandWrite(0x01);            // 屏幕清空,光标位置归零
 94   delay(10);
 95   LcdCommandWrite(0x80+2);          //定义光标位置为第一行第二个位置
 96   delay(10);  
 97   LcdDataWrite(\'H\');
 98   LcdDataWrite(\'e\');
 99   LcdDataWrite(\'l\');
100   LcdDataWrite(\'l\');
101   LcdDataWrite(\'o\');
102   LcdDataWrite(\' \');
103   LcdDataWrite(\'W\');
104   LcdDataWrite(\'o\');
105   LcdDataWrite(\'r\');
106   LcdDataWrite(\'l\');
107   LcdDataWrite(\'d\');
108   LcdDataWrite(\'!\');
109   delay(5000);
110 }

 

 看到上面的代码,是否觉得略显复杂?但要是使用了LiquidCrystal库,一切将变得十分简单!!!

2.使用LiquidCrystal库

 1 /*Arduino在8位接法下使用LiquidCrystal库
 2 * 输出欢迎界面和Hello World!
 3 * 作者:大大维
 4 * 2016/10/23
 5 */
 6 #include<LiquidCrystal.h>
 7 LiquidCrystal lcd(12,11,3,4,5,6,7,8,9,10);           //初始化LCD
 8 void setup(){
 9     lcd.begin(16,2);                                 //设置LCD为16列*2行
10 }
11 void loop(){
12     lcd.clear();                                    //清屏操作
13     lcd.setCursor(5,0);                              //设置光标位置为第一行,第六列
14     lcd.print("Welcome");                           //在LCD上输出信息
15     delay(10);                                       //延时程序
16     lcd.setCursor(2,1);
17     lcd.print("I am DaDaWei");
18     delay(3000);
19     lcd.clear();
20     lcd.setCursor(2,0);
21     lcd.print("Hello World!");
22     delay(5000);
23 }

<4>试验展示

演示视频

五、Arduino下的LCD1602的四线驱动模式:

<1>优缺点

 四线模式相对于八线模式的优点是占用的端口更少,减少了四条数据线,也就是说八位的数据需要通过四条线来发送,那么会导致四线模式比八线模式数据速度慢些。

<2>接线方式

<3>试验代码

 1.不使用LiquidCrystal库

  1 /*Arduino在4位接法下不使用LiquidCrystal库
  2 * 输出欢迎界面和Hello World!
  3 * 作者:大大维
  4 * 2016/10/23
  5 */
  6 
  7 int RS = 12;                             //数据/命令选择器引脚(RS)    
  8 int RW = 11;                            //读/写选择器引脚(R/W)
  9 int DB[] = {6, 7, 8, 9};                //使用数组来定义总线需要的管脚(D0-D7)
 10 int Enable = 10;                        //使能(E)    
 11 
 12 void LcdCommandWrite(int value) {
 13     // 定义所有引脚
 14     int i = 0;
 15     digitalWrite(Enable,LOW);
 16     delayMicroseconds(1);        // 延时1us
 17     digitalWrite(RS, LOW);
 18     digitalWrite(RW, LOW);
 19     
 20     /* 6     7     8     9
 21     *  D7     D6      D5    D4 
 22     *  DB[0] DB[1] DB[2] DB[3]
 23     */
 24     int temp=value & 0xf0;//取指令高4位
 25     for (i=DB[0]; i <= 9; i++)
 26     {
 27         if((temp & 0x80)!=0)//取指令最高位
 28             digitalWrite(i,HIGH);
 29         else
 30             digitalWrite(i,LOW );    
 31         temp <<= 1;
 32     }
 33     delayMicroseconds(1);        // 延时1us
 34     digitalWrite(Enable,HIGH);
 35     delayMicroseconds(1);          // 延时1us
 36     digitalWrite(Enable,LOW);
 37     
 38     temp=(value & 0x0f)<<4;
 39     for (i=DB[0]; i <= 9; i++)
 40     {
 41         if((temp & 0x80)!=0)//取指令最高位
 42             digitalWrite(i,HIGH);
 43         else
 44             digitalWrite(i,LOW );    
 45         temp <<= 1;
 46     }    
 47     delayMicroseconds(1);          // 延时1us
 48     digitalWrite(Enable,HIGH);
 49     delayMicroseconds(1);          // 延时1us
 50     digitalWrite(Enable,LOW);
 51     delayMicroseconds(1);          // 延时1us
 52 }
 53 
 54 void LcdDataWrite(int value) {
 55     // 定义所有引脚
 56     int i = 0;
 57     digitalWrite(Enable,LOW);
 58     delayMicroseconds(1);        // 延时1us
 59     digitalWrite(RS, HIGH);
 60     digitalWrite(RW, LOW);
 61     int temp=value& 0xf0;
 62     for (i=DB[0]; i <= 9; i++)
 63     {
 64         if((temp & 0x80)!=0)//取指令最高位
 65             digitalWrite(i,HIGH);
 66         else
 67             digitalWrite(i,LOW );    
 68         temp <<= 1;
 69     }
 70     digitalWrite(Enable,HIGH);
 71     delayMicroseconds(1);        // 延时1us
 72     digitalWrite(Enable,LOW);
 73 
 74     temp=(value & 0x0f)<<4;
 75     for (i=DB[0]; i <= 9; i++)
 76     {
 77         if((temp & 0x80)!=0)//取指令最高位
 78             digitalWrite(i,HIGH);
 79         else
 80             digitalWrite(i,LOW );    
 81         temp <<= 1;
 82     }
 83     delayMicroseconds(1);        // 延时1us
 84     digitalWrite(Enable,HIGH);
 85     delayMicroseconds(1);        // 延时1us
 86     digitalWrite(Enable,LOW);
 87     delayMicroseconds(1);          // 延时1us
 88 }
 89 
 90 void setup (void) {
 91     int i = 0;
 92     for (i=Enable; i <= RS; i++) {
 93        pinMode(i,OUTPUT);   
 94     }
 95     delay(100);
 96     // 短暂的停顿后初始化LCD
 97     // 用于LCD控制需要
 98     LcdCommandWrite(0x38);         // 设置为8-bit接口,2行显示,5x7文字大小                     
 99     delay(20);                      
100     LcdCommandWrite(0x06);      // 输入方式设定,自动增量,画面没有移位
101     delay(20);                      
102     LcdCommandWrite(0x0C);      // 显示设置,开启显示屏,光标关,无闪烁
103     delay(20);                                  
104 }
105 
106 void loop (void) {
107   LcdCommandWrite(0x01);          // 屏幕清空,光标位置归零  
108   delay(10); 
109   LcdCommandWrite(0x80+5);         // 定义光标位置为第一行第五个位置
110   delay(10);                     
111   // 写入欢迎信息 
112   LcdDataWrite(\'W\');
113   LcdDataWrite(\'e\');
114   LcdDataWrite(\'l\');
115   LcdDataWrite(\'c\');
116   LcdDataWrite(\'o\');
117   LcdDataWrite(\'m\');
118   LcdDataWrite(\'e\');
119   delay(10);
120   LcdCommandWrite(0xc0+2);          // 定义光标位置为第二行第二个位置  
121   delay(10); 
122   LcdDataWrite(\'I\');
123   LcdDataWrite(\' \');
124   LcdDataWrite(\'a\');
125   LcdDataWrite(\'m\');
126   LcdDataWrite(\' \');
127   LcdDataWrite(\'D\');
128   LcdDataWrite(\'a\');
129   LcdDataWrite(\'D\');
130   LcdDataWrite(\'a\');
131   LcdDataWrite(\'W\');
132   LcdDataWrite(\'e\');
133   LcdDataWrite(\'i\');
134   delay(3000);
135   LcdCommandWrite(0x01);         // 屏幕清空,光标位置归零
136   delay(10);
137   LcdCommandWrite(0x80+2);         //定义光标位置为第一行第二个位置
138   delay(10);  
139   LcdDataWrite(\'H\');
140   LcdDataWrite(\'e\');
141   LcdDataWrite(\'l\');
142   LcdDataWrite(\'l\');
143   LcdDataWrite(\'o\');
144   LcdDataWrite(\' \');
145   LcdDataWrite(\'W\');
146   LcdDataWrite(\'o\');
147   LcdDataWrite(\'r\');
148   LcdDataWrite(\'l\');
149   LcdDataWrite(\'d\');
150   LcdDataWrite(\'!\');
151   LcdCommandWrite(0xc0);          // 定义光标位置为第二行起始位置  
152   delay(10);
153   LcdDataWrite(\'4\');
154   LcdDataWrite(\'-\');
155   LcdDataWrite(\'B\');
156   LcdDataWrite(\'i\');
157   LcdDataWrite(\'t\');
158   LcdDataWrite(\'-\');
159   LcdDataWrite(\'I\');
160   LcdDataWrite(\'n\');
161   LcdDataWrite(\'t\');
162   LcdDataWrite(\'e\');
163   LcdDataWrite(\'r\');
164   LcdDataWrite(\'f\');
165   LcdDataWrite(\'a\');
166   LcdDataWrite(\'c\');
167   LcdDataWrite(\'e\');
168   delay(10); 
169   delay(5000);
170 }

 

2.使用LiquidCrystal库

 1 /*Arduino在4位接法下使用LiquidCrystal库
 2 * 输出欢迎界面和Hello World!
 3 * 作者:大大维
 4 * 2016/10/23
 5 */
 6 #include<LiquidCrystal.h>
 7 LiquidCrystal lcd(13,12,11,10,9,8,7);            //初始化LCD
 8 void setup(){
 9     lcd.begin(16,2);                               //设置LCD为16列*2行
10 }
11 void loop(){
12     lcd.clear();                                //清屏操作
13     lcd.setCursor(5,0);                            //设置光标位置为第一行,第六列
14     lcd.print("Welcome");                        //在LCD上输出信息
15     delay(10);                                    //延时程序
16     lcd.setCursor(2,1);
17     lcd.print("I am DaDaWei");
18     delay(3000);
19     lcd.clear();
20     lcd.setCursor(2,0);
21     lcd.print("Hello World!");
22     lcd.setCursor(0,1);
23     lcd.print("4-Bit-Interface");
24     delay(5000);
25 }

 

<4>试验展示

 演示视频