LCD1602工作原理介绍

LCD1602液晶显示屏简介

LCD1602(Liquid Crystal Display)是一种工业字符型液晶,能够同时显示16×02即32字符(16列两行),LCD1602主要用来显示数字、字母、图形以及少量自定义字符。可以显示2行16个字符,拥有16个引脚,其中8位数据总线D0-D7,和RS、R/W、EN三个控制端口,工作电压为5V,并且带有字符对比度调节V0和背光源AK。

LCD1602工作原理介绍_第1张图片 LCD1602实物图

LCD1602主要参数
  • 显示字符:16×2个字符
  • 工作电压:4.5~5V
  • 工作电流:2.0mA
  • 工作温度:-20°C~70°C
  • 模块最佳工作电压:5.0V
  • 单个字符尺寸2.95×4.35(W×Hmm)
  • 引脚:16脚
LCD1602引脚功能

LCD1602工作原理介绍_第2张图片

引脚1(VSS/GND):地引脚

引脚2(VDD/VCC):电源引脚

引脚3(VL):液晶显示器对比度引脚,接正电源时对比度最弱,接地时对比度最高,使用时可以通过外接一个电位器调整其对比度。

引脚4(RS):寄存器选择脚,高电平时选择数据寄存器、低电平时选择指令寄存器。

引脚5(R/W):读(read)/写(write)信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或显示地址;当RS为低电平,R/W为高电平时,可以读忙信号;当RS为高电平,R/W为低电平时,可以写入数据。

引脚6(E):使能端,当E端由高电平跳变为低电平时,液晶模块执行命令。

引脚7-14(D0~D7): 8位双向数据线 用于单片机向1602写入数据和从1602读取数据

引脚15(BLA):背光源正极

引脚16(BLK):背光源负极

LCD1602引脚接线(51单片机)

虽然看到LCD1602的引脚很多,但是总体分下来其实只需要分成三个部分记忆去接线就好了。

第一部分(电源、接地):这里会分为两组,一组是VDD/GND组,主要给模块供电、另一组是BLA/BLK组,主要给背光源供电。由于VL引脚接地,也将它放在此部分记忆。

注:两组我的写法都是以接5V电源/接地的顺序写的,当然也可以按着引脚说明部分自己注意甄别。

第二部分(IO口):也就是引脚7-14(D0-D7)由于他是8位双向数据线,所以按照顺序依次接51单片机P0^0引脚-P0^7引脚

第三部分(信号线):引脚RS(数据命令选择端)、R/W(读写选择端)、E(使能信号)可以随意选择其他IO口接线,这里以我自己写的代码所定义的引脚为例(C代码):

LCD1602工作原理介绍_第3张图片

LCD1602的RAM地址

LCD1602,总共显示为16行2列,对应着32个RAM地址,在使用的时候,需要在哪个位置显示,就写入对应的RAM地址,然后再写入需要的字符,对应就会显示该字符。

下图是LCD1602的内部显示地址
一共32个地址,对应2行16列

LCD1602工作原理介绍_第4张图片

如果我要在第二行第一个位置显示字符,它的地址是 40H,那么是否直接写入 40H 就可以将光标定位在第二行第 一个字符的位置呢?

答:这样不行,因为写入显示地址时要求最高位 D7 恒定为高电平 1 所以实 际写入的数据应该是 01000000B(40H) +10000000B(80H)=11000000B(C0H)。

那要显示什么字符呢就需要结课ASCII码表

LCD1602工作原理介绍_第5张图片

如上图所示,需要写入哪个字符,就直接设置对应进制码就可以了,比如数字1,代码是0011 0001与ASCII码一致。也就是表中的ASCII码字符的地址和实际的ASCII码字符是一样的。

读时序、写时序及数序参数

以下为读时序和写时序的图以及数序参数。

读时序:

LCD1602工作原理介绍_第6张图片

写时序:

LCD1602工作原理介绍_第7张图片

 数序参数:

LCD1602工作原理介绍_第8张图片

写时序代码实现 

 首先我们先来观察写时序的图,通过时序图来确定代码

在前面引脚功能部分有提到RS引脚为寄存器选择脚,高电平(1)时为选择数据寄存器、低电平(0)时为选择指令寄存器。我们知道液晶显示模块需要先有告诉在显示屏哪个地址显示字符后,再做显示字符操作,选择指令寄存器就是告知模块指令或地址选择数据寄存器则是写入数据操作。不过要结合R/W来看。

告知模块指令或地址时的写时序中一开始需要让RS = 0,继续观察写时序图我们会发现E一开始也是低电平,R/W一开始可高可低,但是根据后续变化来看,主要实现操作的电平为低电平,所以干脆直接在写时序里全程低电平,即:

RS = 0;

R/W = 0;

EN = 0;//在定义时,将E接口命名成了EN

LCD1602工作原理介绍_第9张图片

如图,我们需要延时tsp1的时间为传输数据做准备,而后E会给到一个上升沿,这个时候指令就开始写入LCD中,此刻根据数序参数给到一定的延时后,将E置低电平。

LCD1602工作原理介绍_第10张图片

在准备传输数据阶段期间,其实已经开始将指令数据送到数据口D0~D7,所以综合以上时序的解析,代码如下:

LCD1602工作原理介绍_第11张图片

注:这个是一个自己写的函数,在主程序中调用,其中char cmd传进来的是需要显示字符的地址,check_busy();这个是读忙的函数,后续会提到,databuffer是之前定义的P0口,其中用到_nop_();做延时作用,它是一个空函数,运行它时大概需要1.085微妙,足够满足数序参数的需求。不过值得注意的是_nop_();需要加头文件#include "intrins.h"。 

 在写入数据时的写时序,只需要RS需要为高电平,其他和告知模块指令或地址时一致,代码如下:

