目录
⭐ 1. 初始化流程(关键!必须按顺序执行,8 位模式专属,顺序不可乱)
⭐ 4. 显示字符 / 字符串(8 位 / 4 位模式通用,无差异)
⭐ 1、LCD1602 初始化流程(【核心关键】,顺序绝对不可调换、缺一不可)
⭐ 2、LCD1602 写指令函数流程(通用,所有指令发送均遵循此流程)
⭐ 3、LCD1602 写数据函数流程(通用,所有显示字符发送均遵循此流程)
<6.7> 51 单片机 LCD1602 (8 位模式) 完整驱动代码
6.1 基本概述
- 器件类型:LCD1602(Liquid Crystal Display)液晶显示屏是一种字符型液晶显示模块(只能显示 ASCII 字符,如数字、字母、符号,无法显示图形)
- 显示容量:16×2个字符,可同时显示 32 个字符,每个字符为5*7点阵。
6.2 引脚定义


6.3 工作原理
LCD1602 的核心是
指令寄存器和
数据寄存器,通过 RS、RW、E 引脚的电平组合控制操作类型:
- 两种工作模式

- 忙标志位(BF)
- 位于 LCD 内部状态寄存器的最高位(D7)
- BF=1:LCD 正忙,无法接收新指令 / 数据
- BF=0:LCD 空闲,可以执行新操作
- 51 驱动时,可通过延时替代读 BF(简化编程)
- 使能信号(E)
- 必须给一个高→低的跳变,LCD 才会执行输入的指令 / 数据
- 典型操作:E=1 → 写入指令 / 数据 → E=0
6.4 51 单片机与 LCD1602 的连接方式
51 单片机与 LCD1602 有
8 位并行 和
4 位并行 两种连接方式,4 位模式更常用(节省 IO 口)。
8 位并行连接(D0-D7 全用)
- 连接:D0-D7 接 51 单片机的 P0~P7(如 P0 口);RS、RW、E 接任意通用 IO 口(如 P2.0、P2.1、P2.2)。
- 优点:数据传输快,指令 / 数据一次发送完成。
- 缺点:占用 8 个数据 IO 口,资源消耗大。
4 位并行连接(仅用 D4-D7)
- 连接:D4-D7 接 51 单片机的 4 个 IO 口(如 P0.4~P0.7);RS、RW、E 接通用 IO 口。
- 核心原理:将 8 位指令 / 数据分两次发送,高 4 位(D4-D7)先发送,低 4 位(D0-D3)后发送,每次发送都需触发 E 引脚。
- 优点:仅占用 4 个数据 IO 口,节省资源,51 单片机项目首选。
- 缺点:数据传输速度略慢于 8 位模式(对字符显示无明显影响)。
6.5 核心指令集(必背)
LCD1602 的所有操作都需通过
指令配置,常用指令如下(8 位模式,4 位模式需拆分高 4 位和低 4 位):


地址码与屏幕位置对应关系
LCD1602 的每一行有固定的地址码,用于定位光标:
- 第一行字符地址:0x00 ~ 0x0F(对应第 1~16 列)
- 第二行字符地址:0x40 ~ 0x4F(对应第 1~16 列)
- 例:设置光标到第二行第 3 列 → 指令码 = 0x80 + 0x42 = 0xC2
6.6 51 单片机驱动 LCD1602 的基本流程
8 位数据接口模式
⭐ 1. 初始化流程(关键!必须按顺序执行,8 位模式专属,顺序不可乱)
- 延时 15ms(LCD 上电稳定时间,内部复位必备,缺一不可)。
- 发送功能设置指令(0x38) → 8 位数据接口,16×2 显示,5×8 点阵(一次性发送完整 8 位,无需拆分)。
- 延时 5ms(指令执行稳定时间,保证 LCD 正确识别指令)。
- 重复发送功能设置指令(0x38)→ 二次确认,防止上电指令识别失败,提高兼容性。
- 发送显示开关控制指令(0x0C) → 开显示,关闭光标(最常用,0x0E 开显示开光标,0x0F 开显示 + 光标 + 闪烁)。
- 发送输入模式设置指令(0x06) → 写数据时光标自动右移,显示内容不整体移位,书写顺序正常。
- 发送清屏指令(0x01),延时 2ms → 清除屏幕所有内容,光标归位到第一行第一列。

