当前位置:   article > 正文

LCD1602的学习与理解_lcd1602函数

lcd1602函数

LCD1602的学习与理解


# 前言

看过很多博主的文章,很多都讲得不是很清楚,很可能的原因就是,这些博主在写文章的时候,认为你有一定的基础认知了,才来看的。其实,大部分来找资料的不是小白就是没怎么学明白,脑袋一团浆糊才来找资料的人,结果,看了一些博主的文章,不但没看明白,反而脑袋里又多了一段浆糊。


下面我就自己的学习,整理了一下,该怎么去学习和理解LCD1602。

一、LCD1602知识体系的结构

先看一张我画的整个LCD1602知识体系的结构图

在这里插入图片描述
从这个图中,我就来一点一点的讲解吧,把这个图的每一部分了解清楚,这个模块也就理解清楚了。

  1. LCD1602,由两部分组成,分别是液晶显示屏,和HD44780芯片。液晶显示屏有2行,每行显示16个字符。HD44780芯片里面的东西就多了,上面图上的右半部分都是HD44780芯片的东西。

  2. 显示数据随机存储器 (Display Data RAM,简称DDRAM)

    DDRAM就是显示数据RAM,用来寄存待显示的字符代码。共80个字节,其地址和屏幕的对应关系如下表:
    在这里插入图片描述
    也就是说想要在LCD1602屏幕的第一行第一列显示一个"A"字,就要向DDRAM的00H地址写入“A”字的代码就行了。但具体的写入是要按LCD模块的指令格式来进行的,后面我会说到的。那么一行可有40个地址呀?是的,在1602中我们就用前16个就行了。第二行也一样用前16个地址。对应如下:
    DDRAM 地址与显示位置的对应关系
    在这里插入图片描述
    那么,每行40个字节,显示却只用了前面的16个,剩下的干嘛去了呢?剩下的那些是为了方便滚屏使用,具体操作也是可以通过指令来设置的。

  3. 字符生成只读存储器(Character Generator ROM,简称CGROM)

    我们知道文本文件中每一个字符都是用一个字节的代码记录的。一个汉字是用两个字节的代码记录。在 PC 上我们只要打开文本文件就能在屏幕上看到对应的字符是因为在操作系统里和 BIOS 里都固化有字符字模。什么是字模?就代表了是在点阵屏幕上点亮和熄灭的信息数据,例如“A”。CGROM中就存储着HD44780已经定义好的字符字模。
    在这里插入图片描述
    上面这个就是HD44780里面的字符字模表,每个格子都有一个地址,比如“A”的地址是0100 0001,也就是41H,可以理解成41H这个地址里存放的是‘“A”的字模(也可以理解成字符编码,因为左边的这些字母数字基本上都是ASCII编码)。
    在这里插入图片描述

  4. 字符生成随机存储器(Character Generator RAM,简称CGRAM)
    CGRAM用于编写CGROM中没有的字符,它的存储空间大小为64字节,在上面CGROM中可以看到,最左边有一列00H-0FH地址编码是供CGRAM使用的区域,标着有16个房间,实际上只有8个房间的地址编号可以使用(第8-16个房间地址与0-7房间地址等效)。如果自定义的是58的字符,那么一个字符需要8个字节来定义,最多就只能定义8个自定义字符,如果是定义510的字符,一个字符需要16字节,最多只能定义4个字符。注意,自定义的字符是存储在CGROM中,上表就有CGRAM自定义的字符的地址编码(可以理解成CGRAM是CGROM的一部分),CGRAM的64字节空间是用于存储自定义字符的,并不是地址编码,地址编码在CGROM中,这一点要搞清楚。

  5. 地址计数器(Address Counter,简称 AC)
    存储DDRAM的地址信息,也可以存储CGRAM的地址信息,在显示时,通过指令设置AC,让光标指向相应位置。

  6. 11个指令操作
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    通过这11个指令可以看出,有些位是固定的,在写初始化程序的时候,只需要去找相应的控制指令,然后设置对应的位填入就行了。

二、初始化程序

先附上硬件电路图
在这里插入图片描述
在这里插入图片描述

通过LCD1602的的结构图,可以看出,指令的读写通过引脚E RW RS三个引脚控制,数据传输通过D0-D7。
E:使能控制,读写指令数据必须打开这个开关
RS:指令或数据,低电平是指令,高电平是数据
RW:读写控制,高电平是读,低电平是写

这两个引脚自由组合有四种可能

  1. 读指令:RS=0,RW=1;
  2. 读数据:RS=1,RW=1;
  3. 写指令:RS=0,RW=0;
  4. 写数据:RS=1,RW=0;

还有一点比较重要的就是,时序图!!!
无论是读写数据或是指令,都跟时序图有关,要看懂这个时序图,才能真正理解程序是怎样读写数据指令的。
在这里插入图片描述
在这里插入图片描述
下面以一个写命令的初始化函数为例

