小码农1602液晶开单片机大门

618 阅读7分钟

「这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战

小码农为了御萝,咳咳,为了知识怎么敢说液晶不显示啊

我们要清楚液晶在哪一层,可以很明显的看出在服务层 -Ser

首先我先说一下我这套板子数码管和液晶不是共存的,他们有公用的牛角座,一个用了另一个就不可以用了

数码管牛角座接法

image-20211004174404040

液晶牛角座接法

image-20211004174522142

所以我不好一起演示给你们看,也就是和上一篇博客没有没有什么关系,但是质量这方面我没见过比我好的,除了汪老师

原理图


LCD1602引脚

image-20211002220351810

你们最爱的时序图

image-20211004172853574

写指令函数LCD1602_Write_Cmd

void LCD1602_Write_Cmd(u8 add)//写命令,因为操作的是地址
{
	LCD1602_RS = 0;
	LCD1602_RW = 1;
	LCD1602_E = 0;
	LCD1602_RW = 0;//我由于没有写这条代码液晶屏一直初始化不成功
	LCD1602_Delay(3);
	LCD1602_E = 1;
	LCD1602_DB = add;
	LCD1602_E = 0;
}

写数据函数LCD1602_Write_Data

void LCD1602_Write_Data(u8 Data)//写数据
{
	LCD1602_RS = 1;
	LCD1602_RW = 1;
	LCD1602_E = 0;
	LCD1602_RW = 0;//我由于没有写这条代码液晶屏一直初始化不成功
	LCD1602_Delay(3);
	LCD1602_E = 1;
	LCD1602_DB = Data;	
	LCD1602_E = 0;
}

1602字符型LCD的写操作过程(R/W为低电平)

1.写命令过程:RS低电平,然后命令加载到D0-D7,E脚产生下降沿,命令即被1602接收并执行

2.写内容过程:RS高电平,然后数据加载到D0-D7,E脚产生下降沿,数据即被1602接收并显示

LCD1602的命令,CGRAM地址和DDRAM地址

1.命令,地址范围是0x00--0x3f。用来操作液晶的硬件配置

2.CGRAM,地址范围0x40--0x7f。用来保存液晶本身没有的其他自定义图像

3.DDRAM,地址范围0x80--0xff。用来保存ASCII码值,通过ASCII码指向自定义CGRAM图像数据首地址或者光刻的CGROM图像数据首地址

image-20211004231049942

LCD的代码控制要求

1.上电之后,必须等待最少15ms才能对LCD写入指令(地址)

2.每条指令都有最低执行时间,请按照耗时要求增加延迟等待时间

3.建议按照以下表格的顺序和耗时,轮流写入指令到LCD,方可顺利初始化

4.其他的写入地址和图像,每个字节都是耗时40微秒

image-20211004233644961

上面初始化好了

image-20211004232705561

image-20211005001057920

初始化函数LCD1602_Init

void LCD1602_Init()
{
	P4M1 &= 0xf8;
	P4M0 &= 0xf8;//设置液晶RS,RW和E的IO口为标准IO口
	//这时候就根据时序图写时序
	LCD1602_Delay(250);		    //上电后等待至少15ms,才能往LCD写指令
	LCD1602_Delay(250);			//上电后等待至少15ms,才能往LCD写指令
	LCD1602_Write_Cmd(0x38);
	LCD1602_Write_Cmd(0x01);
	LCD1602_Delay(50);
	LCD1602_Write_Cmd(0x02);
	LCD1602_Delay(50);
	LCD1602_Write_Cmd(0x06);
	LCD1602_Write_Cmd(0x0c);
	LCD1602_Write_Cmd(0x14);
}

我们试着打印一个字符

image-20211005002714436

image-20211005035627255

但是正常人谁记ASCII码呀,所以需要字符和数字之间的转换,直接用字符表示

image-20211005041627030

他后面可以连续的写,字符串的话我写串口这篇博客再细说

image-20211005042132874

这里我们在初始化里面写出来了,这只是用来测试的,真正的是不可能在初始化里面写的,不符合框架式编程要求,所以我们用数组来存储,以后我们操作数组就行了

image-20211005043007900

主文件液晶数据分配

image-20211005044311459

//液晶数据分配
void LCD1602_Allot()//液晶是很慢的一个模块
	//我们一直循环刷就会次次延时,很容易影响其他器件的工作
{
	static xdata u16 count = 0;
	count++;
	if(count>1000)
	{
		count = 0;//超过1000计数器清零
		LCD1602_Display_Ser();
	}
}

