news 2026/1/27 19:26:50

LCD1602液晶显示屏程序与传感器数据联动显示案例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LCD1602液晶显示屏程序与传感器数据联动显示案例

用LCD1602把传感器数据“说”出来:一个看得见的温湿度监测系统

你有没有过这样的经历?调试一个温湿度采集项目时,串口打印一堆数字来回滚,眼睛都快看花了,却还是搞不清当前环境到底有多湿、多热。这时候要是有个小屏幕,直接告诉你“温度:25°C,湿度:60%”,是不是瞬间清爽了?

别急着上OLED或TFT彩屏——成本高、功耗大、驱动复杂。在很多对价格敏感的小型嵌入式设备里,真正扛大梁的,其实是一个看起来有点“复古”的家伙:LCD1602字符液晶屏

今天我们就来做一个实战案例:让LCD1602实时显示DHT11采集到的温湿度数据。不讲虚的,从硬件连接到代码逻辑,再到常见坑点和优化技巧,手把手带你把“传感器→单片机→显示屏”这条链路打通。


为什么选LCD1602?它真的还值得用吗?

先别急着嫌弃它“老土”。虽然现在满大街都是彩色触摸屏,但在实际工程中,LCD1602依然有它的不可替代性

我们来看一组对比:

特性LCD1602OLEDTFT
成本< ¥5~¥15> ¥30
功耗(不含背光)~1mA~0.05mA~50–100mA
接口方式并行GPIO(4/8位)I2C/SPISPI/RGB并行
显示内容固定ASCII字符图形+文字全彩图形+GUI
自定义能力支持8个自定义字符完全自由绘图支持复杂界面

看出门道了吗?

如果你只需要显示几行固定格式的文字,比如:

Temp: 26 C Humi: 58 %

那完全没必要为了一朵“云”买下整片天空。LCD1602结构简单、驱动直接、稳定性强,特别适合教学实验、工业控制面板、农业监测节点这类对可靠性要求高、预算有限的场景。

更重要的是——它不需要操作系统,不用跑RTOS,甚至不用DMA,STM32、Arduino、51单片机都能轻松驾驭。


硬件怎么接?一张图搞定

我们这个系统的主角有三个:

  • 主控芯片:STM32F103C8T6(蓝 pill 开发板)
  • 传感器:DHT11 温湿度模块
  • 显示器:LCD1602 字符屏(带HD44780控制器)

引脚连接一览

LCD1602引脚功能说明连接到MCU引脚备注
VSSGNDGND必接
VDDVCC (5V)5V必接
V0对比度调节可调电阻中间抽头建议接10kΩ电位器
RS寄存器选择PA0高=数据,低=指令
RW读写控制GND通常只写不读,直接接地
E使能信号PA2上升沿触发
D4–D7数据线(低4位)PB4–PB74位模式
A / K背光电源5V 或 PWM 控制可串联限流电阻

⚠️ 注意:DHT11的数据线建议通过一个10kΩ上拉电阻接到VCC,并尽量缩短走线以减少干扰。

这样一共用了7个GPIO(RS、E + D4~D7),比8位模式省了两个IO,性价比拉满。


软件怎么写?分三步走

整个程序的核心流程非常清晰:

初始化LCD → 显示启动提示 → 循环读取DHT11 → 成功则更新显示,失败则报错

我们一步步拆解。

第一步:让LCD1602“醒过来”

LCD1602上电后不能马上干活,必须按照严格的时序进行初始化,尤其是切换到4位工作模式这一步,稍有差池就会黑屏无响应。

关键步骤如下:

  1. 上电延时15ms
  2. 发送0x03三次(确保进入8位模式)
  3. 发送0x02(切换至4位模式)
  4. 配置显示参数:两行、5x7点阵、开显示、关光标

下面是基于STM32 HAL库的简化实现:

void LCD_Init(void) { delay_ms(15); LCD_CTRL_PORT->BRR = RS_PIN; // 指令模式 LCD_SendNibble(0x03); delay_ms(5); LCD_SendNibble(0x03); delay_us(150); LCD_SendNibble(0x03); LCD_SendNibble(0x02); // 正式进入4位模式 LCD_WriteCommand(0x28); // 4位数据,2行显示,5x7字体 LCD_WriteCommand(0x0C); // 开显示,关光标 LCD_WriteCommand(0x06); // 地址自动+1,画面不动 LCD_WriteCommand(0x01); // 清屏 delay_ms(2); }

其中LCD_SendNibble()是核心函数,负责发送半字节数据并触发E脉冲:

void LCD_SendNibble(uint8_t nibble) { uint32_t temp = LCD_DATA_PORT->ODR & 0xFF0F; // 清除D4-D7 temp |= (nibble & 0x0F) << 4; LCD_DATA_PORT->ODR = temp; LCD_CTRL_PORT->BSRR = EN_PIN; // E上升沿 delay_us(1); LCD_CTRL_PORT->BRR = EN_PIN; // E下降沿 delay_ms(1); }

初始化完成后,就可以愉快地输出文字了。


第二步:从DHT11手里“抢”数据

DHT11是典型的单总线器件,通信靠“握手+打拍子”完成。整个过程需要精确控制毫秒和微秒级延时。

基本流程如下:

  1. MCU拉低数据线至少18ms,唤醒DHT11;
  2. DHT11回应一个80μs的低电平+80μs的高电平;
  3. 开始传输40位数据,每位以50μs低电平开头,高电平长短区分0和1;
    - 高电平持续26–28μs → ‘0’
    - 高电平持续70μs左右 → ‘1’

下面是读取函数的关键逻辑:

int DHT11_Read(void) { uint8_t i, j, data = 0; // 设置PA3为推挽输出 GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 启动信号:拉低18ms以上 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, RESET); delay_ms(18); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, SET); delay_us(30); // 释放总线,等待响应 // 切换为输入模式 GPIO_InitStruct.Mode = GPIO_MODE_INPUT; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 等待DHT11拉低(应答开始) wait_timeout(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3), 100); // 应答低 wait_timeout(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3), 100); // 应答高 wait_timeout(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3), 100); // 数据0开始 // 读取40位数据 for (i = 0; i < 5; i++) { data = 0; for (j = 0; j < 8; j++) { while (!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3)); // 等待低电平结束 delay_us(40); // 进入高电平后延迟40us判断 if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3)) { data |= (1 << (7 - j)); } while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3)); // 等待该位结束 } dht11_data[i] = data; } // 校验和检查 if (dht11_data[4] == (dht11_data[0]+dht11_data[1]+dht11_data[2]+dht11_data[3])) { return 1; } return 0; }

📌 提示:wait_timeout(condition, max)是一个带超时保护的等待宏,防止死循环。


第三步:把数据显示出来,还不许闪!

很多人第一次做联动显示时都会犯同一个错误:每次刷新前先清屏。结果就是——屏幕疯狂闪烁,用户体验极差。

问题出在哪?LCD_WriteCommand(0x01)不仅清屏,还会归零地址指针,导致整个画面重绘,视觉上就是“闪一下”。

✅ 正确做法:局部刷新 + 补空格防残留

我们要做的不是“重画整个屏幕”,而是“只改变该变的部分”。

比如这一行:

Humi: 60 %

下次变成:

Humi: 8 %

如果不处理,屏幕上会留下一个“0”,变成“Humi: 80 %”——这就是典型的字符残留

解决办法很简单:写完数字后手动加个空格覆盖旧字符。

void LCD_PrintHumidity(uint8_t humi) { LCD_SetCursor(1, 0); // 第二行第0列 LCD_PrintStr("Humi:"); LCD_PrintNum(humi); LCD_WriteData(' '); // 清除可能残留的% LCD_WriteData('%'); }

同理,温度也可以封装成类似函数。

再配合一个状态机制,避免无效刷新:

uint8_t retry = 0; while (retry < 3 && !DHT11_Read()) { retry++; delay_ms(1000); } if (retry >= 3) { LCD_DisplayError("Sensor Error"); } else { LCD_PrintTemperature(dht11_data[2]); LCD_PrintHumidity(dht11_data[0]); }

刷新频率控制在每2秒一次即可,既保证实时性,又延长传感器寿命(DHT11建议采样间隔≥1秒)。


实战中的那些“坑”,我都替你踩过了

你以为写完代码就能稳定运行?Too young。下面这些经验,全是血泪教训总结出来的。

❗ 坑一:DHT11偶尔读不出数据

现象:有时成功,有时失败,重启就好。

原因:单总线对时序极其敏感,稍微一点延迟偏差就会导致误判。

解决方案
- 使用__NOP()内联汇编代替delay_us()提高精度;
- 在中断密集的系统中,临时关闭中断;
- 加10kΩ上拉电阻增强信号质量;
- 优先使用外部晶振而非内部RC。

❗ 坑二:LCD对比度调不好,要么全黑要么全白

现象:调了半天电位器,还是看不清。

真相:V0脚电压决定了对比度,理想范围是0.5V~1.5V之间。

推荐方案
- 不用手动电位器,改用DAC输出1V左右;
- 或者用固定分压电路(如4.7k + 1k电阻);
- 工业级应用可加入温补电路,因为液晶特性受温度影响较大。

❗ 坑三:背光太亮费电,晚上刺眼

改进思路
- 将背光正极通过N-MOS管连接到MCU的PWM引脚;
- 白天全亮,夜间降为30%亮度;
- 甚至可以结合光敏电阻自动调节。


还能怎么升级?让它更聪明一点

别以为这只是个“玩具级”项目。这个基础架构完全可以扩展出更多实用功能:

🔹 加个按键,切换显示模式

  • 按一下:显示温湿度
  • 再按:显示历史最高/最低值
  • 长按:进入校准模式

🔹 接Wi-Fi上传数据

  • 用ESP-01S模块将数据发到MQTT服务器;
  • 手机APP随时查看记录;
  • 结合继电器实现自动除湿/加热控制。

🔹 自定义图标提升体验

LCD1602支持8个自定义字符,我们可以画一个小小的“水滴”💧表示湿度,“太阳”☀️表示温度:

// 自定义“水滴”图案 uint8_t droplet[8] = { 0b00100, 0b01010, 0b01010, 0b01010, 0b01010, 0b10001, 0b10001, 0b01110 }; LCD_CreateChar(0, droplet); // 存入CGRAM位置0 LCD_WriteData(0); // 显示该图标

从此你的显示不再是冷冰冰的字母,而是有了“表情”的交互界面。


写在最后:小屏幕,大世界

也许你觉得LCD1602已经“过时”了,但我想说的是:技术没有过时,只有是否适用

在这个追求“炫酷UI”的时代,我们反而更需要回归本质——用最简单的方案解决最真实的问题

当你在一个偏远农田的监测站里,看到一块小小的LCD屏稳稳地写着“Temp: 28°C, Humi: 72%”,而整个系统靠太阳能供电一年都不用维护时,你会明白:

有时候,最朴素的显示,才是最有力量的信息传递。

掌握LCD1602与传感器联动的技术,不只是学会了一个外设驱动,更是建立起一种系统思维:如何让物理世界的变化,被人类感知

这正是嵌入式开发的魅力所在。

如果你也在做类似的项目,欢迎留言交流经验。或者告诉我你想下一个点亮什么传感器?PM2.5?土壤湿度?我们可以一起把它“显示”出来。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/25 0:26:56

GPT-SoVITS语音克隆应用场景全景图:20个行业用例

GPT-SoVITS语音克隆应用场景全景图&#xff1a;20个行业用例 在数字内容爆炸式增长的今天&#xff0c;用户对个性化、情感化的声音体验需求正以前所未有的速度攀升。从智能助手到有声书&#xff0c;从虚拟偶像到远程教育&#xff0c;传统千篇一律的机械音早已无法满足人们对“像…

作者头像 李华
网站建设 2026/1/14 20:15:51

Keil4串口调试输出分析:操作指南配合仿真

Keil4串口调试输出实战&#xff1a;用软件仿真高效定位嵌入式问题你有没有遇到过这种情况——代码写完了&#xff0c;烧进板子却“没反应”&#xff1f;断点调试又太慢&#xff0c;变量太多根本抓不住重点。这时候&#xff0c;最直接的办法是什么&#xff1f;让程序自己“说话”…

作者头像 李华
网站建设 2026/1/25 19:08:36

GPT-SoVITS与RVC对比:哪个更适合语音克隆新手?

GPT-SoVITS与RVC对比&#xff1a;哪个更适合语音克隆新手&#xff1f; 在AI生成内容爆发的今天&#xff0c;个性化语音不再是影视特效或大厂专属的技术。越来越多的内容创作者、独立开发者甚至普通用户开始尝试“克隆”自己的声音——用于制作有声书、虚拟主播、智能助手&…

作者头像 李华
网站建设 2026/1/26 8:03:59

GPT-SoVITS语音合成动态范围分析:高低频表现均衡性

GPT-SoVITS语音合成动态范围分析&#xff1a;高低频表现均衡性 在智能语音助手、虚拟偶像、有声读物等应用日益普及的今天&#xff0c;用户对“像人”的声音不再满足于基本可懂&#xff0c;而是追求更细腻的情感表达与真实的听觉质感。尤其当一段合成语音出现在安静的夜晚阅读场…

作者头像 李华
网站建设 2026/1/26 1:42:41

Unity游戏自动翻译插件完全指南:轻松实现多语言游戏体验

Unity游戏自动翻译插件完全指南&#xff1a;轻松实现多语言游戏体验 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator 在当今全球化的游戏市场中&#xff0c;Unity游戏翻译已成为玩家突破语言障碍的关键技术…

作者头像 李华
网站建设 2026/1/9 13:16:27

GPT-SoVITS虚拟偶像配音实战:打造专属声线IP

GPT-SoVITS虚拟偶像配音实战&#xff1a;打造专属声线IP 在虚拟主播直播间里&#xff0c;一个声音甜美、语调自然的AI助手正与观众实时互动&#xff1b;在有声书平台&#xff0c;一段由用户自定义音色朗读的小说片段悄然上线&#xff1b;而在某部独立动画制作现场&#xff0c;主…

作者头像 李华