单片机C51 之(10)GPIO 显示 -- LCD1602

本文介绍了LCD1602液晶显示器的工作原理、引脚定义及指令集,并提供了直接控制方式和间接控制方式的连接方法。同时,还详细阐述了如何通过编写驱动程序来实现对LCD1602的操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在之前的文章中讲到了显示器件–数码管,但是数码管两个缺点比较严重:
1、显示单一、体积大,显示复杂内容时就相形见绌了。
2、动态显示时序要求高,对于单片机但线程MCU来说很容易出现显示闪烁等问题。

LCD1602液晶显示器是广泛使用的一种字符型液晶显示模块。它是由字符型液晶显示屏(LCD)、控制驱动主电路及其扩展驱动电路,以及少量电阻、电容元件和结构件等装配在PCB板上而组成。不同厂家生产的LCD1602芯片可能有所不同,但使用方法都是一样的。
在这里插入图片描述在这里插入图片描述
点阵图形式液晶由M×N个显示单元组成,假设LCD显示屏有64行,每行有128列,每8列对应1字节的8位,即每行由16字节,共16×8=128个点组成。显示屏上64×16个显示单元与显示RAM区的1024字节相对应,每一字节的内容与显示屏上相应位置的亮暗对应。

字符型液晶显示模块是一种专门用于显示字母、数字和符号等的点阵式LCD,常用16×2,20×2和40×2等的模块。

引脚定义如下:

编号符号引脚说明编号符号引脚说明
1VSS电源地9D2数据
2VDD电源正极10D3数据
3VL液晶显示偏压11D4数据
4RS数据/命令选择12D5数据
5R/W读/写选择13D6数据
6E使能信号14D7数据
7D0数据15BLA背光源正极
8D1数据16BLK背光源负极

引脚1:VSS为地电源。
引脚2:VDD接5V正电源。
引脚3:VL为液晶显示器对比度调整端,接正电源时对比度最弱,接地时对比度最高,对比度过高时会产生“鬼影”现象,使用时可以通过一个10kQ的电位器调整其对比度。
引脚4:RS为寄存器选择脚,高电平时选择数据寄存器、低电平时选择指令寄存器。
引脚5:R/W为读/写信号线,高电平时进行读操作,低电平时进行写操作。当RS和R/W共同为低电平时可以写入指令或显示地址;当RS为低电平,R/W为高电平时,可以读忙信号;当RS为高电平,R/W为低电平时,可以写入数据。
引脚6:E端为使能端,当E端由高电平跳变为低电平时,液晶模块执行命令。
引脚7-14:D0~D7为8位双向数据线。
引脚15:背光源正极。
引脚16:背光源负极。

指令集 – 重要

序号指令RSR/WD7D6D5D4D3D2D1D0
1清屏0000000001
2光标复位000000001x
3输入方式设置00000001I/DS
4显示开关控制0000001DCB
5光标或字符移位控制000001S/CR/Lxx
6功能设置00001DLNFxx
7字符发生存储器地址设置0001--字符发生存储器地址---
8数据存储器地址设置001---显示数据存储器地址---
9读忙标志或地址01BF---计数器地址---
10写入数据至CGRAM或DDRAM10----要写入的数据内容---
11从CGRAM或DDRAM中读取数据11----读取的数据内容---

(1)指令1:清屏。指令码01H,光标复位到地址00H。
(2)指令2:光标复位。光标复位到地址00H。
(3)指令3:输入方式设置。其中,I/D表示光标的移动方向,高电平右移,低电平左移;S表示显示屏上所有文字是否左移或右移,高电平表示有效,低电平表示无效。
(4)指令4:显示开关控制。其中,D用于控制整体显示的开与关,高电平表示开显示,低电平表示关显示;C用于控制光标的开与关,高电平表示有光标,低电平表示无光标;B用于控制光标是否闪烁,高电平闪烁,低电平不闪烁。
(5)指令5:光标或字符移位控制。其中,S/C表示在高电平时移动显示的文字,低电平时移动光标。
(6)指令6:功能设置命令。其中,DL表示在高电平时为8位总线,低电平时为4位总线;N表示在低电平时为单行显示,高电平时双行显示;F表示在低电平时显示5×7的点阵字符,高电平时显示5×10的点阵字符。
(7)指令7:字符发生器RAM地址设置。
(8)指令8:DDRAM地址设置。
(9)指令9:读忙信号和光标地址。其中,BF为忙标志位,高电平表示忙,此时模块不能接收命令或数据,如果为低电平则表示不忙。
(10)指令10:写数据。
(11)指令11:读数据。

连接方式
LCD1602与单片机的连接有两种方式,一种是直接控制方式,另一种是所谓的间接控制方式。它们的区别只是所用的数据线的数量不同,其他都一样。
1.直接控制方式
LCD1602的8根数据线和3根控制线E,RS和R/W与单片机相连后即可正常工作。一般应用中只须往LCD1602中写入命令和数据,因此,可将LCD1602的R/W读/写选择控制端直接接地,这样可节省1根数据线。VO引脚是液晶对比度调试端,通常连接一个10kΩ的电位器即可实现对比度的调整;也可采用将一个适当大小的电阻从该引脚接地的方法进行调整,不过电阻的大小应通过调试决定。
在这里插入图片描述

