Bootstrap

【51单片机】LCD1602液晶显示屏

学习使用的开发板:STC89C52RC/LE52RC
编程软件:Keil5
烧录软件:stc-isp

开发板实图:
在这里插入图片描述

LCD1602

LCD1602(Liquid Crystal Display)液晶显示屏是一种字符型液晶显示模块,可以显示ASCII码的标准字符和其他的一些内置特殊字符,还可以有8个自定义字符

显示容量:16 × 2 个字符,每个字符为 5 × 7 点阵

在这里插入图片描述

引脚及应用电路

在这里插入图片描述

  • VSS:电源接地,相当于负极
  • VO:对比度调节电压,可通过该旋钮调节在这里插入图片描述
  • RS、RW、E 对应 I/O口如下在这里插入图片描述
  • D0 ~ D7 对应 I/O 口如下在这里插入图片描述
  • A、K:背光灯电源正负极在这里插入图片描述

存储结构

LCD1602能显示的字符在出厂时已经被固定好了,存储在一个字模库中。

该字模库由 CGRAM(可自定义字符) + CGROM(只读) 组成

在这里插入图片描述
红色部分为 CGROM,出厂时设置好了,不可修改
蓝色部分为 CGRAM,可由用户自定义字符

从上图可看出,“A” 字符对应的高位代码为 0100,对应左边低位代码为 0001,合起来就是 0100 0001,十六进制为 0x41。刚好与 ASCII 码相同,因此在向 LCD1602 显示字符时,可直接用 P0 = ‘A’

0x20 ~ 0x7F 为标准的 ASCII 码,0xA0 ~ 0xFF 为日文字符和希腊文字符,其余字符码(0x10 ~ 0x1F 及 0x80 ~ 0x9F)没有定义


LCD1602 的屏幕为 16 * 2,但其实 DDRAM(数据显示区) 为 40 * 2,超出范围的区域可以通过屏幕左移或右移显示。LCD1602 提供循环显示,即一直左移,超出范围后会自动衔接上最右侧的内容,形成移动横幅的效果

显示逻辑如下

在这里插入图片描述

  • AC(光标位置):控制写数据的位置

通过控制电路,确定 AC 位置,往 DDRAM 写入要显示的字符,通过字模库转化,最终显示在屏幕上

DDRAM地址如下

在这里插入图片描述

时序结构

  • RS:数据/指令选择,1为数据,0为命令
  • RW:读/写选择,1为读,0为写
  • E:使能标志。置1时,D0 ~ D7 的数据会被写入

指令集如下,标红的为较常用的
在这里插入图片描述

编码 —— 显示字符、数字

LCD1602 主要的两个操作就是 初始化显示字符,其他操作都是基于这两个操作

首先先封装 写数据 和 写命令 的方法

/**
  * @brief		延迟1ms
  * @parm		无
  * @retval		无
  */
void LCD_Delay1ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief		写命令
  * @parm		Command:命令
  * @retval		无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS = 0;					//命令
	LCD_RW = 0;					//写
	LCD_DATAPORT = Command;		//写命令
	LCD_EN = 1;					//拉高使能
	LCD_Delay1ms();
	LCD_EN = 0;					//拉低使能
	LCD_Delay1ms();
}

/**
  * @brief		写数据
  * @parm		Data:数据
  * @retval		无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS = 1;					//命令
	LCD_RW = 0;					//写
	LCD_DATAPORT = Data;		//写命令
	LCD_EN = 1;					//拉高使能
	LCD_Delay1ms();
	LCD_EN = 0;					//拉低使能
	LCD_Delay1ms();
}

初始化
常用的初始化如下:

  1. 八位数据接口,两行显示,5 * 7 点阵
  2. 显示开,光标关,闪烁关
  3. 数据读写操作后,光标自动加一,画面不动
  4. 清屏

通过上述指令集都可以找到对应的指令,调用LCD_WriteCommand即可

/**
  * @brief		初始化LCD1602
  * @parm		无
  * @retval		无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);		//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0C);		//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);		//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);		//清屏
}

显示字符

需要先确定光标位置,将数据写在 DDRAM 的什么位置,再发送数据

/**
  * @brief		设置光标位置
  * @parm		Row:行号,范围:1 ~ 2
  * @parm		Column:列号,范围:1 ~ 40
  * @retval		无
  */