⭐ 2. 写指令函数流程(8 位模式核心,无拆分!)
- RS = 0 (选择指令寄存器,告知 LCD:接下来发送的是指令不是显示数据)。
- RW = 0 (选择写操作,51 驱动 LCD1602 只用到写,读用不到)。
- 将完整 8 位指令码直接送入 LCD 的 D0~D7 数据引脚。
- E 引脚置高 → 置低(利用 E 引脚的下降沿触发LCD 执行指令,这是 LCD 的硬件规则)。
- 延时一段时间(1~2ms,确保指令执行完成,LCD 内部处理指令需要时间)。
⭐ 3. 写数据函数流程(8 位模式核心,无拆分!)
- RS = 1 (选择数据寄存器,告知 LCD:接下来发送的是要显示的字符数据)。
- RW = 0 (保持写操作模式不变)。
- 将完整 8 位 ASCII 码数据直接送入 LCD 的 D0~D7 数据引脚(如显示 '1' 送 0x31、显示 'A' 送 0x41)。
- E 引脚置高 → 置低(下降沿触发,让 LCD 接收显示数据)。
- 延时一段时间(1~2ms,确保数据稳定写入,无乱码)。
⭐ 4. 显示字符 / 字符串(8 位 / 4 位模式通用,无差异)
- 发送光标位置指令(确定显示起始位置)→ 指令格式 0x80 + 地址码。
- 调用写数据函数,逐个发送字符的 ASCII 码,完成显示。
地址码规则(必记):第一行 1~16 列: 0x00 ~ 0x0F第二行 1~16 列: 0x40 ~ 0x4F例:显示到第二行第 5 列 → 指令码 = 0x80 + 0x44 = 0xC4
4 位数据接口模式
⭐ 1、LCD1602 初始化流程(【核心关键】,顺序绝对不可调换、缺一不可)
- 上电后先延时 15ms,等待 LCD1602 内部电路上电稳定;
- 发送功能设置指令 0x28,该指令为 4 位模式专属,发送时需分 2 次:先送高 4 位,再送低 4 位;
- 发送指令后延时 5ms,保证 LCD 稳定识别该指令;
- 重复发送一次功能设置指令0x28,确保 LCD 准确识别 4 位工作模式;
- 发送显示开关控制指令 0x0C,实现「开显示、关闭光标」;
- 发送输入模式设置指令 0x06,实现「写数据时光标自动右移,显示内容不移位」;
- 发送清屏指令 0x01,完成后延时 2ms,清除屏幕残留数据,光标归位至第一行第一列。
⭐ 2、LCD1602 写指令函数流程(通用,所有指令发送均遵循此流程)
- 置引脚 RS = 0 ,选择 LCD 的指令寄存器,告知 LCD 接下来接收的是配置指令;
- 置引脚 RW = 0 ,选择写操作模式(51 驱动 LCD 仅用到写,读操作几乎不用);
- 将需要发送的指令高 4 位,送入 LCD 的 D4~D7 引脚,随后将使能引脚 E「置高→置低」,利用下降沿触发 LCD 接收数据;
- 短暂延时一段时间,保证高 4 位数据稳定写入;
- 将需要发送的指令低 4 位,送入 LCD 的 D4~D7 引脚,再次将使能引脚 E「置高→置低」,触发接收;
- 延时一小段时间,确保指令完全执行完毕,再进行后续操作。
✔ 核心:4 位模式仅用 D4-D7,所有指令必须拆分高低 4 位分两次发送
⭐ 3、LCD1602 写数据函数流程(通用,所有显示字符发送均遵循此流程)
- 置引脚 RS = 1 ,选择 LCD 的数据寄存器,告知 LCD 接下来接收的是显示的字符数据;
- 置引脚 RW = 0 ,保持写操作模式不变;
- 将需要显示的数据高 4 位,送入 LCD 的 D4~D7 引脚,使能引脚 E「置高→置低」,下降沿触发接收;
- 短暂延时一段时间,保证高 4 位数据稳定写入;
- 将需要显示的数据低 4 位,送入 LCD 的 D4~D7 引脚,使能引脚 E 再次「置高→置低」,触发接收;
- 延时一小段时间,确保字符数据完全写入 LCD 内部缓存。
✔ 核心:写数据和写指令的唯一区别,仅为 RS 引脚电平不同(数据 = 1,指令 = 0)
⭐ 4、LCD1602 显示字符 / 字符串 流程
- 第一步:发送光标位置设置指令,指令格式为 0x80 + 地址码,确定字符的显示起始位置;
- 第一行 1~16 列 地址码:0x00 ~ 0x0F
- 第二行 1~16 列 地址码:0x40 ~ 0x4F
- 第二步:调用「写数据函数」,逐个发送字符对应的 ASCII 码,完成显示;
- 举例:显示数字1则发送0x31、显示字母A则发送0x41、显示符号-则发送0x2D;
- 若显示字符串,循环执行第二步,直到发送完所有字符的 ASCII 码。
<6.7> 51 单片机 LCD1602 (8 位模式) 完整驱动代码
✅LCD1602.c
#include <REGX52.H> //51单片机寄存器定义头文件,兼容REG52.H,包含所有IO口/寄存器地址定义
//===============LCD1602硬件引脚定义===============
sbit LCD_RS=P2^6; //LCD寄存器引脚:RS=0写指令,RS=1写数据
sbit LCD_RW=P2^5; //LCD读写引脚:RW=0写操作,RW=1读操作(本代码只用写,默认0)
sbit LCD_E=P2^7; //LCD使能引脚:下降沿触发,高电平锁存数据,低电平执行指令
#define LCD_DataPort P0 //LCD的8位数据口D0~D7 直接接单片机P0口,8位并行模式核心定义
/**
* @brief LCD1602延时函数,晶振12MHz时,该函数精准延时1ms
* @param 无参数
* @retval 无返回值
* @note LCD1602的时序要求必须加延时,保证指令/数据稳定写入,不可删除
*/
void LCD_Delay() //@12.000MHz 延时1ms标准函数
{
unsigned char i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
/**
* @brief LCD1602写指令函数:向LCD写入配置指令
* @param Command 要写入的指令码(如0x38、0x0C等)
* @retval 无
* @note 所有LCD配置操作都调用此函数,写指令固定RS=0、RW=0
*/
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0; //RS置0:选择【指令寄存器】,告知LCD接下来接收的是指令
LCD_RW=0; //RW置0:选择【写操作】,51驱动LCD1602仅用写,读极少用
LCD_DataPort=Command; //将8位指令码一次性送入LCD的D0~D7数据口
LCD_E=1; //E置高电平:锁存数据端口的指令码
LCD_Delay(); //短暂延时,保证数据稳定锁存
LCD_E=0; //E置低电平:下降沿触发LCD执行指令,核心触发逻辑
LCD_Delay(); //延时等待指令执行完成,防止指令执行不完整
}
/**
* @brief LCD1602写数据函数:向LCD写入要显示的字符数据
* @param Data 要写入的字符ASCII码(如显示'A'写0x41,显示'1'写0x31)
* @retval 无
* @note 所有字符显示都调用此函数,写数据固定RS=1、RW=0,与写指令仅RS电平不同
*/
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1; //RS置1:选择【数据寄存器】,告知LCD接下来接收的是显示数据
LCD_RW=0; //RW置0:保持写操作模式
LCD_DataPort=Data; //将字符的ASCII码送入LCD数据口
LCD_E=1; //E置高:锁存数据
LCD_Delay(); //延时稳定
LCD_E=0; //E置低:下降沿触发LCD接收显示数据
LCD_Delay(); //延时保证数据写入完成
}
/**
* @brief LCD1602初始化函数,上电必调用,初始化完成后才能使用所有显示功能
* @param 无参数
* @retval 无
* @note 指令顺序不可调换,是LCD1602的标准初始化流程,8位模式固定指令组合
*/
void LCD_Init(void)
{
LCD_WriteCommand(0x38); //功能设置指令:8位数据接口、16行2列显示、5*8点阵字符
LCD_WriteCommand(0x0C); //显示开关控制:开显示、关闭光标 (0x0E开光标,0x0F光标闪烁)
LCD_WriteCommand(0x06); //输入模式设置:写数据时光标自动右移,屏幕整体不移动
LCD_WriteCommand(0x01); //清屏指令:清除屏幕所有显示内容,光标归位到第一行第一列
}
/**
* @brief LCD1602设置光标位置函数,指定字符显示的行列坐标
* @param Line 行位置,取值范围:1 - 2 (仅支持2行)
* @param Column 列位置,取值范围:1 - 16 (仅支持16列)
* @retval 无
* @note LCD1602的DDRAM地址规则:第一行起始地址0x00,第二行起始地址0x40;0x80是地址指令前缀
*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
if(Line==1) //如果选择第一行
{
LCD_WriteCommand(0x80|(Column-1)); //0x80+列偏移量,设置第一行指定列光标
}
else //如果选择第二行
{
LCD_WriteCommand(0x80|(Column-1)+0x40); //0x80+0x40+列偏移量,设置第二行指定列光标
}
}
/**
* @brief 在LCD1602指定位置显示单个字符
* @param Line 行位置:1或2
* @param Column 列位置:1~16
* @param Char 要显示的单个字符(如'A','5','-'等)
* @retval 无
*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char)
{
LCD_SetCursor(Line,Column); //第一步:先定位光标到指定位置
LCD_WriteData(Char); //第二步:在光标位置写入字符的ASCII码,完成显示
}
/**
* @brief 在LCD1602指定位置开始显示字符串
* @param Line 起始行:1或2
* @param Column 起始列:1~16
* @param String 要显示的字符串(字符串以'\0'作为结束标志,如"Hello 51MCU")
* @retval 无
*/
void LCD_ShowString(unsigned char Line,unsigned char Column,unsigned char *String)
{
unsigned char i;
LCD_SetCursor(Line,Column); //定位光标到起始位置
for(i=0;String[i]!='\0';i++) //循环读取字符串的每个字符,直到读到结束符'\0'
{
LCD_WriteData(String[i]);//逐个写入字符ASCII码,实现字符串连续显示
}
}
/**
* @brief 内部幂运算函数,供数字显示函数调用,不可单独调用
* @param X 底数
* @param Y 指数
* @retval 返回 X的Y次方 计算结果
*/
int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1; //初始化结果为1
for(i=0;i<Y;i++) //循环累乘,计算幂值
{
Result*=X;
}
return Result; //返回计算结果
}
/**
* @brief 在LCD指定位置显示【无符号十进制数字】
* @param Line 起始行:1或2
* @param Column 起始列:1~16
* @param Number 要显示的数字,取值范围:0 ~ 65535
* @param Length 要显示的数字位数,取值范围:1 ~ 5
* @retval 无
* @note 高位在前,低位在后,如数字123,Length=3,显示"123"
*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column); //定位光标起始位置
for(i=Length;i>0;i--) //从高位到低位,依次拆分数字的每一位
{
//取当前位数字 + '0' 转为ASCII码,写入LCD显示
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
}
}
/**
* @brief 在LCD指定位置显示【有符号十进制数字】
* @param Line 起始行:1或2
* @param Column 起始列:1~16
* @param Number 要显示的数字,取值范围:-32768 ~ 32767
* @param Length 要显示的数字位数,取值范围:1 ~ 5
* @retval 无
* @note 正数显示前缀'+',负数显示前缀'-',数字部分按绝对值显示
*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
unsigned char i;
unsigned int Number1;
LCD_SetCursor(Line,Column);
if(Number>=0) //判断数字为正数
{
LCD_WriteData('+');//显示正号
Number1=Number; //正数直接赋值
}
else //判断数字为负数
{
LCD_WriteData('-');//显示负号
Number1=-Number; //取负数的绝对值,统一按正数拆分
}
for(i=Length;i>0;i--) //拆分数字每一位并显示
{
LCD_WriteData('0'+Number1/LCD_Pow(10,i-1)%10);
}
}
/**
* @brief 在LCD指定位置显示【十六进制数字】
* @param Line 起始行:1或2
* @param Column 起始列:1~16
* @param Number 要显示的数字,取值范围:0 ~ 0xFFFF
* @param Length 要显示的位数,取值范围:1 ~ 4
* @retval 无
* @note 十六进制数字0~9正常显示,10~15显示大写字母A~F
*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
unsigned char SingleNumber;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--) //从高位到低位拆分每一位十六进制数
{
SingleNumber=Number/LCD_Pow(16,i-1)%16;
if(SingleNumber<10)
{
LCD_WriteData('0'+SingleNumber); //0~9 转ASCII码显示
}
else
{
LCD_WriteData('A'+SingleNumber-10); //10~15 转A~F显示
}
}
}
/**
* @brief 在LCD指定位置显示【二进制数字】
* @param Line 起始行:1或2
* @param Column 起始列:1~16
* @param Number 要显示的数字,取值范围:0 ~ 0xFFFF
* @param Length 要显示的位数,取值范围:1 ~ 16
* @retval 无
* @note 二进制仅显示0和1,是单片机查看寄存器/引脚状态的常用功能
*/
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--) //从高位到低位拆分每一位二进制数
{
LCD_WriteData('0'+Number/LCD_Pow(2,i-1)%2);
}
}
✅LCD1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__
void LCD_Init(void);
void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,unsigned char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
#endif
6.8 项目示例
✅项目架构:

✅main.c主函数:
#include <REGX52.H>
#include "LCD1602.h"
void main()
{
LCD_Init(); //LCD初始化
LCD_ShowChar(1,1,'A'); //在1行1列显示字符A
LCD_ShowString(1,3,"Hello"); //在1行3列显示字符串Hello
LCD_ShowNum(1,9,66,2); //在1行9列显示数字66,长度为2
LCD_ShowSignedNum(1,12,-88,2); //在1行12列显示有符号数字-88,长度为2
LCD_ShowHexNum(2,1,0xA5,2); //在2行1列显示十六进制数字0xA5,长度为2
LCD_ShowBinNum(2,4,0xA5,8); //在2行4列显示二进制数字0xA5,长度为8
LCD_ShowChar(2,13,0xDF); //在2行13列显示编码为0xDF的字符
LCD_ShowChar(2,14,'C'); //在2行14列显示字符C
while(1)
{
}
}

1万+

被折叠的 条评论
为什么被折叠?