我们要清楚数字和字符的区别,不要直接在写数据中直接写数字,要有个起点,0的ASCII就是0x30,所以想要显示出数字,必须加上0x30

image-20211005051108199

我想要变化的数字

image-20211005054029657


所想显示的符号没有,那我们就只能自己写进去了,操作CGRAM

image-20211005061017244

image-20211005065212375

有时候我们还有控制光标

image-20211005065420133


代码

LCD1602_Ser.c

#include "all.h"

//液晶写缓存
u8 xdata LCD1602_Write_Buffer1[16];
u8 xdata LCD1602_Write_Buffer2[16];
//存一个固定的图案℃
u8 code LCD1602_5x8[8] = {0x80,0x00,0x07,0x08,0x80,0x80,0x80,0x07};
//写光标地址
u8 xdata LCD1602_Write_Cursor_Add;

void LCD1602_Delay(u8 len)
{
	u8 idata i = 0;
	while(len--)
	{
		i = 70;
		while(i--);
	}
}


void LCD1602_Write_Cmd(u8 add)//写命令,因为操作的是地址
{
	LCD1602_RS = 0;
	LCD1602_RW = 1;
	LCD1602_E = 0;
	LCD1602_RW = 0;//我由于没有写这条代码液晶屏一直初始化不成功
	LCD1602_Delay(3);
	LCD1602_E = 1;
	LCD1602_DB = add;
	LCD1602_E = 0;
}
void LCD1602_Write_Data(u8 Data)//写数据
{
	LCD1602_RS = 1;
	LCD1602_RW = 1;
	LCD1602_E = 0;
	LCD1602_RW = 0;//我由于没有写这条代码液晶屏一直初始化不成功
	LCD1602_Delay(3);
	LCD1602_E = 1;
	LCD1602_DB = Data;	
	LCD1602_E = 0;
}

void LCD1602_Init()
{
	u8 i = 0;
	P4M1 &= 0xf8;
	P4M0 &= 0xf8;//设置液晶RS,RW和E的IO口为标准IO口
	//这时候就根据时序图写时序
	LCD1602_Delay(250);		    //上电后等待至少15ms,才能往LCD写指令
	LCD1602_Delay(250);			//上电后等待至少15ms,才能往LCD写指令
	LCD1602_Write_Cmd(0x38);
	LCD1602_Write_Cmd(0x01);
	LCD1602_Delay(50);
	LCD1602_Write_Cmd(0x02);
	LCD1602_Delay(50);
	LCD1602_Write_Cmd(0x06);
	LCD1602_Write_Cmd(0x0c);
	LCD1602_Write_Cmd(0x14);
	//自定义字符放在初始化里面初始化
	LCD1602_Write_Cmd(0x40);//自定义存储空间自定义地址
	for(i = 0;i<8;i++)//把8个字节所组成的字符记录下来
	{
		LCD1602_Write_Data(LCD1602_5x8[i]);
	}
}

//液晶显示服务
void LCD1602_Display_Ser()
{
	u8 i = 0;
	//第一行可写地址就是0x80
	LCD1602_Write_Cmd(0x80);
	for(i = 0;i<16;i++)//把16个字节刷出去
	{
		LCD1602_Write_Data(LCD1602_Write_Buffer1[i]);
	}
	//第二行可写地址就是0xc0
	LCD1602_Write_Cmd(0xc0);
	for(i = 0;i<16;i++)
	{
		LCD1602_Write_Data(LCD1602_Write_Buffer2[i]);
	}
	switch(LCD1602_Write_Cursor_Add)
	{
		case 0:
			LCD1602_Write_Cmd(0x0c);//不显示,不闪烁光标
		break;
		case 1:
			LCD1602_Write_Cmd(0xcd);//倒数第3个位置
			LCD1602_Write_Cmd(0x0f);//光标显示闪烁
		break;
	}
}

LCD1602_Ser.h

#ifndef LCD1602_Ser
#define LCD1602_Ser

#define LCD1602_DB  P7//P7是数码管数据总线

sbit LCD1602_RS = P4^0;
sbit LCD1602_RW = P4^1;
sbit LCD1602_E = P4^2;
//外部声明

extern u8 xdata LCD1602_Write_Buffer1[16];
extern u8 xdata LCD1602_Write_Buffer2[16];
extern u8 xdata LCD1602_Write_Cursor_Add;
extern void LCD1602_Init();
extern void LCD1602_Display_Ser();

#endif