一、概述
LCD1602(Liquid Crystal Display)是一种工业字符型液晶,能够同时显示 16×02 即 32 字符(16列两 行)
引脚说明
第 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 脚:背光源负极。
/ / 和 上 官 一 号 的 接 线
/ / 电 源 V S S - - G N D V D D - - 5 V
/ / 对 比 度 V O - - G N D
/ / 控 制 线 R S - - P 1 . 0 R W - - P 1 . 1 E - - P 1 . 4
/ / 背 光 灯 A - - 5 V K - - G D N
/ / 数 据 D 0 到 D 7 - - P 0 . 到 P 0 . 7
二、开发逻辑
LCD1602=16行*2列
搞清楚,在哪显示?显示什么?
1、在哪显示?
比如N是在05这个位置上,化成二进制就是0000 0101,但是LCD1602要求写入显示地址时要求最高位 D7 恒定为高电平 1 ,所以就变成了1000 0101 = 0X85H。
比如c是在40这个位置上,化成二进制就是0100 0000,但是要求写入显示地址时要求最高位 D7 恒定为高电平 1 ,所以就变成了1100 0000 = 0XC0H。
2、显示什么?
比如a (0110 0001) =0X61 = 97,实际上就是ACILL值
而对于单片机来讲,我发送的地址和数据都是8bit的,怎么区分呢?
比如a,地址是 1110 0001,数据是 0110 0001,在LCD区分我发送的是地址还是数据的时候,需要用到RS寄存器,高电平时选择数据寄存器、低电平时选择指令寄存器。
三、时序
LCD1602 的基本的操作分为读操作和写操作。
其中读操作可以分为读状态和读数据;写操作可以分为写指令和写数据。
读状态:输入 RS=0、RW=1、E=1;输出:D0~7 读出为状态字;
读数据:输入 RS=1、RW=1、E=1;输出:D0~7 读出为数据;
写指令:输入 RS=0、RW=0、E=上升沿;写入控制指令;
写数据:输入 RS=1、RW=0、E=上升沿;写入需要显示的字符。
读操作时序
写操作时序
我们以写操作为例,分析一下时序图。
当我们要写指令的时候,RS 置为低电平,RW 置为低电平,E 置为低电平,然后将指令数据送到数据口 D0~D7,延时 tsp1,让 LCD1602 准备接收数据,这时候将 E 拉高,产生一个上升沿,这时候指令就开始写入 LCD1602,延时一段时间,将 E 置为低电平。
当我们要写数据的时候,RS 置为高电平,RW 置为低电平,E 置为低电平,然后将指令数据送到数据口 D0~D7,延时 tsp1,让 LCD1602 准备接收数据,这时候将 E 拉高,产生一个上升沿,这时候数据就开始写入 LCD1602,延时一段时间,将 E 置为低电平。
对比一下可以发现,写指令和写数据在时序上只是 RS 的不同,写指令 RS=0,写数据 RS=1。
数序参数
四、显示一个字符C
代码如下:
#include "reg52.h"
#include "intrins.h"
#define databuffer P0 //定义8位数据线,P0端口组
sbit RS = P1^0;
sbit RW = P1^1;
sbit EN = P1^4;
void Delay15ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 1;
j = 162;
k = 89;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay5ms() //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
void check_busy()//检测忙信号
{
char tmp = 0x80;
databuffer = 0x80;
while(tmp & 0x80){//1000 0000
RS = 0;
RW = 1;
EN = 0;
_nop_();
EN = 1;
_nop_();
_nop_();
tmp = databuffer;
EN = 0;
_nop_();
}
}
void Write_Cmd_Func(char cmd)//写入指令/地址函数
{
check_busy();
RS = 0;
RW = 0;
EN = 0;
_nop_();
databuffer = cmd;//一个字节一个字节的传输
EN = 1;
_nop_();
_nop_();
EN = 0;
_nop_();
}
void Write_Data_Func(char dataShow)//写入数据函数
{
check_busy();
RS = 1;
RW = 0;
EN = 0;
_nop_();
databuffer = dataShow;//一个字节一个字节的传输
EN = 1;
_nop_();
_nop_();
EN = 0;
_nop_();
}
void LCD1602_INIT(){
//(1)延时 15ms
Delay15ms();
//(2)写指令 38H(不检测忙信号)
Write_Cmd_Func(0X38);
//(3)延时 5ms
Delay5ms();
//(4)以后每次写指令,读/写数据操作均需要检测忙信号
check_busy();
//(5)写指令 38H:显示模式设置
Write_Cmd_Func(0X38);
//(6)写指令 08H:显示关闭
Write_Cmd_Func(0X08);
//(7)写指令 01H:显示清屏
Write_Cmd_Func(0X01);
//(8)写指令 06H:显示光标移动设置
Write_Cmd_Func(0X06);
//(9)写指令 0CH:显示开及光标设置
Write_Cmd_Func(0X0C);
}
void main()
{
char position = 0X80 + 0X05;//地址
char dataShow = 'C';//数据
LCD1602_INIT();
Write_Cmd_Func(position);//选择要显示的地址
Write_Data_Func(dataShow);//选择要显示的数据
}
五、显示字符串
代码如下:
#include "reg52.h"
#include "intrins.h"
#define databuffer P0 //定义8位数据线,P0端口组
sbit RS = P1^0;
sbit RW = P1^1;
sbit EN = P1^4;
void Delay15ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 1;
j = 162;
k = 89;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay5ms() //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
void check_busy()//检测忙信号
{
char tmp = 0x80;
databuffer = 0x80;
while(tmp & 0x80){//1000 0000
RS = 0;
RW = 1;
EN = 0;
_nop_();
EN = 1;
_nop_();
_nop_();
tmp = databuffer;
EN = 0;
_nop_();
}
}
void Write_Cmd_Func(char cmd)//写入地址函数
{
check_busy();//每次输入指令前都要判断液晶模块是否处于忙的状态
RS = 0;
RW = 0;
EN = 0;
_nop_();
databuffer = cmd;//一个字节一个字节的传输
EN = 1;
_nop_();
_nop_();
EN = 0;
_nop_();
}
void Write_Data_Func(char dataShow)//写入数据函数
{
check_busy();//每次输入指令前都要判断液晶模块是否处于忙的状态
RS = 1;
RW = 0;
EN = 0;
_nop_();
databuffer = dataShow;//一个字节一个字节的传输
EN = 1;
_nop_();
_nop_();
EN = 0;
_nop_();
}
void LCD1602_INIT(){
//(1)延时 15ms
Delay15ms();
//(2)写指令 38H(不检测忙信号)
Write_Cmd_Func(0X38);
//(3)延时 5ms
Delay5ms();
//(4)以后每次写指令,读/写数据操作均需要检测忙信号
check_busy();
//(5)写指令 38H:显示模式设置
Write_Cmd_Func(0X38);
//(6)写指令 08H:显示关闭
Write_Cmd_Func(0X08);
//(7)写指令 01H:显示清屏
Write_Cmd_Func(0X01);
//(8)写指令 06H:显示光标移动设置
Write_Cmd_Func(0X06);
//(9)写指令 0CH:显示开及光标设置
Write_Cmd_Func(0X0C);
}
void LCD1602_showLine(char row,char col,char *string){//行、列、字符串
switch(row){
case 1:
Write_Cmd_Func(0x80+col);//最高位是1,第一行
while(*string){
Write_Data_Func(*string);
string++;
}
break;
case 2:
Write_Cmd_Func(0x80+0x40+col);//最高位是1,第二行
while(*string){
Write_Data_Func(*string);
string++;
}
break;
}
}
void main()
{
char position = 0X80 + 0X05;//地址
//char dataShow = 'C';//数据
LCD1602_INIT();
LCD1602_showLine(1,5,"I LOVE YOU");
LCD1602_showLine(2,0,"HuangJingYuan");
}