1. 基于proteus的51单片机开发实例18-LCD1602液晶显示1.1. 实验目的

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(1)

图1 LCD1602显示电路

前面我们已经学习了使用数码管显示数字和简单的字符,但是数码管显示内容有很大的局限性,例如显示的字符数量有限,并且显示复杂的字符形状时,显示的效果不是很好。例如使用8段数码管显示字符“S”时,效果如下图。可以看出这个“S”与数字“5”很像。事实上,数码管显示字符的段码表里面,字符“S”和数字“5”的段码是一样的。

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(2)

数码管显示数字和字符

在本例中,我们使用显示内容更为丰富的液晶来显示字符和数字。使用LCD1602液晶显示“laomashitu mcu”和“0123456789”两行字符,从而熟悉和掌握LCD1602液晶的原理、驱动方法和编程实现。

本实例有两个目的:

1、了解LCD1602液晶的显示原理、驱动电路设计;

2、掌握51单片机编程控制LCD1602液晶显示字符和数字的方法。

1.2. 设计思路

本实例先从LCD1602液晶的工作原理入手,根据其工作原理在proteus中画出LCD1602液晶的工作电路,然后使用51单片机编程实现LCD1602液晶的显示控制。

1.3. 基础知识

关于液晶,想必大家都很熟悉了。从液晶的显示内容可分为段式、字符式、点阵式3种。其中段式液晶的显示内容与数码管一样,原理和驱动方法采用数码管的原理和驱动方法即可。本例中我们使用的LCD1602液晶是字符式液晶。点阵式液晶在后面的例子中再学习。

首先从字面来理解LCD1602液晶。16代表该LCD每行可显示16个字符,02表示该液晶共有两行。因此LCD1602液晶一共可显示32个字符。

下面两个图分别是LCD1602液晶的实物图和引脚图。

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(3)

LCD1602液晶实物图

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(4)

LCD液晶引脚图

我们知道单片机编程主要是根据不同的条件检测端口的电平高低(模拟功能除外),控制端口输出高低电平。所以,对于控制lcd1602液晶,了解其引脚功能是编程的必要条件。

1.3.1. Lcd1602液晶的引脚功能

VSS:电源地

VDD:电源

VEE:液晶对比度调节引脚,可以用一个电位器连接到VDD以调节对比度。

RS:寄存器选择引脚,当RS=0时,选择指令寄存器;RS=1时,选择数据存储器。

R/W:读、写控制引脚。R/W=0时,可以对LCD1602执行写操作,R/W=1,可以对LCD1602执行读操作。

E:使能信号引脚。在该引脚的下降沿,数据被写入LCD1602,当该引脚为高电平时,可以对LCD1602进行读数据操作。

D0~D7:数据总线引脚。

LEDA:背光电源地

LEDK:背光电源

1.3.2. LCD1602液晶显示字符的过程

要通过电路和编程控制LCD1602液晶显示字符,需要解决三个问题。

1、字符标准ASCII码的产生

常用字符的标准ASCII码必须人工产生,在程序中定义字符常量或字符串常量时,C语言在编译后会自动产生其标准的ASCII码。只要将生成的标准ASCII码通过单片机的I/O口送入LCD1602的数据显示寄存器DDRAM中,内部控制线路就会自动将字符传送到显示器上。

单片机中字符型数据或字符串数据的定义一般使用数组方式。例如定义一个字符串unsigned char code string[ ]={"laomashitu mcu"}; 大家可以看到,这个数组没有定义长度,C51会自动根据字符串的长度来指定数组的长度,注意这个数组的最后一个字符默认是空字符“\0”,字符串用双引号括起来。

2、LCD1602显示模式的设置

要让LCD1602液晶显示字符,必须对“有无光标、光标的移动方向、光标是否闪烁、字符的移动方向”等内容进行设置,液晶才会按照设计要求进行显示。这些设置是通过一系列控制指令实现的。控制指令在下面会有详细描述。

需要说明的时候,发送控制指令时,需要对RS和R/W引脚的电平进行相应设置,不同的指令对RS和R/W引脚的电平要求不同。

3、如何指定字符显示位置

要显示字符,必须要让LCD1602液晶控制器直到要在哪个位置显示,即要在第几行第几列显示。也就是说,要先向液晶控制器输入待显示字符的地址。(具体的地址定义在下面控制指令里有详细说明)。

