目录
1.接线说明
2.LCD1602显示原理
3.LCD1602时序分析
4.LCD1602显示一个字符
5.LCD1602显示一行
第1引脚:GND为电源地
第2引脚:VCC接5V电源正极
第3引脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高(对比度过高时会 产生“鬼影”,使用时可以通过一个10K的电位器调整对比度)。
第4引脚:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。
第5引脚:RW为读写信号线,高电平(1)时进行读操作,以51为例的简单原理图低电平(0)时进行写操作。
第6引脚:E(或EN)端为使能(enable)端,高电平(1)时读取信息,负跳变时执行指令。
第7~14引脚:D0~D7为8位双向数据端。第15~16脚:空脚或背灯电源。第15引脚背光正极,第16引脚背光负极。
开发板接线图:
要想搞懂1602如何显示,就只需搞懂两个问题(在哪显示,如何显示)。
首先来说一下在哪显示这个问题:
LCD1602可以显示16*2个字符且通过D0-D7八个引脚传输数据八位数据,每一个显示的位置都对应上图的一个地址。例如我想在第一行的第三个位置显示,那么就可以锁定上表中的“02”,换算成二进制就是0000 0010。听上去很简单,但是LCD1602有个特点就是写入显示地址时要求最高位 D7 恒定为高电平。所以我们想显示真实的地址应该为1000 0010。
在哪显示说清楚了,现在来搞怎么显示这个问题:
在LCD1602的手册中给出了这样一个表格,我们想显示表格中的字符只需获取某个字符的高位和低位即可。例如我想显示“B”这个字符,就是0100 0010转换成16进制就是0x42,刚好对应‘B’的ASCLL码66。当然我们在编程的时候无需这样操作,只需输入字符即可,编译器会自动编译成对应的ASCLL码。
说到这里会发现无论是传输地址的指令还是传输字符的指令都是通过D0-D7这八根线进行传输,那么我们什么时候传输的数据,说明时候传输的是地址呢。我们靠的是在1602上的RS引脚,RS为高电平1时选择数据寄存器(写数据)、低电平0时选择指令寄存器(写地址)。
LCD1602的时序分为读操作时序和写操作时序,我们先分析一下最重要的写操作时序。我们无论是写入数据还是写入地址都必须要执行写操作,因此我们在编程是最好封装两个函数(写地址函数,写数据函数)。
写时序分析
首先看RS,RS的时序分析非常简单就正如上文所说我们只需搞清楚到底是是写地址还是写数据 ,写地址为0,写数据为1即可,没有太多好分析的。
R/W:可以从途中看出来R/W的时序低电平贯穿了整个时序,因此我们将R/W置0即可。
E:初始状态为0,然后延时至少tR之后置1(tR的值参考上表,25ns执行一个_nop_();函数即可),置1后要延时至少tPW(上图给出的tPW值为150ns,建议执行两个_nop_();函数),接着再至少延时tF(执行一个_nop_();函数)后置0。
代码如下(基于51单片机),其它单片机此原理都可适用。
#include "reg52.h"
#include "intrins.h"
#include "delay.h"
#define databuffer P0 //定义D0-D7引脚
sbit EN = P2^7;
sbit RS = P2^6;
sbit RW = P2^5;
void Write_cmd_Func(char cmd) //写命令函数
{
check_busy(); //检测忙信号函数
RS = 0; //RS为低电平:写指令
RW = 0;
EN = 0;
_nop_(); //执行一个空函数,延时约1us
databuffer = cmd;
_nop_();
EN = 1;
_nop_();
_nop_();
EN = 0;
_nop_();
}
void Write_data_Func(char datashow) //写命令函数
{
check_busy(); //检测忙信号函数
RS = 1; //RS为高电平:写内容
RW = 0;
EN = 0;
_nop_();
databuffer = datashow;
_nop_();
EN = 1;
_nop_();
_nop_();
EN = 0;
_nop_();
}
读操作时序:
读操作时序主要应用在检测忙信号,忙信号也在手册初始化中使用到,下文会提到。所以我们分析读操作时序的目的也就是为了写检测忙信号函数。
RS:置0,写命令
RW:高电平贯穿整个时序,因此置1。
E:初始状态为0,延时tR后拉高,之后再延时tPW后拉低。
读操作时序与写操作时序的区别在于:写操作时序在E=0的时候就开始传输数据,而读操作时序要等E=1之后才开始传输数据。
代码如下:
void check_busy()//检测忙信号函数
{
char tmp = 0x80; //创建一个变量,存放数据
databuffer=0x80; //初始值为忙,只要当单片机发数据后高位变低后才为不忙
while(tmp & 0x80){ //检测tmp的高位bf的值是否为高电平,如果为忙程序卡住不往下执行
//高电平:忙 低电平:不忙
RS = 0;
RW = 1;
EN = 0;
_nop_();
EN = 1;
_nop_();
_nop_();
tmp=databuffer;
EN = 0;
_nop_();
}
}
LCD1602初始化:
当然这里还需注意LCD1602的手册给出了使用前还需将LCD1602初始化,具体初始化内容如下,我们只需调用我们刚刚封装好的写命令函数一步一步执行手册所给的内容即可。
(1)延时 15ms
(2)写指令 38H(不检测忙信号)
(3)延时 5ms
(4)以后每次写指令,读/写数据操作均需要检测忙信号
(5)写指令 38H:显示模式设置
(6)写指令 08H:显示关闭
(7)写指令 01H:显示清屏
(8)写指令 06H:显示光标移动设置
(9)写指令 0CH:显示开及光标设置
void LCD1602_Init() //LCD1602初始化
{
Delay15ms();
Write_cmd_Func(0x38);
Delay5ms();
Write_cmd_Func(0x38);
Write_cmd_Func(0x08);
Write_cmd_Func(0x01);
Write_cmd_Func(0x06);
Write_cmd_Func(0x0c);
}
我们上面已经把写命令函数,写数据函数,初始化函数等都已经写完了,现在就可以在main函数里面操作让我们的LCD1602显示一个字符了。
代码如下:
void main()
{
char position = 0x80 + 0x08; //定义显示的位置
char datashow = 'E' //定义显示的字符
LCD1602_Init();
Write_cmd_Func(position);
Write_data_Func(datashow);
}
效果如下:
想要显示一行我们只需基于上面的内容封装一个函数即可。
代码如下:
void LCD1602_ShowLine(char row,char col,char *string) //row:行 col:列 *string:显示内容
{
switch(row){
case 1:
Write_cmd_Func(0x80+col);
while(*string){
Write_data_Func(*string);
string++;
}
break;
case 2:
Write_cmd_Func(0x80+0x40+col);
while(*string){
Write_data_Func(*string);
string++;
}
break;
}
}
效果如下:
有关LCD1602的内容就分享完了,欢迎广大嵌入式爱好者交流!