

一、适用场景
适用场景:字符信息显示(传感器数值、提示信息、菜单)、调试输出、简单人机界面(参数设定、状态提示)、教学(并口/时序/I²C 驱动练习)、低成本信息面板与原型机显示模块。
二、器材清单
LCD1602A 字符液晶模块(16×2,HD44780 兼容) ×1
若干杜邦线(母对母)×1组;
stm32f103(或其他 STM32)开发板 ×1
5V 电源(模块 VCC)×1
三、工作原理(要点)
控制器:LCD1602A 常用 HD44780 兼容控制器,提供并行 8-bit/4-bit 接口与指令集(显示开关、光标、清屏、设置 DDRAM 地址等)。模块还带背光(LED)和对比度 VR(VO)。
接口模式:引脚用 8-bit 模式。I²C 背板(PCF8574)通过串行转并行节省更多引脚(通常用 I²C 地址 0x27/0x3F)。
信号线:常用引脚 VCC/GND/VO/RS/RW/EN/D4..D7/LED+/-(RW 常接地以简化,使用忙标志需接 RW 读忙位)。
时序要点:写指令/数据需遵守 EN 上升/下降脉冲与执行延时(部分驱动通过读忙标志替代延时)。初始化需特定序列(特别是在 4-bit 模式下的初始化三次 0x30 或 0x20 切换)。
四、接线示意
标准库
K、VSS → GND
VDD、A → 5V/3.3V电源
RS→ PD2
RW→ PD3
E→ PD4
D0-7→ PA0-7
HAL库
K、VSS → GND
VDD、A → 5V/3.3V电源
RS→ PB1
RW→ PB3
E→ PB4
D0-7→ PA0-7
五、示例代码
标准库
cpp
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include "stm32f10x.h"
#include "lcd1602.h"
#include "stdlib.h"
#include "bsp_SysTick.h"
void WriteData(u8 data)
{
GPIO_WriteBit(GPIOA, GPIO_Pin_7,(BitAction)((data & 0x80) >> 7 )); //D7
GPIO_WriteBit(GPIOA, GPIO_Pin_6,(BitAction)((data & 0x40) >> 6 ));
GPIO_WriteBit(GPIOA, GPIO_Pin_5,(BitAction)((data & 0x20) >> 5 ));
GPIO_WriteBit(GPIOA, GPIO_Pin_4,(BitAction)((data & 0x10) >> 4 ));
GPIO_WriteBit(GPIOA, GPIO_Pin_3,(BitAction)((data & 0x08) >> 3 ));
GPIO_WriteBit(GPIOA, GPIO_Pin_2,(BitAction)((data & 0x04) >> 2 ));
GPIO_WriteBit(GPIOA, GPIO_Pin_1,(BitAction)((data & 0x02) >> 1 ));
GPIO_WriteBit(GPIOA, GPIO_Pin_0,(BitAction)(data & 0x01)); //D0
}
void LCD1602_GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD ,ENABLE);//使能PB,PE端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
/* 等待液晶准备好 */
void LCD1602_Wait_Ready(void)
{
u16 sta;
WriteData(0xff);
LCD_RS_Clr();//表示要操作的数据是数据
LCD_RW_Set();//表示写操作
do
{
LCD_EN_Set();//使能,开始读取数
Delay_us(5000); //延时5ms,非常重要,读取数据
sta = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_7);//读取状态字
LCD_EN_Clr();//关闭使能
}while(sta & 0x80);//bit15等于1表示液晶正忙,重复检测直到其等于0为止
}
/* 向LCD1602液晶写入一字节命令,cmd-待写入命令值 */
void LCD1602_Write_Cmd(u8 cmd)
{
LCD_RS_Clr();//表示该数据是命令
LCD_RW_Clr();
LCD_EN_Clr();
WriteData(cmd);
LCD_EN_Set();
Delay_us(5000);
LCD_EN_Clr();
}
/* 向LCD1602液晶写入一字节数据,dat-待写入数据值 */
void LCD1602_Write_Dat(u8 dat)
{
LCD_RS_Set();//表示该数据是数据
LCD_RW_Clr();//表示要进行写操作
LCD_EN_Clr();//关闭使能脚,防止对填数据造成干扰
WriteData(dat);//填入数据
LCD_EN_Set();//拉高使能脚lcd开始读取数据
Delay_us(5000);//等待读取完成
LCD_EN_Clr();
}
/* 清屏 */
void LCD1602_ClearScreen(void)
{
LCD1602_Write_Cmd(0x01);//0x01是官方给的清屏指令,不用管什么原因
}
/* 设置显示RAM起始地址,亦即光标位置,(x,y)-对应屏幕上的字符坐标 */
void LCD1602_Set_Cursor(u8 x, u8 y)
{
u8 addr;
if (y == 0)
addr = 0x00 + x;//0x00是第一行最左侧的地址
else
addr = 0x40 + x;//0x40是第二行最左侧的地址
LCD1602_Write_Cmd(addr | 0x80);//官方要求最高位必须是1,因此无论是在那个地址最高位必须设置为1
}
/* 在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,str-字符串指针 */
void LCD1602_Show_Str(u8 x, u8 y, char *str)
{
LCD1602_Set_Cursor(x, y);
while(*str != '\0')
{
LCD1602_Write_Dat(*str++);
}
}
/* 初始化1602液晶 */
void LCD1602_Init(void)
{
LCD1602_Write_Cmd(0x38); //设置显示模式,16*2显示,5*7点阵,8位数据口
Delay_us(5000);
LCD1602_Write_Cmd(0x0c); //打开显示,并光标关闭
Delay_us(5000);
LCD1602_Write_Cmd(0x06); //设置光标的移动显示方式,文字不动,地址自动+1
Delay_us(5000);
LCD1602_Write_Cmd(0x01); //清屏
Delay_us(5000);
}
#include "stm32f10x.h"
#include "stdio.h"
#include "bsp_SysTick.h"
#include "lcd1602.h"
int main()
{
SysTick_Init(); //延时函数初始化
Delay_us(10000);
LCD1602_GPIO_Configuration();
LCD1602_Init();
while(1)
{
LCD1602_Show_Str(2, 1, "open");
Delay_us(5000000);
LCD1602_Show_Str(2, 1, "close");
Delay_us(5000000);
}
}
HAL库
cpp
#include "lcd1602.h"
#include "stdlib.h"
/*****************辰哥单片机设计******************
STM32
* 文件 : LCD1602液晶显示屏c文件
* 版本 : V1.0
* 日期 : 20245.2.6
* MCU : STM32F103C8T6
* 接口 : 见代码
* BILIBILI : 辰哥单片机设计
* CSDN : 辰哥单片机设计
* 作者 : 辰哥
**********************BEGIN***********************/
/*******************************************************************************
* 函 数 名 : LcdInit()
* 函数功能 : 初始化LCD屏
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void LCD1602_Init(void)
{
// LCD1602_WriteCom(0x38); //开显示
// LCD1602_WriteCom(0x0c); //开显示不显示光标
// LCD1602_WriteCom(0x06); //写一个指针加1
// LCD1602_WriteCom(0x01); //清屏
// LCD1602_WriteCom(0x80); //设置数据指针起点
LCD1602_WriteCom(0x38); //开显示
HAL_Delay(5);
LCD1602_WriteCom(0x0c); //开显示不显示光标
HAL_Delay(5);
LCD1602_WriteCom(0x06); //写一个指针加1
HAL_Delay(5);
LCD1602_WriteCom(0x01); //清屏
HAL_Delay(5);
LCD1602_WriteCom(0xC0);
HAL_Delay(5);
LCD1602_WriteCom(0x80);
}
void LCD1602_DATAPINS(uint8_t Date)
{
// uint16_t dat_buf;
// dat_buf=GPIO_ReadOutputData(GPIOA);
// dat_buf=dat_buf&0xFF00;
// dat_buf=dat_buf|Date;
// GPIO_Write(GPIOA, dat_buf);
for (int i = 0; i < 8; i++)
{
HAL_GPIO_WritePin(GPIOA, (1 << i), (Date & (1 << i)) ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
}
void LCD1602_WriteCom(uint8_t com) //写入命令
{
LCD1602_RS_L; //选择发送命令
LCD1602_RW_L; //选择写入
LCD1602_E_L; //使能
LCD1602_DATAPINS(com); //放入命令
HAL_Delay(1); //等待数 据稳定
LCD1602_E_H; //写入时序
HAL_Delay(5); //保持时间
LCD1602_E_L;
}
/*******************************************************************************
* 函 数 名 : LcdWriteData
* 函数功能 : 向LCD写入一个字节的数据
* 输 入 : dat
* 输 出 : 无
*******************************************************************************/
void LCD1602_WriteData(uint8_t dat) //写入数据
{
LCD1602_RS_H; //选择发送命令
LCD1602_RW_L; //选择写入
LCD1602_E_L; //使能
LCD1602_DATAPINS(dat); //写入数据
HAL_Delay(1);
LCD1602_E_H; //写入时序
HAL_Delay(5); //保持时间
LCD1602_E_L;
}
/*------------------------------------------------
写入字符函数
------------------------------------------------*/
void LCD1602_Write_Char(unsigned char x,unsigned char y,unsigned char Data)
{
if (y == 0)
{
LCD1602_WriteCom(0x80 + x); //第一行
}
else
{
LCD1602_WriteCom(0xC0 + x); //第二行
}
LCD1602_WriteData( Data); //显示字符
}
/*------------------------------------------------
写入字符串函数
------------------------------------------------*/
void LCD1602_Write_String(unsigned char x,unsigned char y,unsigned char *s)
{
if (y == 0)
{
LCD1602_WriteCom(0x80 + x); //第一行
}
else
{
LCD1602_WriteCom(0xC0 + x); //第二行
}
while (*s) //判断是否检测到结尾符
{
LCD1602_WriteData( *s);//显示字符
s ++; //指针加1
}
}
/*------------------------------------------------
清屏函数
------------------------------------------------*/
void LCD1602_Clear(void)
{
LCD1602_WriteCom(0x01);
HAL_Delay(5);
}
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lcd1602.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
int i=0;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
LCD1602_Init();
LCD1602_Write_String(0,0,"HELLO!!! ");//显示字符串
HAL_Delay(200);
// LCD1602_Write_String(0,1," ");//显示字符串
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
i++;
HAL_Delay(500);
LCD1602_WriteCom(0xC6);
HAL_Delay(2);
LCD1602_WriteData(i+0x30);
// LCD1602_WriteData('A');
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
六、讲解视频