2.间接控制方式
间接控制方式也称为四线制工作方式,是利用HD44780所具有的4位数据总线的功能,将电路接口简化的一种方式。为了减少接线数量,只采用引脚DB4~DB7与单片机进行通信,先传数据或命令的高4位,再传低4位。采用四线并口通信,可以减少对微控制器I/O的需求,当设计产品过程中单片机的I/O资源紧张时,可以考虑使用此方法。 可以看做是一个LCD1602加上一个IIC转并口输出模块。
在这里插入图片描述

基本操作
读状态。输入RS=0,RW=1,E=高脉冲。输出:D0—D7为状态字。
在这里插入图片描述

读数据。输入RS=1,RW=1,E=高脉冲。输出:D0—D7为数据。

写命令。输入RS=0,RW=0,E=高脉冲。输出:无。
在这里插入图片描述

写数据。输入RS=1,RW=0,E=高脉冲。输出:无。

字符库
1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。
因为1602识别的是ASCII码,试验可以用ASCII码直接赋值,在单片机编程中还可以用字符型常量或变量赋值,如’A’。
在这里插入图片描述
读的时候,先读上面那行,再读左边那列,如:感叹号!的ASCII为0x21,字母B的ASCII为0x42(前面加0x表示十六进制)。

驱动程序
1、公共代码

#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
sfr  LCD_DATA = P0;								//LCD数据端P0
sbit LCD_EN = P2^2;								//定义下面通过LCD_EN来操作P2^7口,1602液晶使能控制端
sbit LCD_WR = P2^1;								//定义下面通过lcdrw来操作P2^5口,1602读写选择端 
sbit LCD_RS = P2^0;								//定义选数据寄存器选指令寄存器控制端 
void DelayTime1ms(unsigned int DelayValue);		//1ms延时
void DelayTime10ms(unsigned int DelayValue);	//10ms延时

uchar code table0[] = {"0123456789ABCDEF"};		//要写入1602液晶的数据

2、初始化

void init_1602()
{   
	LCD_WR = 0;  
	LCD_EN = 0;   
	write_com(0x38);	//设置LCD为16*2显示、5*7点阵、8位数据接口模式  
	write_com(0x0c);	//开显示、不显示光标  
	//write_com(0x08);	// 关显示
	//write_com(0x0e);	// 开显示有光标但不闪烁
	//write_com(0x0f);	// 开显示有光标且闪烁
	write_com(0x06);	//写一个字符后,地址指针自加1  
	write_com(0x01);	//显示清0  
}

3、写指令

void write_com(uchar com) 
{   
	LCD_WR = 0;        		//LCD_WR为读写控制端,LCD_WR=0,这里可不写   
	LCD_RS = 0;        		//液晶rs接口为0时,写指令,rs为1时写数据  
	LCD_DATA = com;         //将要写的指令赋给P0口,由1602读写操作时序图,先将指令赋给P0口,延时后将使能端LCD_EN置高,再延时一段时间,然后将LCD_EN置低,这样指令就写入到LCD了
	DelayTime1ms(5);
	LCD_EN = 1;
	DelayTime1ms(5);
	LCD_EN = 0;
}

4、写一个数据

void write_data(uchar date)//与写指令类似,这里LCD_RS设为1 
{  
	LCD_RS = 1;  			//液晶rs接口为1时,写数据,rs为1时写数据  
	LCD_DATA = date;  		//将要写的指令赋给P0口,由1602读写操作时序图,先将指令赋给P0口,延时后将使能端LCD_EN置高,再延时一段时间,然后将LCD_EN置低,这样指令就写入到LCD了
	DelayTime1ms(5);  
	LCD_EN = 1;  
	DelayTime1ms(5);  
	LCD_EN = 0;  
}

5、读一个数据

uchar Read_Lcd_Data()
{
	unsigned char byte;
	LCD_DATA = 0xff;       //防止低电平干扰拉低数据位
	Lcd_RW = 1;
	Lcd_RS = 1;
	DelayTime1ms(5);       //写个延时程序 为什么加延时请看时序图
	LCD_EN = 0;
	byte = LCD_DATA ;
	DelayTime1ms(5);  
	LCD_EN  = 1;
	return byte;
}

6、显示一位数字