void Lcd_WriteCom(uchar com)  //1602写命令函数
{ 
	P0=com;  //把命令字送入P2
	en=0; 
	rs=0;            //选择指令寄存器
    rw=0;            //选择写
    _nop_();//一个机械周期       
    en=1;           //使能线电平变化,命令送入1602的8位数据口 
    delay(1);
	en=0; 
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

看着时序图的写部分,再结合代码,来分析一下:
时序图,只用看中间的部分
E控制着整个写的过程,只有E拉高之后,指令才会写进去。

  1. 图中可以看到RS RW D0-D7的电平变化都在E的变化之前,所以,在写程序的时候,可以首先把数据怼上去,然后最后一个时序D0-D7就不用管了,只需要等待E电平拉高就行了。
  2. 接下来是设置RS RW E变成相应的电平,写指令的话,RS=0,RW=0,E先变为低电平,然后从时序图中可以看到,操作了RW,RS之后,要等待一个时间tsp1之后才能拉高使能端E的电平,从表中可以查到tsp1最小时间是30ns,这个时间很小,对于51单片机来说,不需要延时,因为51单片机的晶振差不多都是12MHz左右的,一条指令的时间在1us左右,远大于30ns,但对于运行速度较快的单片机,必须延时!!!
  3. 然后拉高E的电平,持续tpw的时间,对于51单片机来说,还是不用延时,但是为了代码规范,我还是加了延时的(E的高电平持续时间要比表格中的时间长就ok),然后拉低E的电平,表示这条指令写进了HD44780芯片当中了。

如果作为小白的你,不太明白着几句话,我建议你结合我给的示例代码和时序图,反复理解一下。

写数据的操作也这个是一样的,我会在文末给出初始化的代码。

下面在说一下忙检函数,主要是用于检测1602当前是否正在进行指令操作
在这里插入图片描述


void Busy(void)
{
	uchar temp=0;
	do
	{
		rw=1;
		rs=0;
		en=0;
		_nop_();
		en=1;
		delay(1);
		en=0;
		temp=P0;
	}while(temp&0x80);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

忙检函数,实际上就是读操作,像我刚才叙述的写操作一样,代码写的顺序也是根据时序图来的,只是和写操作不一样的是,数据D0-D7是在E电平拉高后产生变化的,所以在初始化程序中,就不用管数据的变化,直接设置RW RS E 就行了,最后,说明一点,当E由高电平变为低电平后,数据就已经读取到P0口了,然后再把数据赋值给temp,检测最高位BF(忙标志位)的状态。
补充一下,BF这个位是由硬件决定的,只能读,不能通过软件写。

最后是,LCD1602的初始化函数

void lcd_init()              //1602初始化函数       
{ 
	delay(1);
    Lcd_WriteCom(0x38);       //8位数据,双列,5*7字形       
    Busy();
	Lcd_WriteCom(0x0c);      //开启显示屏,关光标,光标不闪烁 
    Busy();
	Lcd_WriteCom(0x06);    //显示地址递增,即写一个数据后,显示位置右移一位 
    Busy();
	Lcd_WriteCom(0x01);    //清屏 
	Busy();
	Lcd_WriteCom(0x80);   //设置数据指针起点
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

关于里面的数据,0x38,0x0c啥的,这时候就要去看前面的11个指令设置了,对应去找,这些数据怎么来的,相信你也一下子就理解了。

把我写的这些都读懂了,那么我相信你对1602的使用已经有了一个大致的了解了,如果还有什么不懂的,还是看1602的数据手册吧,这篇文章看完,你也应该能看懂数据手册了,细节方面,还是去数据手册里面在找找吧。

最后,附上一个简单的初始化代码
LCD1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__
#include<reg52.h>    //包含头文件
#include"intrins.h"
#define uint unsigned int  //预定义
#define uchar unsigned char 

void delay(uint n);
void Busy(void);
void Lcd_WriteCom(uchar com);
void Lcd_WriteData(uchar dat);
void lcd_init();
#endif

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

LCD1602.c

#include"lcd1602.h"

sbit rs=P2^6;    //1602的数据/指令选择控制线 
sbit rw=P2^5;        //1602的读写控制线 
sbit en=P2^7;        //1602的使能控制线

void delay(uint n)       //延时函数                       
{ 
    uint x,y;  
    for(x=n;x>0;x--) 
        for(y=110;y>0;y--); 
} 

void Busy(void)
{
	uchar temp=0;
	do
	{
		rw=1;
		rs=0;
		en=0;
		_nop_();
		en=1;
		delay(1);
		en=0;
		temp=P0;
	}while(temp&0x80);
}

void Lcd_WriteCom(uchar com)  //1602写命令函数
{ 
	P0=com;  //把命令字送入P2
	en=0; 
	rs=0;            //选择指令寄存器
    rw=0;            //选择写
    _nop_();//一个机械周期       
    en=1;           //使能线电平变化,命令送入1602的8位数据口 
    delay(1);
	en=0; 
} 

void Lcd_WriteData(uchar dat)        //1602写数据函数       
{ 
    P0=dat;        //把要显示的数据送入P0
	en=0; 
	rs=1;        //选择数据寄存器 
    rw=0;        //选择写 
    _nop_();//一个机械周期   
    en=1;        //使能线电平变化,数据送入1602的8位数据口 
	delay(1);
	en=0; 
} 

void lcd_init()              //1602初始化函数       
{ 
	delay(1);
    Lcd_WriteCom(0x38);       //8位数据,双列,5*7字形       
    Busy();
	Lcd_WriteCom(0x0c);      //开启显示屏,关光标,光标不闪烁 
    Busy();
	Lcd_WriteCom(0x06);    //显示地址递增,即写一个数据后,显示位置右移一位 
    Busy();
	Lcd_WriteCom(0x01);    //清屏 
	Busy();
	Lcd_WriteCom(0x80);   //设置数据指针起点
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

main.c


#include"lcd1602.h"

/*P0口接1602的D0~D7*/ 
uchar code table[]="ni hao";             //要显示的内容放入数组table

void main()            //主函数 
{     
    uchar m=0; 
    lcd_init();       //液晶初始化 
    Lcd_WriteCom(0x80);   //显示地址设为80H(即00H,)上排第一位       
    for(m=0;m<6;m++)     //将table[]中的数据依次写入1602显示 
    { 
            Lcd_WriteData(table[m]);           
            delay(200); 
    } 
    while(1);        //动态停机 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

下次再写自定义字符,和动态显示的相关文章吧。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/501845
推荐阅读
相关标签
  

闽ICP备14008679号