LCD1602液晶内部显示地址如下图所示。指定显示位置的方法是“80H 地址码(第一行00H~0FH,第二行40H~4FH)”。例如要在第一行第2列显示一个字符,则应指定地址码为80H 01H=81H。

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(5)

LCD1602液晶内部显示地址

1.3.3. LCD1602液晶的控制指令清屏指令

将屏幕显示的内容清空。用于清除DDRAM和AC的值。

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(6)

归零指令

将屏幕的光标回归原点。

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(7)

输入方式选择指令

设置光标和画面的移动方式。

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(8)

I/D=1:数据读、写操作后,AC自动加1;

I/D=0:数据读、写操作后,AC自动减1.

S=1:数据读、写操作后,画面平移;

S=0:数据读、写操作后,画面保持不变

显示开关控制指令

用于设置显示、光标及闪烁开、关。

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(9)

D=1:显示开;

D=0:显示关。

C=1:光标开;

C=0:光标关。

B=1:闪烁开;

B=0:闪烁关。

光标和画面移动指令

用于在不影响DDRAM的情况下,使光标、画面移动。

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(10)

S/C=1:画面平移一个字符位;

S/C=0:光标平移一个字符位。

R/L=1:右移;

R/L=0:左移。

功能设置指令

用于设置工作方式。(初始化指令)

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(11)

DL=1:8位数据接口;

DL=0:4位数据接口。

N=1:两行显示;

N=0:一行显示。

F=1:5*10点阵字符;

F=0:5*7点阵字符。

CGRAM设置指令

用于设置CGRAM地址,A5~A0=0x00~0x3f。

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(12)

DDRAM设置指令

用于设置DRAM地址。

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(13)

N=0:一行显示,地址:A6~A0=0~4fH;

N=1:两行显示,第一行地址A6~A0=0~2fH,第二行地址A6~A0=40~64H。

l读RF和AC指令

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(14)

BF=1:忙;

BF=0:准备好。此时AC值为最近一次地址设置(CGRAM或DDRAM)的值。

写数据指令

用于将地址码写入DDRAM以使LCD显示出相应的图形或将用户自创的图形存入CGRAM内。

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(15)

读数据指令

根据当前设置的地址,从DDRAM或CGRAM读出数据。

51单片机1602液晶显示程序介绍(基于proteus的51单片机开发实例18-LCD1602液晶显示字符)(16)

1.3.4. LCD1602的初始化步骤:

1、设置LCD1602的功能;

2、设置LCD1602的输入方式

3、设置LCD1602的显示方式

4、清除LCD1602的屏幕

1.4. 电路设计

本实例电路如图1所示。LCD1602液晶的数据管脚连接单片机的P3口的P3.0~P3.7。LCD1602液晶的控制管脚RW,RS,E连接P2口的3个引脚。整体电路很简单。

1.5. 程序设计

本实例程序代码如下。程序代码中在重要的地方都有详细注释。