void write_sfm(unsigned char hang,unsigned char wei,unsigned char shuzhi)//用于在1602显示数字内容
{ 
	if(hang == 1){
		write_com(wei+0x80);		//定义显示在液晶的第一行位置   
		write_data(0x30+shuzhi);	//由1602液晶字库可知,0~9的数据码分别对应0x30~0x39  
	} else if(hang == 2) {
		write_com(wei+0xc0);		//定义显示在液晶的第二行位置  
		write_data(0x30+shuzhi);	//由1602液晶字库可知,0~9的数据码分别对应0x30~0x39  
	}	
}
### C51 单片机 DS18B20 温度传感器 LCD1602 显示 示例代码 为了实现C51单片机读取DS18B20温度传感器的数据并通过LCD1602显示出来,下面提供了一个完整的程序框架以及必要的说明。 #### 初始化设置 初始化部分主要涉及对I/O端口配置、定时器/计数器设定以及其他外设的准备。对于本项目而言,重点在于初始化LCD1602和配置好用于通信的一根GPIO线来操作DS18B20设备。 ```c #include <reg52.h> sbit RS = P2^7; // 定义RS引脚连接到P2.7 sbit RW = P2^6; // 定义RW引脚连接到P2.6 sbit EN = P2^5; // 定义EN引脚连接到P2.5 sbit DQ = P3^7; // 定义DQ引脚连接到P3.7, 这里假设使用的是单总线接口方式 void delay(unsigned int time); void lcd_init(); void write_command(unsigned char command); void write_data(unsigned char data); float read_temperature(); // 主函数入口 void main() { float temperature; lcd_init(); // 初始化液晶屏 while (1) { // 循环执行 temperature = read_temperature(); // 获取当前环境温度 // 将浮点型转换成字符串并发送给LCD显示 char str[16]; sprintf(str, "Temp:%.1f'C", temperature); write_command(0x80); // 设置光标位置至第1行起始处 for(int i=0;i<strlen(str);i++) write_data(str[i]); // 发送字符数组中的每一个字符 delay(1000); // 延迟一段时间再刷新一次 } } ``` #### 函数定义 上述代码片段中调用了几个辅助性的子程序来进行具体的操作: - `delay()` 实现简单的延时功能; - `lcd_init()` 对LCD模块进行基本参数配置; - `write_command()` 向LCD写入指令字节; - `write_data()` 输出待显示的文字信息; - `read_temperature()` 负责从DS18B20获取实时测量得到的摄氏度数值[^1]。 以下是这些函数的具体实现方法: ```c // 简易版毫秒级延迟函数 void delay(unsigned int ms){ unsigned int i,j; for(i=ms;i>0;i--) for(j=119;j>0;j--); } // 初始化LCD1602显示屏 void lcd_init(){ write_command(0x38); // 功能设置:8位数据长度,两行显示模式,5*7点阵字体大小 write_command(0x0C); // 开启显示器但不显示游标也不闪烁 write_command(0x06); // 自动增量地址指针且无屏幕移位动作 write_command(0x01); // 清除整个显示区域的内容并将DDRAM地址置零 } // 向LCD发出一条控制命令 void write_command(unsigned char cmd){ P0 = cmd & 0xF0; // 上半字节先传送 RS = 0; // 当前为命令状态 RW = 0; EN = 1; // E拉高使能信号有效 delay(5); // 经过短暂等待后... EN = 0; // ...E回到低电平完成触发周期 P0 = ((cmd<<4)&0xF0)|((cmd>>4)&0x0F);// 下半字节接着传过去 EN = 1; // 再次激活E脉冲以确认接收完毕 delay(5); EN = 0; } // 向LCD传输一个ASCII码对应的数据项 void write_data(unsigned char dat){ P0 = dat & 0xF0; RS = 1; // 此刻处于数据传输阶段 RW = 0; EN = 1; delay(5); EN = 0; P0 = ((dat<<4)&0xF0)|((dat>>4)&0x0F); EN = 1; delay(5); EN = 0; } // 从DS18B20读取温度值 float read_temperature(){ uchar ROM_NO[]={0x01}; // 存储ROM序列号缓冲区 uchar scratchpad[9]; // 暂存寄存器内容的空间 float temp; // 复位总线并检测是否存在器件响应 OW_Reset(DQ); if(!OW_Check()) return -127.0; // Skip ROM Command跳过匹配过程直接访问唯一挂载的DS18B20芯片 OW_WriteByte(0xCC); // Convert T启动转换流程 OW_WriteByte(0x44); do{}while(!OW_ReadBit()); // 等待直到转换结束标志位被置位 // Read Scratch Pad读回暂存区内保存的结果 OW_WriteByte(0xBE); for(char i=0;i<9;i++) scratchpad[i]=OW_ReadByte(); // 计算实际温度值 short raw_temp=(short)((scratchpad[1]<<8)+scratchpad[0]); if(raw_temp&0x8000) temp=((~raw_temp+1)&0xFFFF)*(-0.0625); else temp=raw_temp*(-0.0625); return temp; } ``` 这段代码展示了如何利用C51单片机配合DS18B20温度传感器与LCD1602液晶显示器构建简易测温系统的全过程。通过合理安排各个组件之间的交互逻辑,能够有效地采集外界物理量变化情况并向用户提供直观可视化的反馈信息[^2]。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值