void LCD_SetCursor(unsigned char Row, unsigned char Column)
{
	if(Row == 1)	//第一行起始为0x00
		LCD_WriteCommand(0x80 | (Column - 1));
	else			//第二行起始为0x40
		LCD_WriteCommand(0x80 | (Column - 1) + 0x40);
}

/**
  * @brief		显示一个字符
  * @parm		Row:行号,范围:1 ~ 2
  * @parm		Column:列号,范围:1 ~ 40
  * @parm		Char:字符
  * @retval		无
  */
void LCD_ShowChar(unsigned char Row, Column, Char)
{
	LCD_SetCursor(Row, Column);
	LCD_WriteData(Char);
}

接下来就是一些扩展方法
显示字符串,十进制无符号和有符号数字,十六进制,二进制

/**
  * @brief		显示字符串
  * @parm		Row:行号,范围:1 ~ 2
  * @parm		Column:列号,范围:1 ~ 40
  * @parm		String:字符串
  * @retval		无
  */
void LCD_ShowString(unsigned char Row, unsigned char Column, unsigned char *String)
{
	unsigned char i = 0;
	LCD_SetCursor(Row, Column);
	for(i = 0; String[i] != '\0'; ++i)
		LCD_WriteData(String[i]);
}

/**
  * @brief		X的Y次方
  * @parm		X:基数
  * @parm		Y:次方数
  * @retval		X^Y
  */
unsigned long LCD_Pow(int X, int Y)
{
	unsigned long res = 1;
	while(Y--)
	{
		res *= X;
	}
	return res;
}

/**
  * @brief		在指定位置显示指定长度的无符号数字,从高位截取
  * @parm		Row: 行号,范围:1/2
  * @parm		Column: 列号,范围:1 ~ 40
  * @parm		Num: 显示的数字,范围:0 ~ 65535
  * @parm		Length: 长度,范围:1 ~ 40
  * @retval		无
  */
void LCD_ShowNum(unsigned char Row, unsigned char Column, unsigned int Num, unsigned char Length)
{
	LCD_SetCursor(Row, Column);
	for(; Length > 0; --Length)
		LCD_WriteData((Num / LCD_Pow(10, Length - 1) % 10) + '0');
}

/**
  * @brief		在指定位置显示指定长度的有符号数字,从高位截取
  * @parm		Row: 行号,范围:1/2
  * @parm		Column: 列号,范围:1 ~ 40
  * @parm		Num: 显示的数字,范围:-32768 ~ 32767。
  * @parm		Length: 长度,范围:1 ~ 40
  * @retval		无
  */
void LCD_ShowSignedNum(unsigned char Row, unsigned char Column, int Num, unsigned char Length)
{
	//显示正负号
	unsigned int ShowNum;
	if(Num >= 0){
		LCD_ShowChar(Row, Column, '+');
		ShowNum = Num;
	}	
	else{
		LCD_ShowChar(Row, Column, '-');
		ShowNum = -Num;
	}
	LCD_ShowNum(Row, Column + 1, ShowNum, Length);
}

/**
  * @brief		在指定位置显示指定长度的十六进制数字
  * @parm		Row: 行号,范围:1/2
  * @parm		Column: 列号,范围:1 ~ 40
  * @parm		Num: 显示的数字,范围:0 ~ 65535
  * @parm		Length: 长度,范围:1 ~ 40
  * @retval		无
  */
void LCD_ShowHexNum(unsigned char Row, unsigned char Column, unsigned int Num, unsigned char Length)
{
	unsigned char Temp;
	LCD_SetCursor(Row, Column);
	for(; Length > 0; --Length)
	{
		Temp = Num / LCD_Pow(16, Length - 1) % 16;
		if(Temp >= 10)
			LCD_WriteData(Temp - 10 + 'A');
		else
			LCD_WriteData(Temp + '0');
	}
}

/**
  * @brief		在指定位置显示指定长度的二进制数字
  * @parm		Row: 行号,范围:1/2
  * @parm		Column: 列号,范围:1 ~ 40
  * @parm		Num: 显示的数字,范围:0 ~ 65535
  * @parm		Length: 长度,范围:1 ~ 40
  * @retval		无
  */
void LCD_ShowBinNum(unsigned char Row, unsigned char Column, unsigned int Num, unsigned char Length)
{
	LCD_SetCursor(Row, Column);
	for(; Length > 0; --Length)
		LCD_WriteData(Num / LCD_Pow(2, Length - 1) % 2 + '0');
}

完整项目链接:【51单片机】LCD1602液晶显示屏


以上就是本篇博客的所有内容,感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;