#include<AT89x52.h> //单片机端口、寄存器定义头文件 #include<intrins.h> //库函数调用,包含_nop_()语句的头文件 //单片机引脚位定义 sbit RS=P2^5; //RS位定义,寄存器选择位定义 sbit RW=P2^6; //RW位定义,读写选择位 sbit E=P2^7; //E位定义,使能信号位 //位变量定义 sbit BF=P0^7; //忙标志检测位,即LCD1602的D7位 //全局变量定义 unsigned char code digit[ ]={"0123456789"}; //定义数字字符串,code表示不占用RAM空间,保存在ROM中 unsigned char code string[ ]={"laomashitu mcu"}; //定义字符串数组 //函数声明 //延时函数,1ms延时函数 void delay1ms(); //延时函数 void delay(unsigned char n); //液晶忙状态检测函数 unsigned char BusyTest(void); //液晶工作模式设置或显示地址函数, void WriteInstruction (unsigned char dictate); //指定字符显示地址函数 void WriteAddress(unsigned char x); //数据写入液晶控制模块函数 void WriteData(unsigned char y); //显示模式初始化函数 void LcdInitiate(void); //主程序 void main(void) { unsigned char i; LcdInitiate(); //LCD1602液晶初始化 WriteAddress(0x00); //写地址,从第一行第一列开始显示字符 i=0; while(string[i]!='\0') //显示字符,直到显示完字符串数字的内容 { WriteData(string[i]); // delay(1000);//每显示一个字符,延时一会 i ; //显示下一个字符 } WriteAddress(0x40); //第二行液晶显示,从第1列开始 i=0; // while(digit[i]!='\0') //直到显示完数组中全部内容 { WriteData(digit[i]); // delay(1000); i ; // } while(1) //主循环 { } } /***************************************************** 函数功能描述:延时1ms,大约1ms ***************************************************/ void delay1ms() { unsigned char i,j; //变量定义和程序执行内容之间最好空一行 for(i=0;i<10;i ) for(j=0;j<33;j ) ; } /***************************************************** 函数功能;延时若干ms ***************************************************/ void delay(unsigned char n) { unsigned char i; for(i=0;i<n;i ) delay1ms(); } /***************************************************** 函数功能:判断液晶模块是否处于忙状态, 如果处于忙状态,则不能对液晶进行操作 ***************************************************/ unsigned char BusyTest(void) { bit result;//位变量定义 RS=0; //读忙状态前,需要将RS置低,RW置高 RW=1; E=1; //E=1£¬²ÅÔÊÐí¶Áд _nop_(); //空操作,相当于延时 _nop_(); _nop_(); _nop_(); //一个nop的空操作相当于延时一个机器周期 result=BF; //读取忙状态标志 E=0; //将E恢复为低电平 return result;//函数返回忙状态值 } /***************************************************** 函数功能:模式设置 ***************************************************/ void WriteInstruction (unsigned char dictate) { while(BusyTest()==1); //设置前先判断液晶空闲状态,空闲,则可进行设置 RS=0; //模式设置前,RS和RW置低电平 RW=0; E=0; //E置低电平,写指令时,需要E有一个正跳变,即从0跳变到1 _nop_(); _nop_(); //延时一会 P3=dictate; //将数据送到液晶的数据端口 _nop_(); _nop_(); _nop_(); _nop_(); // E=1; //E置高电平,写数据前E置低,这样就是一个从0到1的跳变 _nop_(); _nop_(); _nop_(); _nop_(); // E=0; //E由高到低的跳变,液晶模块开始执行命令 } /***************************************************** 函数功能:指定字符显示地址 ***************************************************/ void WriteAddress(unsigned char x) { WriteInstruction(x|0x80); //显示位置的制定规则:80H 地址码 } /***************************************************** 函数功能:将数据写入液晶模块 ***************************************************/ void WriteData(unsigned char y) { while(BusyTest()==1); RS=1; //写数据前,需要设置RS=1,RW=0 RW=0; E=0; //写命令需要E有一个从0到1的跳变, // 写之前E置0,数据送出后E置1,这样就产生了跳变 P3=y; //数据送到液晶数据端口 _nop_(); _nop_(); _nop_(); _nop_(); // E=1; //数据送出后,E置1,以便产生0到1的跳变 _nop_(); _nop_(); _nop_(); _nop_(); // E=0; //E由1跳变到0,则液晶开始执行命令 } /***************************************************** 函数功能:显示模式初始化设置 ***************************************************/ void LcdInitiate(void) { delay(15); // WriteInstruction(0x38); //显示模式设置:16*2显示,5*7点阵,8位数据接口 delay(5); //每一条指令后都延时一会,便于液晶有时间执行完指令 WriteInstruction(0x38); delay(5); WriteInstruction(0x38); //初始化指令可多执行几次,确保初始化成功 delay(5); WriteInstruction(0x0c); //显示模式设置:显示开,无光标,光标不闪烁 delay(5); WriteInstruction(0x06); //显示模式设置:光标右移,字符不移 delay(5); WriteInstruction(0x01); //清屏指令:将液晶屏幕当前显示内容清除 delay(5); }

这段程序实现的功能是:LCD1602液晶从第一行第1列开始逐个显示字符“laomashitu mcu”,第二行逐个显示字符“0123456789”。

1.6. 实例仿真

编译程序后,将生成的hex文件载入proteus电路的单片机中,开始仿真,LCD1602液晶显示的内容,是否符合设计预期。

下面视频是本实例的仿真过程。

1.7. 总结

通过本实例的学习,初步学习了LCD1602液晶的显示电路和编程控制。在接下来的实例中,我们将会进一步学习LCD1602液晶的更多功能。

,