LCD1602的电路图和程序
LCD1602液晶显示实验实验报告及程序.doc
实验三 LCD1602 液晶显示实验姓名专业学号成绩一、实验目的1.掌握 Keil C51 软件与 proteus 软件联合仿真调试的方法;2.掌握 LCD1602液晶模块显示西文的原理及使用方法;3.掌握用 8 位数据模式驱动 LCM1602液晶的 C 语言编程方法;4.掌握用 LCM1602液晶模块显示数字的 C 语言编程方法。
二、实验仪器与设备1.微机一台 C51 集成开发环境仿真软件三、实验内容1.用 Proteus 设计一 LCD1602液晶显示接口电路。
要求利用 P0口接 LCD1602液晶的数据端, ~做 LCD1602液晶的控制信号输入端。
~口扩展 3 个功能键 K1~K3。
参考电路见后面。
2.编写程序,实现字符的静态和动态显示。
显示字符为第一行:“ 1. 姓名全拼”,第二行:“ 2. 专业全拼 +学号”。
3.编写程序,利用功能键实现字符的垂直滚动和水平滚动等效果显示。
显示字符为:“1. 姓名全拼 2.专业全拼+学号EXP8DISPLAY ”主程序静态显示“ My information!”四、实验原理液晶显示的原理:采用的 LCD显示屏都是由不同部分组成的分层结构,位于最后面的一层是由荧光物质组成的可以发射光线的背光层,背光层发出的光线在穿过第一层偏振过滤层之后进入包含成千上万水晶液滴的液晶层,液晶层中的水晶液滴都被包含在细小的单元格结构中,一个或多个单元格构成屏幕上的一个像素。
当 LCD中的电极产生电场时,液晶分子就会产生扭曲,从而将穿越其中的光线进行有规则的折射,然后经过第二层过滤层的过滤在屏幕上显示出来。
1.LCD1602采用标准的 14 引脚(无背光)或 16 引脚(带背光)接口,各引脚接口说明如表:编号符号引脚说明编号符号引脚说明1VSS电源地9D2数据2VDD电源正极10D3数据3VL液晶显示偏压11D4数据4RS数据/命令选择12D5数据5R/W读/写选择13D6数据6E使能信号14D7数据7D0数据15BLA背光源正极8D1数据16BLK背光源负极2. 1602 液晶模块内部的控制器共有11 条控制指令,如表所示:3.芯片时序表:4. 1602LCD的一般初始化 ( 复位 ) 过程(1)延时 15ms。
51单片机驱动LCD1602程序设计(C语言)
字符液晶绝大多数是基于 HD44780 液晶芯片的,控制原理是完全相同的,因此 HD44780 写 的控制程序可以很方便地应用于市面上大部分的字符型液晶。字符型 LCD 通常有 14 条引脚线或 16 条引脚线的 LCD,多出来的 2 条线是背光电源线 VCC(15 脚)和地线 GND(16 脚),其控制原理 与 14 脚的 LCD 完全一样,定义如下表所示:
for(i=0;i<count;i++) {
if (0 == y) x |= 0x80; //当要显示第一行时地址码+0x80; else x |= 0xC0; //在第二行显示是地址码+0xC0; Write_com(x); //发送地址码 Write_dat(*p); //发送要显示的字符编码 x++; p++; }
01110
○■■■○
10001
■○○○■
10001
■○○○■
10001
■○○○■
11111
■■■■■
10001
■○○○■
10001
■○○○■
上图左边的数据就是字模数据,右边就是将左边数据用“○”代表 0,用“■”代表 1。看出是个“A”
字了吗?在文本文件中“A”字的代码是 41H,PC 收到 41H 的代码后就去字模文件中将代表 A 字的
字符型 LCD 的引脚定义
HD44780 内置了 DDRAM、CGROM 和 CGRAM。DDRAM 就是显示数据 RAM,用来寄存 待显示的字符代码。共 80 个字节,其地址和屏幕的对应关系如下表:
也就是说想要在 LCD1602 屏幕的第一行第一列显示一个"A"字,就要向 DDRAM 的 00H 地址写 入“A”字的代码就行了。但具体的写入是要按 LCD 模块的指令格式来进行的。在 1602 中我们用前 16 个就行了。第二行也一样用前 16 个地址。对应如下:
LCD1602液晶显示器
实验11:1602液晶显示屏显示(字符型液晶显示器)字符型液晶显示器用于数字、字母、符号并可显示少量自定义符号。
这类液晶显示器通常有16根接口线,下表是这16根线的定义。
字符型液晶接口说明编号符号引脚说明编号符号引脚说明1 Vss 电源地 9 D2 数据线22 Vdd 电源正 10 D3 数据线33 VL 液晶显示偏压信号 11 D4 数据线44 RS 数据/命令选择端 12 D5 数据线55 R/W 读/ 写选择端 13 D6 数据线66 E 使能信号 14 D7 数据线77 D0 数据线0 15 BLA 背光源正极8 D1 数据线1 16 BLK 背光源负极(本学习板配的内部已经接地)下图是字符型液晶显示器与单片机的接线图。
这用了P0口的8根线作为液晶显示器的数据线,用P20、P21、P22做为3根控制线。
字符型液晶显示器与单片机的接线图字符型液晶显示器的使用,字符型液晶显示器一般采用HD44780芯片做为控制器的。
1.字符型液晶显示器的驱动程序这个驱动程序适用于1602型字符液晶显示器,1) 初始化液晶显示器命令(RSTLCD)设置控制器的工作模式,在程序开始时调用。
参数:无。
2) 清屏命令(CLRLCD)清除屏幕显示的所有内容参数:无3) 光标控制命令(SETCUR)用来控制光标是否显示及是否闪烁参数:1个,用于设定显示器的开关、光标的开关及是否闪烁。
4) 写字符命令(WRITECHAR)在指定位置(行和列)显示指定的字符。
参数:共有3个,即行值、列值及待显示字符,分别存放在XPOS、YPOS和A中。
其中行值与列值均从0开始计数,A中可直接写入字符的符号,编译程序自动转化为该字符的ASCII值。
5) 字符串命令(WRITESTRING)在指定位置显示指定的一串字符。
参数:共有3个,即行值、列值和R0指向待显示字符串的内存首地址,字符串须以0结尾。
如果字符串的长度超过了从该列开始可显示的最多字符数,则其后字符被截断,并不在下行显示出来。
LCD1602的简单显示程序
/*======================================================
===
1602液晶显示的实验例子
-------------------------------------------------
| DB4-----P0.4 | RW-------P2.1
函数名:Read_Status_LCM()
功能:忙检测函数
======================================*/
void Read_Status_LCM(void)
{
unsigned char read=0;
LCM_RW = 1;
LCM_RS = 0;
LCM_E = 1;
LCM_Data = 0xff;
delay_nms(15);
Write_Command_LCM(0x28,1); //显示模式设置,开始要求每次检测忙信号
Write_Command_LCM(0x08,1); //关闭显示
Write_Command_LCM(0x01,1); //显示清屏
void LCM_Init(void) //LCM初始化
{
LCM_Data = 0;
Write_Command_LCM(0x28,0); //三次显示模式设置,不检测忙信号
delay_nms(15);
Write_Command_LCM(0x28,0);
delay_nms(15);
Write_Command_LCM(0x28,0);
函数名:Write_Command_ LCM ( )
功能:对LCD 1602写指令
lcd1602程序流程图
LCD1602程序代码和显示流程图LCD1602显示程序代码_ DB P0 //---P0 = DB0〜DB7位LCD_ RS = P2; //--p2.0 = RS 位LCD_ RW = P2; //--p2.1 = RW 位LCD_ E = P2; //-p2.2 = E / /---/--/--定义函数ා 定义uchar unsigned char ා 定义uint unsigned int // //-定义子程序函数void LCD_ Init (void ); //-初始化LCD1602函数void LCD_ write_ Command (uchar command ); //-写指令功能无效LCD 到LCD1602_ write_数据(uchar DAT ); //-将无效的LCD 数据写入LCD1602_ set_ XY (uchar x ,uchar y ); //设置LCD1602的显示位置x (0-16),y(1-2)void LCD_ disp_ Char(uchar x,uchar y,uchar DAT); //-在LCD1602_ disp_ String (uchar x,uchar y,uchar * s)上显示字符无效的LCD;//-在LCD1602上显示字符串// void LCD_ check_ Busy(void); //检查忙功能。
我没有使用此功能,因为通过率非常低。
LCD_ delay_ 10us(uint n); //-一个10微秒的延迟子程序void LCD_ delay_ 50uS(uint n); /-延迟子程序50微秒_ init(无效){LCD_ delay_ 10us(20); LCD_ write_命令(0x38); //-设置8位格式,2行,5x7 LCD_ delay_ 10us(5);LCD_ write_命令(0x0c); //-整体显示,关闭光标,不闪烁LCD_ delay_ 10us(5);LCD_ write_命令(0x06); //-设置输入模式,增量不移位LCD_ delay_ 10us(5);LCD_ write_命令(0x01); // /-清除屏幕上的LCD_ delay_ 50uS(40);} //将无效的LCD指令写入LCD1602_ write_命令(uchar dat){LCD_ delay_ 10us (5);LCD_ Rs = 0; //命令LCD_RW = 0;//写入LCD_ DB = dat; LCD_ delay_ 10us(5); LCD_ E = 1; //允许LCD_delay_10us(5);LCD_ E = 0;} /-将数据无效LCD写入LCD1602_ write_ data(uchar dat){LCD_ delay_ 10us(5);LCD_ Rs = 1; //数据LCD_RW = 0;//写入LCD_ DB = dat; LCD_ delay_ 10us(5); LCD_ E = 1; //允许LCD_delay_10us(5);LCD_ E = 0;} /-设置显示位置无效LCD_ set_ XY(uchar x,uchar y){uchar地址;如果(y = = 1){地址= 0x80 + X; /-第一行位置} else {地址= 0xc0 + X; //第二行位置} LCD_ delay_ 10us(5); LCD_ write_命令(地址);} /-显示字符函数void LCD_ disp_ char(uchar x,uchar y,uchar dat)//--LCD_ disp_ Char(0,1,0x38); /-显示8 {LCD_ set_ xy(x,y); LCD_ delay_ 10us(5); LCD_ write_ Data(DAT);} /-显示字符串函数void LCD_ disp_ string(uchar x,uchar y,uchar * s){LCD_ set_ xy(x,y); LCD_ delay_ 10us(5); while(* s!='\ 0'){LCD_ write_ Data(* s); s + +;} / /≡S + +;} /≡S + _ check_ Busy()// /实践证明,在我的LCD1602上,检查忙指令的通过率非常低,并且{/ /液晶正常使用。
LCD1602最详细资料
1602字符液晶所谓1602是指显示的内容为16*2,即可以显示两行,每行16个字符。
目前市面上字符液晶绝大多数是基于HD44780液晶芯片的,控制原理是完全相同的,因此基于HD44780写的控制程序可以很方便地应用于市面上大部分的字符型液晶。
1602液晶的正面(绿色背光,黑色字体)1602液晶背面(绿色背光,黑色字体)另一种1602液晶模块,显示屏是蓝色背光白色字体字符型LCD1602通常有14条引脚线或16条引脚线的LCD,多出来的2条线是背光电源线VCC(15脚)和地线GND(16脚),其控制原理与14脚的LCD完全一样,引脚定义如下表所示:HD44780内置了DDRAM、CGROM和CGRAM。
DDRAM就是显示数据RAM,用来寄存待显示的字符代码。
共80个字节,其地址和屏幕的对应关系如下表:也就是说想要在LCD1602屏幕的第一行第一列显示一个"A"字,就要向DDRAM 的00H地址写入“A”字的代码就行了。
但具体的写入是要按LCD模块的指令格式来进行的,后面我会说到的。
那么一行可有40个地址呀?是的,在1602中我们就用前16个就行了。
第二行也一样用前16个地址。
对应如下:DDRAM地址与显示位置的对应关系(事实上我们往DDRAM里的00H地址处送一个数据,譬如0x31(数字1的代码)并不能显示1出来。
这是一个令初学者很容易出错的地方,原因就是如果你要想在DDRAM的00H地址处显示数据,则必须将00H加上80H,即80H,若要在DDRAM的01H处显示数据,则必须将01H加上80H即81H。
依次类推。
大家看一下控制指令的的8条:DDRAM地址的设定,即可以明白是怎么样的一回事了)1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,如下表所示,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B (41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”上表中的字符代码与我们PC中的字符代码是基本一致的。
LCD1602数据手册LCD16...
LCD1602数据手册1602采用标准的16脚接口,其中:第1脚:VSS为地电源第2脚:VDD接5V正电源第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高,对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
第5脚:RW为读写信号线,高电平时进行读操作,低电平时进行写操作。
当RS和RW共同为低电平时可以写入指令或者显示地址,当RS为低电平RW为高电平时可以读忙信号,当RS为高电平RW为低电平时可以写入数据。
第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
第7~14脚:D0~D7为8位双向数据线。
第15~16脚:空脚1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,如表1所示,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”1602液晶模块内部的控制器共有11条控制指令,如表2所示,它的读写操作、屏幕和光标的操作都是通过指令编程来实现的。
(说明:1为高电平、0为低电平)指令1:清显示,指令码01H,光标复位到地址00H位置指令2:光标复位,光标返回到地址00H指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否左移或者右移。
高电平表示有效,低电平则无效指令4:显示开关控制。
D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符指令7:字符发生器RAM地址设置指令8:DDRAM地址设置指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
IIC接口 I2C接口 LCD1602 程序
PIC16F1824驱动IIC/I2C接口LCD1602液晶模块前一段时间,做一个显示电路,7段码显示内容太少,LCD1602占用的IO又太多,最后找到一种IIC/I2C接口LCD1602转接板。
T宝上买的LCD1602转接板,有资料,不过是针对Arduino的。
决定自己写程序。
首先得知道从器件地址。
T宝卖家给的地址是0x27(针对Arduino),而单片机使用的时候需要先左移一位,0x4E;测试的时候一直没反应,用示波器看,单片机发送的地址没问题,但转接板没有应答,ACK 一直是高电平,推测还是地址错误;后来搜索发现,PCF8574与PCF8574A的地址是不一样的,而T宝卖的是PCF8574A,给的资料还是PCF8574。
最后确认,从器件PCF8574A地址应该是0x7E;后来发送地址0x7E后,有应答ACK,又搜了写LCD1602的显示程序,稍微改了改,显示成功了;主要的程序如下:MCU:PIC16F1824IIC/I2C接口LCD1602转接板:PCF8574ATmain.c中包含:I2CInit();LCD1602Init();Dip_Single_char(1,5,'A');//********************************************************************// 文件名称: I2C.h// 创建日期: 2016-10-11// 最新更改: 2016-10-11// 描述: I2C初始化//********************************************************************//#define _XTAL_FREQ 2000000 // 延时函数delay_us/ms使用此值#define Slave_Add 0x7E // 从器件地址,PCF8574A,0x7E// PCF8574,0x27,左移1位,0x4E,#define I2C_BPS 0x18 // I2C波特率Fclock = Fosc/((I2C_BPS+1)*4) // 2MHz,20k,0x18#define Idle !(SSP1STATbits.R_nW|(0x1F & SSP1CON2)) // 空闲void I2CInit ( );void I2CStart ( );void I2CStop ( );void ReStart ( );void I2CSendByte(unsigned char I2CSnBy);void WriteCommand(unsigned char Command);void WriteData (unsigned char Data);void LCD1602Init(void);void Dip_Single_char(unsigned char col,unsigned char row,unsigned char sign); void DisDec(unsigned char col_D,unsigned char row_D,unsigned int Temp_k );/*********************************************************************** The End*********************************************************************///********************************************************************// 文件名称: I2C.c// 创建日期: 2016-10-11// 最新更改: 2016-10-11// 描述: I2C初始化//********************************************************************//#include "xc.h"#include "I2C.h"/*********************************************************************** Function name: I2CInit** Descriptions: 注意:必须将SDA、SCL引脚配置为输入引脚,<<DS P293>>** input parameters: 无** output parameters: 无** Returned value: 无**********************************************************************/void I2CInit (void){SSP1STATbits.SMP = 1; // 禁止标准速度模式下的压摆率控制SSP1STATbits.CKE = 0; // 禁止SMBus特定输入SSP1CON1bits.SSPEN = 1; // 使能I2C,并将SDA 和SCL引脚配SSP1CON1bits.SSPM = 0x8; // I2C主模式SSP1ADD = I2C_BPS; // Fclock = Fosc / ((SSP1ADD + 1)*4)}/*********************************************************************** Function name: I2CStart ( )** Descriptions: I2C开始** input parameters: 无** output parameters: 无** Returned value: 无**********************************************************************/void I2CStart ( ){while (!Idle);SSP1CON2bits.SEN = 1; // 在SDA和SCL引脚上发出启动条件,硬件自动清零 while(SSP1CON2bits.SEN); // 启动条件发送完成while(!Idle);}/*********************************************************************** Function name: I2CStop ( )** Descriptions: I2C停止** input parameters: 无** output parameters: 无** Returned value: 无**********************************************************************/void I2CStop(){while (!Idle);SSP1CON2bits.PEN = 1; // 在SDA和SCL引脚上发出停止条件,硬件自动清零 while(SSP1CON2bits.PEN); // 停止条件发送完成while(!Idle);}/*********************************************************************** Function name: ReStart()** Descriptions: I2C ,ReStart** input parameters: 无** output parameters: 无** Returned value: 无**********************************************************************/void ReStart(){while (!Idle);SSP1CON2bits.RSEN = 1; // 在SDA和SCL引脚上发出重复启动条件,硬件自动清零while(SSP1CON2bits.RSEN); // 重复启动条件发送完成while(!Idle);}/*********************************************************************** Function name: I2CSendByte()** Descriptions: SSP1BUF中写入字节** input parameters: I2CSnBy,要发送的数据** output parameters: 无** Returned value: 无**********************************************************************/void I2CSendByte(unsigned char I2CSnBy) {while (!Idle);SSP1BUF = I2CSnBy; // SSP1BUF中写入字节while(!Idle);}/*********************************************************************** Function name:** Descriptions:** input parameters:** output parameters: 无** Returned value: 无**********************************************************************/void WriteCommand(unsigned char Command){I2CStart(); // I2C开始I2CSendByte(Slave_Add); // 从器件地址unsigned char Temp_C;Temp_C = Command & 0xF0;Temp_C |= 0x0C; // P3=1 EN=1 RW=0 RS=0I2CSendByte(Temp_C);Temp_C &= 0xF8; // P3=1 EN=0 RW=0 RS=0I2CSendByte(Temp_C);Temp_C = (Command & 0x0F)<< 4;Temp_C |= 0x0C; // P3=1 EN=1 RW=0 RS=0I2CSendByte(Temp_C);Temp_C &= 0xF8; // P3=1 EN=0 RW=0 RS=0I2CSendByte(Temp_C);I2CStop(); // I2C停止}/********************************************************************* ** Function name:** Descriptions:** input parameters:** output parameters: 无** Returned value: 无**********************************************************************/void WriteData (unsigned char Data){I2CStart(); // I2C开始I2CSendByte(Slave_Add); // 从器件地址unsigned char Temp_D;Temp_D = Data & 0xF0;Temp_D |= 0x0D; // P3=1 EN=1 RW=0 RS=1I2CSendByte(Temp_D);Temp_D &= 0xF9; // P3=1 EN=0 RW=0 RS=1I2CSendByte(Temp_D);Temp_D = (Data & 0x0F)<< 4;Temp_D |= 0x0D; // P3=1 EN=1 RW=0 RS=1I2CSendByte(Temp_D);Temp_D &= 0xF9; // P3=1 EN=0 RW=0 RS=1I2CSendByte(Temp_D);I2CStop(); // I2C停止}/*********************************************************************** Function name: LCD1602Init(void),LCD1602初始化** Descriptions: 写一次,偶尔不能正常显示,重复2次** input parameters:** output parameters: 无** Returned value: 无**********************************************************************/void LCD1602Init(void){__delay_ms(10);WriteCommand(0x33); __delay_ms(5);WriteCommand(0x32); __delay_ms(5);WriteCommand(0x28); __delay_ms(5);WriteCommand(0x0C); __delay_ms(5);WriteCommand(0x06); __delay_ms(5);WriteCommand(0x01); __delay_ms(5); // 清屏__delay_ms(10);WriteCommand(0x33); __delay_ms(5);WriteCommand(0x32); __delay_ms(5);WriteCommand(0x28); __delay_ms(5);WriteCommand(0x0C); __delay_ms(5);WriteCommand(0x06); __delay_ms(5);WriteCommand(0x01); __delay_ms(5); // 清屏}/********************************************************************** Function name: L1602_char(uchar col,uchar row,char sign)** Descriptions: 改变液晶中某位的值,如果要让第一行,第五个字符显示"b" ,调用该函数如,Dip_Single_char(1,5,'A');** input parameters: 行,列,需要输入1602的数据** output parameters: 无** Returned value: 无*********************************************************************/void Dip_Single_char(unsigned char col,unsigned char row,unsigned char sign){ unsigned char a;if(col == 1) a = 0x80;if(col == 2) a = 0xc0;a = a + row - 1;WriteCommand(a);WriteData(sign);}/********************************************************************** Function name: Dip_Single_char** Descriptions: 显示int型数据,5位** input parameters: 行,列,数据** output parameters: 无** Returned value: 无*********************************************************************/void DisDec(unsigned char col_D,unsigned char row_D,unsigned int Temp_k ){if(Temp_k>=65535) Temp_k=65535;unsigned int Temp_Ts;unsigned char Table[5]; // 数字与1602显示码转换Table[0] = Temp_k/10000+48; // 万位Temp_Ts = Temp_k%10000; // 取余,0-9999Table[1] = Temp_Ts/1000+48; // 千位Temp_Ts = Temp_Ts%1000; // 取余,0-999Table[2] = Temp_Ts/100+48; // 百位Temp_Ts = Temp_Ts%100; // 取余,0-99Table[3] = Temp_Ts/10+48; // 十位Table[4] = Temp_Ts%10+48; // 个位unsigned char q;for(q=0;q<5;q++){ // 显示Dip_Single_char(col_D,q+row_D,Table[q]);}}/*********************************************************************** The End*********************************************************************/。
LCD1602中文资料程序和使用说明
LCD1602中文资料程序和使用说明一、硬件连接和初始化步骤:1.将LCD1602的16个引脚连接到MCU(单片机)的相应引脚上。
其中,VCC和GND分别接到电源正负极,VO接到可调电位器的中间引脚(用于调节背光亮度),RS、RW和E分别接到MCU的IO口上,D0-D7分别接到MCU的8个IO口上。
2.初始化LCD1602的操作包括设置显示模式、显示光标、输入模式等,具体步骤如下:a.将8位数据接口设置为并行输入模式,即设置D0-D3为输入模式。
b.设置显示模式为2行显示,5x8点阵字符,显示器不移动。
c.将显示光标设置为闪烁显示。
d.设置数据输入方式为向右移动,同时字符显示不移动。
e.清除显示内容,将光标位置设置为第一行第一列。
f.打开显示器和光标显示功能。
二、常用函数和操作方法:1. void lcd1602_init( 初始化LCD1602,包括上述硬件连接和初始化步骤。
2. void lcd1602_clear( 清除显示内容。
3. void lcd1602_setCursor(int row, int column) 设置光标位置,row表示行数(从0开始),column表示列数(从0开始)。
4. void lcd1602_print(String str) 在当前光标位置打印字符串str。
5. void lcd1602_shiftDisplayLeft( 将显示内容向左移动一位。
6. void lcd1602_shiftDisplayRight( 将显示内容向右移动一位。
7. void lcd1602_scrollDisplayLeft( 将整个显示内容向左滚动一格。
8. void lcd1602_scrollDisplayRight( 将整个显示内容向右滚动一格。
9. void lcd1602_noCursor( 关闭光标显示。
10. void lcd1602_cursor( 打开光标显示。
LCD1602液晶显示实验
LCD1602液晶显示实验1.实验原理1.1 基本原理1.1.1 1602字符型LCD简介字符型液晶显示模块是一种专门用于显示字母、数字、符号等点阵式LCD,目前常用16*1,16*2,20*2和40*2行等的模块。
1.1.2 1602LCD的基本参数及引脚功能1602LCD分为带背光和不带背光两种,基控制器大部分为HD44780,带背光的比不带背光的厚,是否带背光在应用中并无差别,两者尺寸差别如下图1-2所示:图1-2 1602LCD尺寸图1.1602LCD主要技术参数:显示容量: 16×2个字符芯片工作电压: 4.5~5.5V工作电流: 2.0mA(5.0V)模块最佳工作电压: 5.0V字符尺寸: 2.95×4.35(W×H)mm2.引脚功能说明:1602LCD采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如表:表1-3引脚接口说明表编符号引脚说明编号符号引脚说明号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.1.3 1602LCD的指令说明及时序1602液晶模块内部的控制器共有11条控制指令,如表1-4所示:表1-4 控制命令表序号指令RS R/W D7 D6 D5 D4 D3 D2 D1 D01 清显示0 0 0 0 0 0 0 0 0 12 光标返回0 0 0 0 0 0 0 0 1 *3 置输入模式0 0 0 0 0 0 0 1 I/D S4 显示开/关控制0 0 0 0 0 0 1 D C B5 光标或字符移位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液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。
基于单片机的lcd1602电子时钟设计
基于单片机的LCD1602电子时钟设计一、设计任务和目的1.1、设计任务(1):用单片机设计基于LCD1602的电子时钟,显示时间和日期;(2):误差精度控制在1s/天;(3):具有时间和日期的校准功能;(4):能区分某年是闰年或平年,并对应显示2月份的天数;(5):根据月份的不同显示不同的最大日数;(6):搭建仿真电路图,模拟单片机要实现的功能;(7):焊接单片机开发板;(8):编写程序,下载并调试,实现要求的功能。
1.2、设计目的(1):熟练掌握KEIL软件的使用方法;(2):熟练掌握PROTEUS软件的使用方法;(3):掌握单片机I/O接口的工作原理;(4):掌握LCD显示器的工作原理及编程方法;(5):掌握独立式键盘的工作原理及编程使用方法;(6):掌握单片机的下载使用方法。
二、设计思路和方案论证2.1、设计思路电路总体上分为控制和显示部分。
以单片机最小系统作为核心控制电路,控制LCD显示,具体显示内容及方式由软件来完成;由于有时钟和日期的调节功能需要校准电路和基本的复位电路,复位电路采用按键复位,调节键、加1键、减1键三个按键完成,共需四个按键;计时功能由固定频率的晶振完成(采用11.0592MHz);显示部分主要采用LCD1602作为显示。
2.2、方案论证(1):时钟芯片的选择和论证方案一:采用DS1302时钟芯片实现时钟,DS1302芯片是一种高性能的时钟芯片,可自动对秒、分、时、日、月、年以及闰年补偿的年进行计数,精度也较高,工作电压2.5V~5.5V范围内,功耗也较低,但价格比较贵。
方案二:直接采用单片机定时计数器提供秒信号,使用程序实现秒、分、时、日、月、年计数。
采用此方案实现虽然有一定的时间误差,但可减少芯片的使用,节约成本,易于实现,符合现实选用,所以采用此种作为时钟信号发生器。
(2):显示模块选择方案和论证:方案一:采用点阵式图形LCD12864液晶显示屏,液晶显示屏的显示功能强大,可显示文字,图形,显示多样,清晰可见,但是价格昂贵,需要的接口线多,所以在此设计中不采用点阵式图形LCD12864液晶显示屏。
lcd1602程序流程图
lcd1602程序流程图lcd1602程序流程图1、引脚3(对⽐调整电压)接正电源时对⽐度最低,接地时对⽐度最⾼,通常通过⼀个10k的电位器相连后接地,上电后需要对电位器进⾏调整以显⽰出相应的字符(就像调节电视的对⽐度使图像清晰,这⾥是使字符清晰)2、D0~D7为8为数据总线,⽤于与单⽚机之间的数据传送了解了引脚功能后,我们再来看其内置芯⽚关于HD44780HD44780内部含有DDRAM,CGROM,CGRAM下⾯我来简单介绍⼀下这三个存储器DDRAM是⽤于寄存待显⽰字符代码的,其内部带有80字节的RAM 缓冲区,与LCD屏幕的位置⼀⼀对应。
通常我们只使⽤前16个地址(两⾏32个),这样⼀来,我们便可以将这32个地址当作是我们的坐标,⽐如要在DDRAM的02H 地址(对应的是屏幕第⼀⾏第三个)显⽰字符“A”,我们就可以分两步⾛,⾸先⽤程序先找到“坐标点”,也就是将地址转到02H(具体如何不做详细说明),然后在这个位置写⼊“A”,写⼊地址和数据都是通过D0~D7实现的,详细的程序在⽂章的后⾯举例说明。
CGROM与CGRAM是LCD内部固化的字模存储器,这相当于芯⽚内部划出的⼀块区域,CGROM⾥⾯存放着我们⽇常所使⽤的⼀些字符(192个),⽽CGRAM则允许⽤户⾃定义⼀些字符(8个)。
具体对应关系如下,0x00~0x0F就是⽤户⾃定义的CGRAM区。
再回到之前的问题,在DDRAM的02H地址显⽰字符“A”,⾸先通过程序找到地址02H,然后在该地址写⼊41H,从图中也可看出该位置对应的字符就是“A”。
我们再来理⼀理这个过程,有关字符显⽰,⾸先便是找到DDRAM 中我们所要显⽰位置对应的地址,接着便是在这个地址写⼊⼀个地址(单⽚机中的间接寻址),LCD根据这个地址在CGROM中找到对应的字符,然后在02H这个位置显⽰出来,这个过程也到此结束。
由于CGROM中的字符代码与PC中的字符代码基本⼀致,通常我们也直接在02H地址直接写⼊“A”,简化了程序设计。
LCD1602的电路图和程序文件
PORTE_PE5 = 1; //不亮
/*DDRA_DDRA0 = 1;
DDRA_DDRA1 = 1;
DDRA_DDRA2 = 1;
DDRA_DDRA3 = 1;*/
DDRA_DDRA4 = 0; //SET PORTA I/O INPUT
DDRA_DDRA5 = 0;
二、实验设备与器件
CodeWarrior软件,BDM仿真器,万用电路板,飞思卡尔单片机,LCD1602液晶显示器,
三、实验内容
内容:利用飞思卡尔单片机制作基于1602字符液晶显示器的显示系统
要求:用四个按键控制,按下第一个按键显示1,按下第二个按键显示2,以此类推。
(1)LCD1602液晶显示器的原理:1602共16个管脚,但是编程用到的主要管脚不过三个,分别为:RS(数据命令选择端),R/W(读写选择端),E(使能信号);以后编程便主要围绕这三个管脚展开进行初始化,写命令,写数据。
{
LCD_write_command(0x38);//设置8位格式,2行,5x7
LCD_write_command(0x0c);//整体显示,关光标,不闪烁
LCD_write_command(0x06);//设定输入方式,增量不移位
LCD_write_command(0x01);//清除屏幕显示
delay_n25us(10);//实践证明,我的LCD1602上,用for循环200次就能可靠完成清屏指令。
本次设计中主要用到PORTA,PORTB端口:
PORTA:PORTA为通用I/O口,共8个,作为通用数字I/O口使用,未集成特殊功
能.主要配置寄存器有:数据寄存器PORTA、数据方向寄存DDRA、上拉电阻控制寄存器
lcd1602指令解读及基本程序
0x1c字符全部右移一格,但光标不动
0x10光标左移1格,且AC值减1
0x14光标右移1格,且AC值加1
*/
#include <intrins.h>
#define dataport P1
sbit RS=P2^ 6;
sbit RW=P2^5;
sbit EN=P2^4;
uchar code yue[]={0x0f,0x09,0x0f,0x09,0x0f,0x09,0x0b,0x11};// "月"
uchar code ri[]={0x1f,0x11,0x11,0x1f,0x11,0x11,0x11,0x1f};// "日"
//显示汉字
displyonecharacter(0,0,0x40,nian);
displyonecharacter(1,0,0x80,yue);
displyonecharacter(1,0,0xc0,ri);
0x01清屏,光标复位到地址00H位置
0x02光标归原点,DDRAM中内容不变,地址计数器AC=0;(此时地址为0x80)
0x0F开显示,显示光标,光标闪烁
0x0e开显示,显示光标,光标不闪烁
0x0c开显示,不显示光标
0x08只开显示
0x06地址加一,当写入数据的时候光标右移
设定显示屏或光标移动方向指令
}
void writecmd(unsigned char cmd) //写命令到LCD1602
{
waitfor(); //测忙
RS=0;RW=0; //选择指令寄存器写操作
dataport=cmd; //将数据送到数据口
LCD1602帮助手册
LCD1602帮助手册正面图背面图正面图为第一图,管脚应排列在左上方,左边第一脚为管脚1,向右依次为2,3,4………15,16。
背面一般也有标注,并且附带了管脚对应的作用。
其中第三脚VO为对比度调节脚,一般外接滑动变阻器,调节输入的电压,来调节明暗度(可以直接接地,不过直接接地,需要斜着屏幕,才能看见LCD是否显示字符,正面看都是黑黑的一格一格的)。
15,16角一般为背光LED灯源,一个接VCC(一般为15脚),一个接GND(一般为16脚),最好接入限流电阻,不接也可使用,不过会缩短寿命,这两角可以不接,如果不接,在黑暗的室内,显示效果欠佳。
管脚编号如下图所示:管脚对应符号对LCD的操作,有四种操作,分别为:读状态,读数据,写指令和写数据,一般常用的为读状态,写指令和写数据。
操作图如下:当RS端为低电平,RW端为高电平,E为高电平是,对LCD1602的操作为读状态操作,这时,可以对LCD的状态进行读取,读取通过D0~D7的端口读取。
其他操作相似,对照图,即可完成,但是有个读写时序的要求,时序图见下图:读操作时序对LCD进行读操作时,先将RS置为低电平(0V),然后将RW样置为高电平(+5V),然后有个tsp1的延迟(但是一般这个延迟为ns级,一个单片机的指令周期通常都为us级,一般不需要特别延迟,如果程序有一定错误的时候,可以稍微延迟一下),然后再将E置为1,然后延迟td时间(td一般也为ns级,可以适当延迟一点点),然后读取D0~D7的数据。
写操作也是类似的,将RS,RW,E端口进行相应操作即可完成,写数据和写命令的操作,延迟的时间都很短,程序不稳定的话,可以延迟个1us,一般就可以了。
LCD1602的指令有11条,如下图:(指令表)从之前的操作来看,对照此表,不难看出,指令表的前8条都是命令指令,RS,RW都为0,所以操作时,都是写命令操作,D7~D0的数值的不同,代表了操作的不同,比如D0~D7为0x01时,对LCD的操作命令就为清屏显示,第二条指令为光标返回指令,在D0处有个※标记,这表示,不论此位的数据为1还是为0,对此命令都无效,即D0~D7端口写入0x20为光标返回指令,D0~D7端口写入0x03,此命令也为光标返回指令。
加个模块,实现IIC方式驱动LCD1602
加个模块,实现IIC驱动LCD1602 PCF8574模块使实现IIC驱动LCD1602成为现实。
下图是PCF8574模块与1602的连接电路图:实物接法如下:想要使用PCF8574模块来实现IIC驱动LCD1602,首先非常必要弄清楚IIC的时序、PCF8574设备地址、四线控制LCD1602方法。
下面是两个重要的h文件。
通过修改这两个h文件中的部分代码(接线有所不同)即可移植到你的程序中去。
PCF8574.h程序:sbit scl=P1^6;sbit sda=P1^7;void delay()//{ ;; }void init()//IIC初始化{sda=1;delay();scl=1;delay();}void start() //IIC开始信号{sda=1;delay();sda=0;delay();}void stop() //IIC停止{sda=0;delay();scl=1;delay();sda=1;delay();}void respons() //IIC应答{uchar i;scl=1;delay();while((sda==1)&&(i<250))i++;}void write_byte(uchar date)//IIC写入数据{uchar i,temp;temp=date;for(i=0;i<8;i++){temp=temp<<1;scl=0;delay();sda=CY;delay();scl=1;delay();}scl=0;delay();sda=1;uchar read_byte()//IIC读取字节{uchar i,k;scl=0;delay();sda=1;delay();for(i=0;i<8;i++){scl=1;delay();k=(k<<1)|sda;scl=0;delay();}return k;}start();write_byte(0x7e); //8574设备地址(写)respons();write_byte(date1);respons();stop();}uchar read_add()//向IO读取数据{uchar date1;start();write_byte(0x71); //8574设备地址(读)respons();date1=read_byte();respons();stop();return date1;}PCF8574+LCD1602_4.h程序:uchar a,b;for(a=x;a>0;a--)for(b=200;b>0;b--);}void write_com(uchar com) //写命令函数{ uchar com1,com2;com1=com|0x0f;write_add(com1&0xfc);delay1(2);write_add(com1&0xf8);com2=com<<4;com2=com2|0x0f;write_add(com2&0xfc);delay1(2);write_add(com2&0xf8);}void write_date(uchar date) //写数据函数{date1=date|0x0f;write_add(date1&0xfd);delay1(2);write_add(date1&0xf9);date2=date<<4;date2=date2|0x0f;write_add(date2&0xfd);delay1(2);write_add(date2&0xf9);}void init_lcd() //初始化函数{write_com(0x33); //显示模式设置delayms(6);write_com(0x32); //显示模式设置delayms(6);write_com(0x28); //4位总线,双行显示,显示5×7的点阵字符delayms(6);write_com(0x01); //清屏write_com(0x06); //字符进入模式:屏幕不动,字符后移delayms(6);write_com(0x0c); //显示开,关光标//write_LCD_Command(0x0f); //显示开,开光标,光标闪烁delayms(6);}//显示字符串:第x行第y列显示什么内容void ShowString(unsigned char x,unsigned char y,unsigned char *str){//设置起始位置if(x == 1){write_com(0x80 | y-1);// |相当于加法}if(x == 2){write_com(0xc0 | y-1);}//输出字符串while(*str!='\0') {write_date(*str);str++;}}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
LCD1602的电路图和程序————————————————————————————————作者:————————————————————————————————日期:MS基于1602字符型液晶显示器的显示系统姓名:杨越班级:电子11-1学号:110400104一、实习目的(1)了解飞思卡尔单片机的基本原理,掌握其基本的工作流程。
(2)了解LCD1602的基本原理及用法。
(3)能够熟练使用CodeWarrior软件编写C语言程序,使用BDM仿真器下载程序。
(4)能够熟练焊接电路板。
二、实验设备与器件CodeWarrior软件,BDM仿真器,万用电路板,飞思卡尔单片机,LCD1602液晶显示器,三、实验内容内容:利用飞思卡尔单片机制作基于1602字符液晶显示器的显示系统要求:用四个按键控制,按下第一个按键显示1,按下第二个按键显示2,以此类推。
(1)LCD1602液晶显示器的原理:1602共16个管脚,但是编程用到的主要管脚不过三个,分别为:RS(数据命令选择端),R/W(读写选择端),E(使能信号);以后编程便主要围绕这三个管脚展开进行初始化,写命令,写数据。
以下具体阐述这三个管脚:RS为寄存器选择,高电平选择数据寄存器,低电平选择指令寄存器。
R/W为读写选择,高电平进行读操作,低电平进行写操作。
E端为使能端,后面和时序联系在一起。
除此外,D0~D7分别为8位双向数据线。
操作时序:RS R/W 操作说明0 0 写入指令码D0~D70 1 读取输出的D0~D7状态字1 0 写入数据D0~D71 1 从D0~D7读取数据注:关于E=H脉冲——开始时初始化E为0,然后置E为1,再清0.读取状态字时,注意D7位,D7=1,禁止读写操作;D7=0,允许读写操作;所以对控制器每次进行读写操作前,必须进行读写检测。
(即后面的读忙子程序)指令集:LCD_1602 初始化指令小结:0x38 设置16*2显示,5*7点阵,8位数据接口0x01 清屏0x0F 开显示,显示光标,光标闪烁0x08 只开显示0x0e 开显示,显示光标,光标不闪烁0x0c 开显示,不显示光标0x06 地址加1,当写入数据的时候光标右移0x02 地址计数器AC=0;(此时地址为0x80)光标归原点,但是DDRAM 中断内容不变0x18 光标和显示一起向左移动(2)飞思卡尔单片机的功能及特点:MC9S12XS128是 16 位单片机,由 16 位中央处理单元(CPU12X)、128KB 程序、Flash(P-lash)、8KB RAM、8KB 数据 Flash(D-lash)组成片内存储器。
主要功能模块包括:内部存储器,内部PLL 锁相环模块,2 个异步串口通讯 SCI ,1个串行外设接口 SPI MSCAN 模块,1 个 8 通道输入/输出比较定时器模块 TIM ,周期中断定时器模块PIT ,16 通道 A/D 转换模块 ADC ,1 个 8 通道脉冲宽度调制模块 PWM ,输入/输出数字 I/O 口。
本次设计中主要用到PORTA,PORTB端口:PORTA:PORTA 为通用 I/O 口, 共 8 个,作为通用数字 I/O 口使用,未集成特殊功能.主要配置寄存器有:数据寄存器 PORTA、数据方向寄存 DDRA、上拉电阻控制寄存器PUCR 和驱动控制寄存器 RDR。
a.数据寄存器 PORTA通过写 1/0 使单片机对应引脚输出高低电平,或通过读取数据寄存器获得对应引脚的高低电平值。
例:PORTA_PB0=1b.数据方向寄存器 DDRADDRA 寄存器配置引脚为输出口还是输入口,“0”,输入口;“1”,输出口。
MCU 复位后,DDRA 值为 0x00, 引脚默认为输入口。
例:DDRA=0xFF //配置PORTA 口为输出PORTB:PORTB 为通用数字 I/O 口, 共 8 个。
其使用与 PORTA 基本一样。
主要配置寄存器有:数据寄存器 PORTB、数据方向寄存 DDRB。
上拉电阻控制寄存器 PUCR 和驱动控制寄存器 RDR 与 PORTA 、PORTB、PORTE、PORTK 共用。
a.数据寄存器 PORTBb.数据方向寄存器 DDRB四、原理图:器件说明:LCD1602 (16管脚),2个排阻,4个10k电阻,一个1K电阻,飞思卡尔芯片(64管脚)管脚连接:VSS GND DB6 PB6VCC VCC DB7 PB7VEE GND A VCCRS PA0 K GNDRW PA1 K1 PA4E PA2 K2 PA5DB0 PB0 K4 PA6DB1 PB1 K4 PA7DB2 PB2DB3 PB3 DB4 PB4 DB5PB5五、流程图否是六、程序设计1.void PLL_Init(void):内部锁相环模块,单片机使用PLL 功能能够获得更高的总线频率,这对于需要提高单片机运行速度的应用场合非常必要。
2. void LCD_init(void):初始化LCD1602液晶显示屏,3. void LCD_write_command(uchar dat):写指令4. void LCD_write_data(uchar dat):写数据5. void LCD_disp_char(uchar x,uchar y,uchar dat):显示字符6. void main(void):主函数#include <hidef.h> /* common defines and macros */#include "derivative.h" /* derivative-specific definitions */ #include "MC9S12XS128.h"unsigned char a=0; unsigned char b=0; unsigned char c=0;锁相环开初始化 写指令 写数 显示是否有unsigned char d=0;void PLL_Init(void) //PLLCLK=2*OSCCLK*(SYNR+1)/(REFDV+1){ //锁相环时钟=2*16*(2+1)/(1+1)=48MHzREFDV=1; //总线时钟=48/2=24MHzSYNR=2;while(!(CRGFLG&0x08));CLKSEL=0x80; //选定锁相环时钟}# define LCD_DB PORTB# define LCD_RS PORTA_PA0# define LCD_RW PORTA_PA1# define LCD_E PORTA_PA2void LCD_init(void);//初始化函数void LCD_write_command(uchar command);//写指令函数void LCD_write_data(uchar dat);//写数据函数void LCD_disp_char(uchar x,uchar y,uchar dat);//在某个屏幕位置上显示一个字符,X (0-16),y(1-2)//void LCD_check_busy(void);//检查忙函数。
我没用到此函数,因为通过率极低。
void delay_n25us(uint n);//延时函数//********************************//*******初始化函数***************void LCD_init(void){LCD_write_command(0x38);//设置8位格式,2行,5x7LCD_write_command(0x0c);//整体显示,关光标,不闪烁LCD_write_command(0x06);//设定输入方式,增量不移位LCD_write_command(0x01);//清除屏幕显示delay_n25us(10);//实践证明,我的LCD1602上,用for循环200次就能可靠完成清屏指令。
//LCD_write_command(0x06);//LCD_write_command(0x0c);}//********************************//********写指令函数************void LCD_write_command(uchar dat){LCD_DB=dat;delay_n25us(1);LCD_RS=0;delay_n25us(1);//指令LCD_RW=0;delay_n25us(1);//写入LCD_E=1;delay_n25us(1);//允许LCD_E=0;delay_n25us(1);//实践证明,我的LCD1602上,用for循环1次就能完成普通写指令。
}//*******************************//********写数据函数*************void LCD_write_data(uchar dat){LCD_DB=dat;delay_n25us(1);LCD_RS=1;delay_n25us(1);//数据LCD_RW=0;delay_n25us(1);//写入LCD_E=1;delay_n25us(1);//允许LCD_E=0;delay_n25us(1);delay_n25us(1);}//********************************//*******显示一个字符函数*********void LCD_disp_char(uchar x,uchar y,uchar dat){uchar address;if(y==1)address=0x80+x;elseaddress=0xc0+x;LCD_write_command(address);LCD_write_data(dat);}//********************************/*******检查忙函数*************void LCD_check_busy() //实践证明,在我的LCD1602上,检查忙指令通过率极低,以{ //至于不能正常使用LCD。
因此我没有再用检查忙函数。
而使do //用了延时的方法,延时还是非常好用的。
我试了一下,用{ LCD_E=0; //for循环作延时,普通指令只要1次循就可完成。
清屏指令LCD_RS=0; //要用200次循环便能完成。
LCD_RW=1;LCD_DB=0xff;LCD_E=1;}while(LCD_DB^7==1);}******************************///********延时函数***************void delay_n25us(uint n){ uint i=0;uchar j=0;for(i=n;i>0;i--)for(j=0;j<2;j++); //在这个延时循环函数中我只做了2次循环,} //实践证明我的LCD1602上普通的指令只需1次循环就能可靠完成。