赞
踩
前言,LCD1602是一个比较常用的单片机显示外设,下面我们从它的显示原理,来分析用51单片机编程的思路。另外结尾还提供了完成的程序代码参考。
一、LCD1602的外观、结构和基本参数
引脚功能解析:
第1引脚:GND为电源地脚。
第2引脚:VCC接5V电源正极。
第3引脚:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高。
第4引脚:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。
第5引脚:RW为读写信号线,高电平(1)时进行读操作,低电平(0)时进行写操作。
第6引脚:E(或EN)端为使能(enable)端,高电平(1)时读取信息,负跳变时执行指令。
第7~14引脚:D0~D7为8位双向数据端。
第15~16脚:空脚或背灯电源。第15引脚背光正极,第16引脚背光负极。
二、电路接线图
RD(也就是RS)\RW\E接口分别接单片机的1.1、1.2、1.3位。LCD0~7接P0刚好八个。
三、LCD1602的显示原理分析
LCD1602之所以是1602是因为它能够显示16(列)*2(行)个字符,如下图所示:
其实LCD1602编程显示的原理并不是很难,简单来说就是要做好两步。
第一步就是要找出我们显示字符的位置
比如我们想把字符显示在上图的第一行的第九个位置,那么就可以选定08。08换算成二进制就是0000 1000。
但是还有个需要注意的地方就是,如果是要写入显示的地址信息的时候,D7是要求为高电平的。那么08就要变成10001000。就是88(0x88)。
第二步发送要显示的字符,1602的参考手册给出了查询字符的表格。如下:
如图上所示,如果我们想发送一个D,那么我们只要找出来0100 0100,转换成16进制的就是0x44, 刚好对应Ascll码68。实际上我们输入的时候输入字符就可以了。编译器会自动转换成对应的Ascll码的。
这两个步骤,一个是传输地址,一个是传输字符。那么怎么去区分呢。通过RS引脚来做区分,RS为高电平1时选择数据寄存器(写数据)、低电平0时选择指令寄存器(写地址)。
四、LCD1602时序分析
①写操作的时序分析
RS:地址命令和数据的选择,写地址命令为0,写数据为1。
R/W:读和写的选择,0是写,1是读。可以从上图的时序可以看出来R/W贯穿了整个时序,因此我们将R/W置0即可。
E:初始状态为0,
然后延时至少tR之后置1(tR的值参考上表,25ns执行一个_nop_()函数就可以满足),
置1后要延时至少tPW(上图给出的tPW值为150ns,建议执行两个_nop_()函数),
接着再至少延时tF(执行一个_nop_()函数)后置0。
参考程序如下:
void Write_Cmd(unsigned char cmd)
{
Busy_Check();
Lcd_Rs=0;//写“地址命令标志”
Lcd_Rw=0;
Lcd_En=0;
_nop(); //执行一个空函数,延时月1us
P0=cmd;
Lcd_En=1;
_nop();
_nop();
Lcd_En=0;
_nop();
}
void Write_Dat(unsigned char dat)
{
Busy_Check();
Lcd_Rs=1;//写“ 数据”标志
Lcd_Rw=0;
Lcd_En=0;
_nop(); //执行一个空函数,延时月1us
P0=dat;
Lcd_En=1;
_nop();
_nop();
Lcd_En=0;
_nop();
}
读操作的时序和写操作的时序有点区别。读操作时序与写操作时序的区别在于:写操作时序在E=0的时候就开始传输数据,而读操作时序要等E=1之后才开始传输数据。
②读操作的时序分析
RS:因为是写入命令,所以这里是0。
RW:读标志,置1。
E:初始状态为0,延时tR后拉高,之后再延时tPW后拉低。
参考程序:
void Busy_Check(void) //判断是否忙碌的函数。
{
P0=0xFF;
do
{
Lcd_Rs=0;
Lcd_Rw=1;
Lcd_En=0;
_nop();
Lcd_En=1;
_nop();
_nop();
} while(Lcd_Busy==1) ;
Lcd_En=0;
_nop();
}
五、LCD1602的初始化
查看手册的时候可以看到初始化的说明
这里我们做了程序的简化:
void Lcd1602_Init(void)
{
Write_Cmd(0x38);
Write_Cmd(0x0C);
Write_Cmd(0x06);
Write_Cmd(0x01);
}
完整代码:
一、LCD1602 显示一个字符,参考程序
#include <reg52.h>
sbit Lcd_Rs=P1^2;// 通过位操作把LCD的命令、使能、数据引脚等跟单片机的对应IO定义好。
sbit Lcd_Rw=P1^3;
sbit Lcd_En=P1^4;
sbit Lcd_Busy=P0^7; //这个是LCD的忙碌标志,通过获取这个引脚的电平就可以判断LCD是否在忙碌,
void Busy_Check(void) //判断是否忙碌的函数。
{
P0=0xFF;
do
{
Lcd_Rs=0;
Lcd_Rw=1;
Lcd_En=0;
_nop();
Lcd_En=1;
_nop();
_nop();
} while(Lcd_Busy==1) ;
Lcd_En=0;
_nop();
}
void Write_Cmd(unsigned char cmd)
{
Busy_Check();
Lcd_Rs=0;//写“地址命令标志”
Lcd_Rw=0;
Lcd_En=0;
_nop(); //执行一个空函数,延时月1us
P0=cmd;
Lcd_En=1;
_nop();
_nop();
Lcd_En=0;
_nop();
}
void Write_Dat(unsigned char dat)
{
Busy_Check();
Lcd_Rs=1;//写“ 数据”标志
Lcd_Rw=0;
Lcd_En=0;
_nop(); //执行一个空函数,延时月1us
P0=dat;
Lcd_En=1;
_nop();
_nop();
Lcd_En=0;
_nop();
}
void Lcd1602_Init(void)
{
Write_Cmd(0x38);
Write_Cmd(0x0C);
Write_Cmd(0x06);
Write_Cmd(0x01);
}
void main(void)
{
Lcd1602_Init();
Write_Cmd(0x80+0x08);// 发送命令,规定显示的位置。
Write_Dat('x') ;// 发送显示的数据。
while(1);
}
显示效果如下:
二、LCD1602显示字符串,参考程序
#include <reg52.h>
#include <intrins.h>
sbit Lcd_Rs=P1^2;// 通过位操作把LCD的命令、使能、数据引脚等跟单片机的对应IO定义好。
sbit Lcd_Rw=P1^3;
sbit Lcd_En=P1^4;
sbit Lcd_Busy=P0^7; //这个是LCD的忙碌标志,通过获取这个引脚的电平就可以判断LCD是否在忙碌,
unsigned char code str1[]={"12345678"};
unsigned char code str2[]={"zhongguojiayou"};
void Busy_Check(void) //判断是否忙碌的函数。
{
P0=0xFF;
do
{
Lcd_Rs=0;
Lcd_Rw=1;
Lcd_En=0;
_nop();
Lcd_En=1;
_nop();
_nop();
} while(Lcd_Busy==1) ;
Lcd_En=0;
_nop();
}
void Write_Cmd(unsigned char cmd)
{
Busy_Check();
Lcd_Rs=0;//写“地址命令标志”
Lcd_Rw=0;
Lcd_En=0;
_nop(); //执行一个空函数,延时月1us
P0=cmd;
Lcd_En=1;
_nop();
_nop();
Lcd_En=0;
_nop();
}
void Write_Dat(unsigned char dat)
{
Busy_Check();
Lcd_Rs=1;//写“ 数据”标志
Lcd_Rw=0;
Lcd_En=0;
_nop(); //执行一个空函数,延时月1us
P0=dat;
Lcd_En=1;
_nop();
_nop();
Lcd_En=0;
_nop();
}
void Write_String(unsigned char addr_sta,unsigned char *p)
{
Write_Cmd(addr_sta) ;
while(*p!='\0')
{
Write_Dat(*p++);
}
}
void Lcd1602_Init(void)
{
Write_Cmd(0x38);
Write_Cmd(0x0C);
Write_Cmd(0x06);
Write_Cmd(0x01);
}
void main(void)
{
Lcd1602_Init();
Write_String(0x80,str1);// 发送字符串1的位置和数据。
Write_String(0xC0,str2);// 发送字符串2的位置和数据。
while(1);
}
显示效果如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。