LCD1602工作原理介绍_第12张图片

 LCD1602初始化

我们可以根据一下步骤进行书写LCD1602的初始化

LCD1602 初始化过程(8bit)

(1)延时 15ms

(2)写指令 38H(不检测忙信号)

(3)延时 5ms

(4)以后每次写指令,读/写数据操作均需要检测忙信号

(5)写指令 38H:显示模式设置

(6)写指令 08H:显示关闭

(7)写指令 01H:显示清屏

(8)写指令 06H:显示光标移动设置

(9)写指令 0CH:显示开及光标设置

LCD1602 初始化过程(4bit)

(01)延时 50ms

(02)发送 0x03(4bit)(rs=0,rw=0)

(03)延时 4.5ms

(04)发送 0x03(4bit)(rs=0,rw=0)

(05)延时 4.5ms

(06)发送 0x03(4bit)(rs=0,rw=0)

(07)延时 150μs

(08)发送 0x02(4bit)(rs=0,rw=0)

(09)写指令 28H(8bit)

(10)写指令 0CH(8bit)

(11)写指令 01H(8bit)

(12)延时 2ms(8bit)

(13)写指令 06H(8bit)

因为我操作的是8bit的情况,如下图代码实现:

LCD1602工作原理介绍_第13张图片

 LCD1602操作指令——读忙指令

LCD1602一共有11条指令,今天主要说读忙指令

1602液晶模块的读写操作,屏幕和光标的操作都是通过指令来实现的。(1为高电平,0为低电平),操作指令整理如下图:

LCD1602工作原理介绍_第14张图片

读忙指令

LCD1602工作原理介绍_第15张图片

BF:忙标志位,高电平表示忙,此时模块不能接收命令或数据,如果为低电平表示不忙 

读忙指令编码可以知道要RS=0,R/W=1,这时需要观察读时序的图来判断E的状态,如下图

LCD1602工作原理介绍_第16张图片

依旧是我们需要延时tsp1的时间,并等待E提供一个上升沿,并延时一段时间,只是在读数据时是在E=1之后,所以获取数据的位置需要改变,其他E的状态变化和写时序没太大区别,代码如下

LCD1602工作原理介绍_第17张图片

这时我们需要做一个循环判断,来确定指令是不是处于忙状态,前面有提到当BF = 1时为忙状态,而它位于DB7口,其他IO口无所谓,所以可以定义一个tmp=0x80,databuffer=0x80,这样如上图所示,用databuffer给tmp赋值,当databuffer的P0^7口为0或1时,做while(tmp & 0x80)的判断。完整代码如下:

LCD1602工作原理介绍_第18张图片

 这时,我想要输出一个字符'C'的话,主函数如下写即可。

LCD1602工作原理介绍_第19张图片

当然,如果想输出一个字符串需要再做一个函数,如下图:

LCD1602工作原理介绍_第20张图片

注:其中row和col做的是在LCD1602的第几行显示的判断,row利用switch做判断,col做逻辑选择。这里解析一下0x80+col和0x80+0x40+col的操作为什么可以确定是第几行,0x80在前面已经有聊到过为什么需要加,写入显示地址时要求最高位 D7 恒定为高电平 1 。而第一行的第一个地址是00,也就是0x00,换算为十进制为0,而第二行地址为40,即0x40,换算为十进制则是64,但是由于不太美观且和上面不一致,不如写成0x80+0x40+0这样,就可以以形参的形式传递,具有比较好的观感。最后一个则是传递字符串的。

OK,今天的介绍就到这里吧,以下为完整代码

完整代码

#include "reg52.h"
#include "intrins.h"
/*
RS  -- P1.0
RW  -- P1.1 
E   -- P1.4 */
#define databuffer  P0 //定义8位数据线,Po端口组
sbit RS = P1^0;
sbit RW = P1^1;
sbit EN = P1^4;

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;
	_nop_();
	EN = 1;
	_nop_();
	_nop_();
	EN = 0;
	_nop_();	
}

void Write_Data_Func(char dataShow)
{
	check_busy();
	RS = 1;
	RW = 0;
	
	EN = 0;
	_nop_();
	databuffer = dataShow;
	_nop_();
	EN = 1;
	_nop_();
	_nop_();
	EN = 0;
	_nop_();	
}

void Delay15ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 27;
	j = 226;
	do
	{
		while (--j);
	} while (--i);
}
void Delay5ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 9;
	j = 244;
	do
	{
		while (--j);
	} while (--i);
}


void LCD1602_INIT()
{
	//(1)延时 15ms
	Delay15ms();
//(2)写指令 38H(不检测忙信号) 
	Write_Cmd_Func(0x38);
//(3)延时 5ms
	Delay5ms();
//(4)以后每次写指令,读/写数据操作均需要检测忙信号
//(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);
				while(*string){
					Write_Data_Func(*string);
					string++;
				}
				break;
		
		case 2:
				Write_Cmd_Func(0x80+0x40+col);
				while(*string){
					Write_Data_Func(*string);
					string++;
				}
				break;
	
	}
}

void main()
{
	char position = 0x80 + 0x05;
	//char dataShow = 'C';
	LCD1602_INIT();
	LCD1602_showLine(1,5,"NO.1");
	LCD1602_showLine(2,0,"clc handsome");

}

你可能感兴趣的:(嵌入式硬件,51单片机)