LCD1602 与 TFT 彩屏:想显示更多内容时怎么选
- 分清 LCD1602、TFT、OLED 三类屏各自适合什么场景
- 在 ESP-IDF 下用 i2c_master 驱动 + HD44780/PCF8574 组件点亮 LCD1602 并实时刷新一个数值
- 知道 TFT 彩屏在 ESP-IDF 下怎么上手(esp_lcd + LVGL)、要付出什么代价
- 能照表排查白屏、不显示、乱码、地址错这些常见坑
| 器材 | 数量 | 参考 |
|---|---|---|
| LCD1602 字符屏(带 I2C PCF8574 转接板) | 1 | — |
价格随渠道波动,以购买页实时为准。
上一篇的 OLED 小巧又省线,几块钱就能给项目加块屏。但用着用着你会撞到它的天花板:0.96 寸的屏,一眼看上去就那么点地方,想显示一大段文字得分好几屏翻;想来点彩色图标、画个温度曲线,单色屏更是无能为力。
这时候就该看另外两类屏了:LCD1602 字符屏和 TFT 彩屏。一个走"便宜皮实、专门显示固定文字数字"的路线,一个走"彩色图形、好看 UI"的路线。这篇以 LCD1602 为主线在 ESP-IDF 下把代码跑通,再给 TFT 一个上手的方向——读完你能照着需求,直接挑对那块屏。
读这篇前,你得搭好 ESP-IDF 环境、跑通过 点灯那节,知道 idf.py build flash monitor 是怎么回事。
三类屏先摆在一起比一比
买屏之前,先搞清楚它们各自是干嘛的。别一上来就买 TFT 想做花哨界面,结果发现引脚和代码都吃不消。
| LCD1602 字符屏 | TFT 彩屏 | OLED | |
|---|---|---|---|
| 能显示什么 | 只能显示 16×2 个字符(固定格子) | 彩色文字、图形、图片 | 单色文字、简单图形 |
| 接口 | 带 I2C 转接板后只要 2 根信号线 | SPI,占 5~6 根线 | I2C,2 根信号线 |
| 价格 | 最便宜 | 中等偏贵 | 便宜 |
| 资源占用 | 极低 | 费引脚、费内存、费代码 | 低 |
| ESP-IDF 用什么驱 | i2c_master + HD44780 组件 | esp_lcd(SPI 面板)+ LVGL | i2c_master + SSD1306 组件 |
| 适合 | 显示固定文字、数字(温度、菜单项) | 好看的 UI、图标、曲线、中文 | 小而精、省电的小项目 |
一句话总结我的选法:只想稳稳显示几行字和数字 → LCD1602;要彩色、图形、中文 → TFT;又小又精、不占地方 → OLED(看上一篇)。这篇把 LCD1602 跑通,TFT 给方向。
LCD1602 的"1602"就是它的全部规格:16 列 × 2 行 = 32 个字符格子。它不能画像素、不能显示图片,只能在这 32 个格子里塞字母、数字和符号。听起来很受限,但正因为受限,它便宜、皮实、代码极简单——显示"Temp: 25.3C"这种固定文字,它就是最省事的选择。
接线:选带 I2C 转接板(PCF8574)的版本
LCD1602 原生是并口的,要占 16 个引脚——那是上古接法,别碰。买的时候认准背面焊了一块 I2C 转接板的版本(一小块带蓝色电位器的板子,上面那颗芯片基本都是 PCF8574)。这样和 OLED 一样,只要两根信号线。
| LCD1602(I2C 板) | ESP32-S3 |
|---|---|
| VCC | 5V |
| GND | GND |
| SDA | GPIO8 |
| SCL | GPIO9 |
GPIO8/GPIO9 是 ESP32-S3 上一对干净的通用脚,做 I2C 主机很合适。你也可以换成别的空闲 GPIO,记得代码里同步改。
注意一个和 OLED 不同的点:LCD1602 要用 5V 供电,3.3V 通常点不亮或者显示很淡。ESP32-S3 开发板上的 5V(USB 供电时有 5V 输出)拿来给它就行。
ESP32-S3 是 3.3V 的芯片,而 LCD1602 用 5V。好在 PCF8574 转接板上的 I2C 信号大多能兼容 3.3V 电平,直接接通常没问题。如果遇到不稳定,了解一下 电平转换 的原理,加一个电平转换模块更稳妥。想搞清楚 SDA/SCL 这两根线怎么同时挂多个设备,看 I2C 总线原理。
让它显示文字 + 实时数值(完整可跑代码)
ESP-IDF 不像 Arduino 那样库管理器里搜一个 LiquidCrystal I2C 装上就完事。这里 LCD1602 走的路径是:新版 i2c_master 驱动建好 I2C 总线 → 一个 HD44780 字符屏组件经 PCF8574 背包驱动屏。我们用社区里最成熟的 UncleRus esp-idf-lib 里的 hd44780 + pcf8574 两个组件,省去自己撸 4-bit 命令时序的麻烦。
第一步:把组件拉进工程
在工程目录下用组件管理器拉依赖(esp-idf-lib 已上架乐鑫组件库):
idf.py add-dependency "espressif/esp-idf-lib"
不同发行渠道的组件名和 API 可能略有出入。下面这段是按 esp-idf-lib 的 hd44780/pcf8574 接口写的参考实现,需以你拉到的那个组件的 README/头文件为准自行核对——尤其是初始化函数名、回调签名这些。组件作者偶尔会调 API,照搬别人半年前的代码可能编不过。
第二步:贴这段完整代码
把下面这段放进工程的 main/main.c:
// 在 ESP32-S3 上经 PCF8574 背包点亮 LCD1602,第一行实时刷新一个温度值
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/i2c_master.h"
#include "pcf8574.h" // I2C 扩展芯片驱动(来自 esp-idf-lib)
#include "hd44780.h" // LCD1602 字符屏驱动(来自 esp-idf-lib)
static const char *TAG = "lcd";
#define I2C_PORT I2C_NUM_0
#define PIN_SDA GPIO_NUM_8
#define PIN_SCL GPIO_NUM_9
#define LCD_ADDR 0x27 // PCF8574 背包最常见地址;有的模块是 0x3F
// hd44780 通过 pcf8574 写每根脚时,会回调到这里
static i2c_dev_t pcf; // pcf8574 设备句柄
static esp_err_t lcd_write(const hd44780_t *lcd, uint8_t data)
{
return pcf8574_port_write(&pcf, data);
}
void app_main(void)
{
// 1) 用 esp-idf-lib 的 i2cdev 初始化 I2C 总线(它内部封装了 i2c_master)
ESP_ERROR_CHECK(i2cdev_init());
// 2) 描述 PCF8574 背包:挂在哪个口、什么地址、用哪两根脚
pcf = (i2c_dev_t){ 0 };
ESP_ERROR_CHECK(pcf8574_init_desc(&pcf, LCD_ADDR, I2C_PORT, PIN_SDA, PIN_SCL));
// 3) 描述 LCD1602:16 列 2 行,背包到 HD44780 各脚的位映射 + 写回调
hd44780_t lcd = {
.write_cb = lcd_write,
.font = HD44780_FONT_5X8,
.lines = 2,
.pins = {
.rs = 0, .e = 2, .d4 = 4, .d5 = 5, .d6 = 6, .d7 = 7, .bl = 3,
},
};
ESP_ERROR_CHECK(hd44780_init(&lcd));
// 4) 开背光、写固定标题
hd44780_switch_backlight(&lcd, true);
hd44780_gotoxy(&lcd, 0, 0); // 第 0 列、第 0 行(左上角)
hd44780_puts(&lcd, "Temp:");
ESP_LOGI(TAG, "LCD1602 已初始化,开始刷新数值");
while (1) {
// 这里假设你已读到温度 temp(替换成你真实的传感器读取)
float temp = 25.3f;
char buf[8];
snprintf(buf, sizeof(buf), "%.1f C ", temp); // 末尾留空格,盖掉上次残留
hd44780_gotoxy(&lcd, 6, 0); // 移到 "Temp:" 后面
hd44780_puts(&lcd, buf);
vTaskDelay(pdMS_TO_TICKS(1000)); // 每秒刷新一次
}
}
在工程目录下编译、烧录、看日志:
idf.py build flash monitor
(第一次用要先 idf.py set-target esp32s3 选好芯片型号。)
你应该看到什么
- 编译烧录完成、进入串口监视后,监视窗口里打出一行
lcd: LCD1602 已初始化,开始刷新数值。 - 屏背光亮起来,第一行显示出
Temp:25.3 C。 - 如果你把假数据
temp = 25.3f换成真实传感器读数,那个数字会每秒跟着变——这就是"实时刷新一个数值"。
看到这行字,说明你已经会用 LCD1602 了。它的核心就两件事:hd44780_gotoxy(列, 行) 把光标移到要写的位置,hd44780_puts(...) 把内容打上去。和 OLED 的"擦画布→画→推"不同,LCD1602 是直接往格子里写字,没有帧缓冲的概念,简单得多。
注意上面 snprintf 里 "%.1f C " 末尾那个空格。LCD1602 不会自动擦旧字:上一秒显示 25.3,这一秒读到 9.8,如果不补空格,屏上会残留成 9.83(旧的 3 没被盖掉)。末尾多打一两个空格盖掉残留,是字符屏刷新数值的标准手法——和你用什么框架无关,这是 HD44780 这块控制器本身的脾气。
上面 .pins 里 rs/e/d4..d7/bl 这组数字,是 PCF8574 的 8 根输出脚到 HD44780 各控制脚的接线映射。市面绝大多数 I2C 背包是同一种走线(0,2,4,5,6,7,3),但偶有例外。如果初始化了却满屏花格子,先怀疑这个映射——这也是为什么我强调"以组件 README 为准"。
TFT 彩屏:在 ESP-IDF 下怎么上手与代价
如果 LCD1602 的"只能 32 个格子、只有单色"满足不了你——你想画彩色图标、显示一条温度曲线、甚至放张图片,那就上 TFT 彩屏。常见的驱动芯片有 ST7789、ILI9341 这些,尺寸从 1.3 寸到 3.5 寸都有,走 SPI 接口。
ESP-IDF 里玩彩屏,官方路径就是乐鑫的 esp_lcd 组件,配套 LVGL 这个图形库做 UI。和 LCD1602 那种"写一行字就完事"完全不是一个量级,思路链条是:
esp_lcd_new_panel_io_spi(...)先建一个 SPI 上的"面板 IO"——把屏挂到 SPI 总线上,配好 CS/DC/时钟等引脚。esp_lcd_new_panel_st7789(...)(或_ili9341)按你的屏型号建面板驱动对象,复位、初始化、设方向。- 上面这层只能"往某块矩形区域刷一块像素"。要做按钮、曲线、中文界面,再叠一层 LVGL:把 esp_lcd 的刷屏函数注册成 LVGL 的 flush 回调,之后你就用 LVGL 的控件搭 UI,它自己算"哪块脏了只刷哪块"。
为什么要"只刷变化区域":一块 240×320 的屏有近 8 万个像素,整屏刷一次数据量很大、还很慢。LVGL 帮你管脏区域,温度数字变了就只重画那一小格,否则会看到明显的闪烁和卡顿。
代价说清楚:TFT 费引脚(SPI 占 5~6 根)、费内存(LVGL 要画面缓冲,常还得开 PSRAM)、费代码(esp_lcd 初始化 + LVGL 学习曲线都不短)。但回报是真正的彩色 UI 和图形能力,还能轻松显示中文(LCD1602 和单色 OLED 显示中文都很别扭,要彩色中文界面基本就得上 TFT)。
新手第一块屏不建议直接上 TFT——先用 LCD1602 或 OLED 把"显示数据"这件事跑顺,再啃 esp_lcd + LVGL 不迟。彩屏这块我们后面会专门开一节深做(建工程、配 LVGL、搭第一个界面),这里你先有个"该往哪查"的方向:搜 乐鑫 esp_lcd 文档 和官方 spi_lcd_touch 例程,是最稳的起点。
故障排查:白屏 / 不显示 / 乱码,按表查
LCD1602 第一次接,卡住八成是下面这几类。照表查:
| 现象 | 最可能的原因 | 怎么办 |
|---|---|---|
| 背光亮但全屏白格子、不显示字 | I2C 地址不对 | 改代码里的 LCD_ADDR,0x27 不行就试 0x3F;或用 i2c_master 跑一遍地址扫描扫出真实地址 |
| 屏一片漆黑、毫无反应 | 没开背光 / 供电不足 | 确认代码里有 hd44780_switch_backlight(&lcd, true);确认用的是 5V 不是 3.3V |
| 显示出字但忽明忽暗、看不清 | 对比度没调好 | 拧 I2C 板上那个蓝色电位器,慢慢调到字最清楚为止 |
| 满屏花格子 / 乱码 | 背包到 HD44780 的引脚映射(.pins)不对 / 接线松 |
先按组件 README 核对 .pins 那组数字;再查 SDA/SCL 接线 |
i2cdev_init 或 hd44780_init 返回错误码 |
总线没建好 / 组件 API 对不上 | 看 monitor 里 ESP_ERROR_CHECK 报的具体行;核对组件版本与函数签名 |
数值刷新后残留旧数字(如 9.83) |
没盖掉旧字符 | 刷新数值时 snprintf 末尾多留几个空格盖残留(见上面 tip) |
I2C 板上那个蓝色小电位器是对比度调节,新屏到手第一件事就是拧它。 很多人以为屏坏了——其实是对比度出厂没调好,字淡到几乎看不见。一边拧一边看屏,调到字黑白分明就停。这一步能解决大半"屏不显示"的误判。
还有,I2C 地址不对是 LCD1602 最高频的坑。模块批次不同地址就可能不一样,0x27 和 0x3F 是两个最常见值,两个都试一遍,或者写个 i2c_master 扫描小程序把总线上的地址全列出来最稳。
变体:显示传感器数据 / 画图标
把屏用起来,最实用的就是显示真实传感器数据。
- 显示温湿度:把上面
while(1)里的假数据,换成你从 DHT11 或 DHT22 读到的真实温湿度。第一行显示温度、第二行显示湿度(hd44780_gotoxy(&lcd, 0, 1)切到第二行),一个不用连电脑的温湿度表就成了。 - TFT 上画图标/曲线:彩屏的玩法更多——在 esp_lcd + LVGL 那套里,你可以用
lv_img放一个图标位图,用lv_chart画一条实时温度曲线,搭一个带图标的状态面板。这些都属于上面说的"后面专门开一节"的内容,先有印象即可。
LCD1602 第二行的起始行号是 1(从 0 数):hd44780_gotoxy(&lcd, 0, 1) 才是第二行开头。新手常写成行号 2 然后发现第二行不显示——记住只有 0 和 1 两行。
动手挑战
别只看,挑一个改出来:
- LCD1602 实时温湿度显示(推荐):接好 LCD1602,第一行
Temp: xx.x C、第二行Humi: xx %,数据来自真实的 DHT11/DHT22。注意snprintf时末尾补空格盖残留。这就是一个能装进盒子、插电就显示的小作品。 - 做一个秒表显示:用一个计数变量计秒(配合
vTaskDelay),每秒在第二行更新一个递增的数字。卡在残留旧数字上?回看刷新那段的空格技巧。
卡住了?把你的代码、屏的型号、LCD_ADDR、用的组件版本、想要的效果一起发给 AI,让它帮你定位。LCD1602 的问题翻来覆去就那几类:地址不对、对比度没调、忘了开背光、引脚映射错、没盖旧字符——对照上面的排查表基本能自查。
小结 · 你现在掌握了什么
- 你能分清 LCD1602、TFT、OLED 三类屏:固定字符省事选 LCD1602,要彩色图形中文选 TFT,小而精选 OLED。
- 你能在 ESP-IDF 下用
i2c_master+ HD44780/PCF8574 组件,两根线接好 LCD1602、显示文字、实时刷新一个数值,也知道刷新时为什么要补空格。 - 你知道 TFT 在 ESP-IDF 下的上手路径(esp_lcd 建 SPI 面板 + LVGL 做 UI、只刷脏区域)以及它费引脚、费内存、费代码的代价。
- 白屏、不显示、乱码、对比度、地址错、引脚映射错,你能照表自己排查。
屏会用了,下一步把传感器 + 屏拼成一个能独立工作的完整作品——综合项目:把传感器和屏拼成一个设备。那一节会把数据读取和屏显示真正合到一起,做成插上电就显示的小装置。还没跑过最基础的烧录流程?回 第一个程序:点灯 把工具链顺一遍再来。
本文为公开资料整理,非亲测。关键参数与代码请结合实物与下列官方来源验证。