1.9英寸LCD模块驱动全攻略:从ST7789/ST7735S到TFT_eSPI实战
1. 项目概述:1.9英寸LCD模块的入门与价值
最近在捣鼓一个需要小型显示界面的项目,选型时,1.9英寸的LCD模块进入了我的视线。这尺寸听起来不大,但在嵌入式开发、便携设备和DIY项目中,它是个非常经典的“甜点”尺寸。比0.96英寸的显示内容多,又比2.4或3.5英寸的省电、便宜且易于集成。如果你正在为你的树莓派Pico、Arduino或者STM32寻找一块清晰、够用且驱动简单的屏幕,那么深入了解这块1.9英寸LCD模块,绝对能让你少走很多弯路。
简单来说,这是一个对角线为1.9英寸的液晶显示模块。市面上常见的有两种主流驱动芯片:ST7789和ST7735S,分辨率则多为170x320(竖屏)或320x170(横屏)。这种模块通常集成了背光、驱动电路和排针接口,我们只需要通过几根线(SPI或8位并行)与主控MCU连接,再写好驱动代码,就能点亮它,显示文字、图形甚至流畅的动画。它解决的正是小型化、低功耗项目中“人机交互界面”的核心需求,无论是做个迷你游戏机、便携式传感器数据显示屏,还是智能家居的微型控制面板,它都能胜任。
2. 核心驱动方案与接口选择
当你拿到一块1.9寸LCD模块,第一件事不是急着接线,而是搞清楚它的“心脏”——驱动芯片是什么,以及它支持哪种通信接口。这直接决定了你的硬件连接方式和后续的软件驱动库选择。
2.1 驱动芯片辨识:ST7789 vs ST7735S
市面上绝大多数1.9寸LCD模块都采用这两款由意法半导体(ST)生产的控制器。它们功能相似,但略有区别。
ST7789:这是更常见于1.9寸模块的驱动芯片,尤其是那些170x320分辨率的型号。它支持最高262K色(18位RGB 6-6-6格式),显存(GRAM)足够大,能完整缓存一屏170x320的图像数据。这意味着在实现全屏刷新或动画时,性能表现更稳定。其指令集相对丰富,支持局部刷新、睡眠模式等高级功能。
ST7735S:最初更多用于1.44寸或1.8寸屏,但也有一些1.9寸模块使用其变种。它通常支持最高262K色,但显存可能较小,有时需要主控MCU进行分块刷新。其驱动代码库非常成熟,在Arduino社区有大量现成例子。
实操心得:如何快速分辨?最可靠的方法是查看模块背面或卖家提供的资料。如果资料不全,可以尝试:1)观察分辨率,170x320的多为ST7789;2)用万用表测量,ST7789的典型工作电压是2.8V-3.3V(VCC),而背光电压(LED+)可能是3.3V或5V;3)最直接的是,尝试用Arduino的TFT_eSPI库,分别选择ST7789和ST7735S的配置进行测试,哪个能正常显示就用哪个。
2.2 通信接口详解:SPI与8位并行
接口选择是平衡速度和引脚资源的关键。
SPI(串行外设接口):这是最常用、最省引脚的方式。通常需要4-5根线:
- SCK:时钟线。
- MOSI:主设备输出,从设备输入,用于发送命令和数据。
- DC(或RS):数据/命令选择线。这是关键!拉高时,MOSI上传的是要显示的像素数据;拉低时,传的是控制命令(如设置显示区域)。
- CS:片选线,低电平有效。当连接多个SPI设备时,用于选择当前操作的屏幕。
- RST:复位线(可选,但建议连接)。用于硬件复位屏幕,解决初始化异常问题。
SPI接口的优点是接线简单,占用MCU的I/O口少。缺点是刷新速度受限于SPI时钟频率。对于1.9寸170x320的分辨率,全屏刷新一帧图像需要传输1703202(假设16位色深)≈ 108,800字节。在40MHz的SPI时钟下,理论刷新率可以达到十几帧每秒,对于大多数UI应用足够了。
8位并行接口:这种方式会占用大量的I/O口(通常需要D0-D7共8根数据线,外加DC、WR、RD、CS、RST等控制线),但优势是速度极快,因为它每个时钟周期可以传输8位数据。如果你的主控MCU(如STM32F4系列)有富裕的I/O且对刷屏速度有极致要求(比如显示高速变化的波形),可以考虑此方式。但对于Arduino Uno或树莓派Pico这类引脚资源紧张的平台,SPI是更务实的选择。
注意事项:购买模块时,务必确认其接口类型。有些模块的排针焊盘同时支持SPI和8位并行,需要通过焊点或电阻来选择模式。默认出厂通常是SPI模式。接线前,仔细阅读模块的引脚定义图,VCC和GND切勿接反,背光LED+的电压也要匹配(接3.3V或5V,串联一个限流电阻更安全)。
3. 硬件连接与供电设计要点
正确的硬件连接是成功点亮屏幕的第一步,这里面的细节决定了系统的稳定性和寿命。
3.1 典型接线方案(以SPI接口连接树莓派Pico为例)
假设我们使用一块基于ST7789、SPI接口的1.9寸LCD模块,与树莓派Pico连接。树莓派Pico有硬件SPI接口,我们使用其默认的SPI0。
| LCD模块引脚 | 树莓派Pico GPIO引脚 | 功能说明 |
|---|---|---|
| VCC | VSYS 或 3V3(OUT) | 电源正极(3.3V)。注意:务必确认模块逻辑电压是3.3V兼容。 |
| GND | GND | 电源地。 |
| SCL (SCK) | GP2 (SPI0 SCK) | SPI时钟线。 |
| SDA (MOSI) | GP3 (SPI0 TX) | SPI数据输出线。 |
| RES (RST) | GP4 | 复位引脚,低电平有效。可接任意GPIO。 |
| DC (RS) | GP5 | 数据/命令选择引脚。可接任意GPIO。 |
| CS | GP6 | 片选引脚,低电平有效。可接任意GPIO。 |
| BLK (LED+) | GP7 (通过一个100Ω电阻) | 背光控制。可接PWM引脚实现亮度调节。 |
接线时,建议使用杜邦线或焊接排针,确保接触牢固。对于需要移动的项目,可以考虑使用FFC软排线,更为可靠。
3.2 电源与背光电路设计
电源是稳定的基石。1.9寸LCD模块的工作电流不大,逻辑部分通常在几十毫安以内,但背光LED是耗电大户。全亮时,背光电流可能达到60-100mA。
逻辑电源(VCC):必须与MCU的逻辑电平匹配。绝大多数现代MCU(如RP2040、ESP32、STM32)都是3.3V系统,因此模块VCC接3.3V。如果MCU是5V系统(如Arduino Uno),而模块是3.3V逻辑,则必须使用电平转换器,或者确认模块是否标称支持5V输入(有些模块板载了LDO,从5V降压到3.3V)。
背光电源(BLK/LED+):
- 直接使能:最简单的方法是接一个GPIO。输出高电平(3.3V或5V)点亮,输出低电平关闭。务必在GPIO和LED+之间串联一个限流电阻!电阻值可以根据公式
R = (Vcc - Vf_led) / I_led计算。其中Vcc是GPIO输出电压(如3.3V),Vf_led是LED正向压降(通常约2.8V-3.0V),I_led是期望的背光电流(可从模块手册查得,如60mA)。计算可得R = (3.3V - 2.9V) / 0.06A ≈ 6.7Ω,可以选择一个10Ω/0.25W的电阻。如果没有电阻,长时间工作可能烧毁背光LED或损坏GPIO口。 - PWM调光:将BLK接到支持PWM的GPIO上。通过调节PWM的占空比,可以无级调节屏幕亮度。这在电池供电的设备中非常有用,可以动态降低亮度以节省电量。代码中只需使用
analogWrite(Arduino)或设置PWM占空比即可。
- 直接使能:最简单的方法是接一个GPIO。输出高电平(3.3V或5V)点亮,输出低电平关闭。务必在GPIO和LED+之间串联一个限流电阻!电阻值可以根据公式
踩坑记录:我曾有一次直接将3.3V接至模块的LED+引脚,没有加限流电阻。屏幕点亮几分钟后,背光区域开始发黄,亮度逐渐下降,最终彻底熄灭。这就是典型的过流导致LED光衰加速。一个几分钱的电阻就能避免几十块钱的模块损坏。
4. 软件驱动与图形库实战
硬件连接妥当后,我们就进入了软件世界。选择一款高效、易用的驱动库,能让你事半功倍。
4.1 驱动库选型:TFT_eSPI vs. LVGL vs. U8g2
对于嵌入式开发,有几个图形库值得考虑:
TFT_eSPI(Arduino/PlatformIO):这是驱动ST7789/ST7735等屏幕的“瑞士军刀”。它本身是一个高度优化的底层驱动库,支持多种芯片和接口。你需要编辑库中的用户配置文件(
User_Setup.h),正确选择驱动芯片、设置分辨率、定义引脚,然后它就能提供基础的画点、画线、填充、显示位图等函数。它效率高,但构建复杂UI需要自己从零开始。LVGL(Light and Versatile Graphics Library):这是一个开源的高级嵌入式图形库,功能极其强大。它自带丰富的控件(按钮、标签、滑块、图表等)、动画效果、主题系统和多语言支持。你可以先用TFT_eSPI作为它的“显示驱动程序”,然后在其上构建复杂的用户界面。LVGL有专门针对STM32、ESP32等的移植示例。学习曲线稍陡,但适合需要华丽UI的项目。
U8g2:这是一个专注于单色图形和文本显示的库,但也支持像ST7789这样的彩色屏(会以灰度或简单色彩显示)。如果你的项目只需要显示文字和简单图标,U8g2的字体和绘图API非常易用。它比TFT_eSPI+LVGL的组合更轻量。
对于初学者或快速验证,我强烈推荐从TFT_eSPI开始。
4.2 使用TFT_eSPI驱动1.9寸ST7789屏(以PlatformIO为例)
下面是一个完整的配置和测试流程:
步骤一:创建项目并安装库在PlatformIO IDE中新建一个项目,选择正确的开发板(如Raspberry Pi Pico)。打开platformio.ini文件,在lib_deps部分添加:
lib_deps = bodmer/TFT_eSPI@^2.5.0步骤二:配置TFT_eSPI库这是最关键的一步。在项目目录下,找到并打开.pio/libdeps/[你的环境名]/TFT_eSPI/User_Setup.h这个文件。你需要修改以下关键部分:
// 取消注释你使用的驱动芯片,例如: #define ST7789_DRIVER // 设置分辨率 #define TFT_WIDTH 170 #define TFT_HEIGHT 320 // 定义引脚(根据你的实际接线修改) #define TFT_CS 6 // GP6 #define TFT_DC 5 // GP5 #define TFT_RST 4 // GP4 #define TFT_MOSI 3 // GP3 #define TFT_SCLK 2 // GP2 // 定义SPI频率(可以尝试提高以获得更快刷新) #define SPI_FREQUENCY 40000000 // 40MHz // 如果屏幕颜色显示异常(红蓝互换),可能需要交换颜色模式 // #define TFT_RGB_ORDER TFT_RGB // 正常顺序 // #define TFT_RGB_ORDER TFT_BGR // 红蓝交换保存文件。
步骤三:编写测试代码创建一个main.cpp,写入以下基础测试代码:
#include <TFT_eSPI.h> TFT_eSPI tft = TFT_eSPI(); void setup() { tft.init(); tft.setRotation(1); // 设置屏幕方向,0-3分别对应不同旋转角度,根据你的安装方式调整 tft.fillScreen(TFT_BLACK); // 清屏为黑色 // 设置文本颜色和大小 tft.setTextColor(TFT_WHITE, TFT_BLACK); tft.setTextSize(2); // 在屏幕中央显示“Hello World” tft.setCursor(20, 120); tft.println("Hello, 1.9\" LCD!"); // 画一个红色的矩形框 tft.drawRect(10, 10, 150, 100, TFT_RED); // 填充一个绿色的圆 tft.fillCircle(85, 200, 30, TFT_GREEN); } void loop() { // 主循环,可以添加动态效果 static uint32_t lastTime = 0; if (millis() - lastTime > 1000) { lastTime = millis(); // 每秒切换一次屏幕背景色 tft.fillScreen(random(0xFFFF)); // 随机颜色 delay(100); tft.fillScreen(TFT_BLACK); } }编译并上传到你的开发板。如果一切顺利,你应该能看到屏幕点亮,并显示文字和图形。
注意事项:如果屏幕白屏、花屏或显示错位,请按以下顺序排查:1) 检查
User_Setup.h中的驱动芯片型号和引脚定义是否完全正确;2) 检查硬件接线,特别是VCC、GND和DC引脚;3) 尝试降低SPI_FREQUENCY(如改为20000000);4) 尝试在tft.init()后添加一小段延时delay(100);5) 检查背光是否点亮。
5. 性能优化与高级功能探索
当基础显示功能实现后,我们通常会追求更流畅的体验和更丰富的功能。这里有几个进阶方向。
5.1 提升刷新率与动画流畅度
对于170x320的分辨率,全屏刷新数据量不小。优化刷新率是关键。
使用局部刷新:只更新屏幕上发生变化的部分区域,而不是整个屏幕。TFT_eSPI库的
setAddrWindow和pushColors函数可以配合实现。例如,更新一个区域:tft.setAddrWindow(x, y, w, h); // 设置要更新的矩形区域 tft.pushColors(buffer, w*h, 1); // 推送颜色数据数组这比调用多次
drawPixel或drawLine要快得多。启用双缓冲(如果MCU RAM足够):在内存中开辟一块和屏幕一样大的缓冲区(对于16位色深,1703202 ≈ 108KB)。所有的绘图操作都先在这个缓冲区中进行,完成一帧后,一次性通过
pushImage函数将整个缓冲区数据发送到屏幕。这可以完全消除屏幕绘制过程中的闪烁感。但请注意,树莓派Pico只有264KB RAM,分配108KB给显存后要谨慎管理剩余内存。优化SPI时钟和DMA:确保在
User_Setup.h中设置了尽可能高的SPI_FREQUENCY(如80MHz,前提是MCU和模块支持)。对于像STM32或ESP32这类有DMA(直接内存访问)控制器的MCU,可以配置SPI使用DMA传输。这样MCU在发送显示数据时,CPU可以被释放出来处理其他任务,极大提高效率。TFT_eSPI库对部分平台(如ESP32)的DMA有支持。
5.2 显示图片与中文字符
显示位图(BMP):TFT_eSPI库内置了
drawBmp函数,可以直接从SD卡读取并显示24位或16位的BMP图片。你需要先将图片转换为适合屏幕分辨率和色深的BMP格式(推荐使用工具如IrfanView或在线转换器)。注意,从SD卡读取和解码会较慢,适合显示静态logo或背景。显示中文字符:库本身不支持直接显示中文。有两种主流方案:
- 使用位图字体:将需要用到的汉字生成点阵字库(可以用
PCtoLCD等软件),然后作为图片数组嵌入代码,通过drawBitmap函数显示。优点是显示速度快,缺点是字体固定、不灵活,且占用程序存储空间。 - 使用LVGL库:LVGL内置了完善的字库支持,可以轻松添加
.bin或.ttf格式的中文字库文件,并动态渲染文本。这是构建中文UI的最佳选择,但需要引入整个LVGL框架。
- 使用位图字体:将需要用到的汉字生成点阵字库(可以用
5.3 低功耗设计考虑
对于电池供电的便携设备,屏幕往往是耗电大户。
- 动态控制背光:如前所述,使用PWM动态调节背光亮度。在待机或显示内容简单时,将亮度调至最低可接受水平。
- 利用睡眠模式:ST7789驱动芯片支持睡眠模式(Sleep In)。在屏幕长时间不需要显示时,可以通过发送命令让屏幕进入睡眠状态,此时功耗可以降至微安级别。对应的唤醒命令是
Sleep Out。在TFT_eSPI中,可以使用tft.writecommand(ST7789_SLPIN)和tft.writecommand(ST7789_SLPOUT)。 - 部分刷新模式:有些高级驱动芯片支持仅刷新屏幕上变化的部分区域,这比全屏刷新更省电。
6. 常见问题排查与实战技巧
在实际项目中,你几乎一定会遇到各种奇怪的问题。这里汇总了一些典型故障和解决方法。
6.1 上电无显示或白屏
这是最常见的问题。请按照以下清单逐步排查:
| 现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 屏幕完全无光 | 1. 电源未接通或接反。 2. 背光未开启或损坏。 3. 模块已损坏。 | 1. 用万用表测量VCC和GND引脚间电压是否为3.3V。 2. 测量BLK引脚电压,确认背光供电正常。检查限流电阻。 3. 尝试用已知好的模块替换测试。 |
| 屏幕有背光但全白 | 1. 复位时序不正确。 2. SPI通信失败(引脚接错、频率过高)。 3. 驱动芯片型号配置错误。 | 1. 确保RST引脚有正确的复位序列(先拉低至少10ms,再拉高)。在setup()中手动执行一次digitalWrite(RST_PIN, LOW); delay(20); digitalWrite(RST_PIN, HIGH); delay(150);。2. 用逻辑分析仪或示波器检查SCK、MOSI、DC线上是否有波形。降低SPI频率再试。 3. 核对 User_Setup.h中的#define,确认是ST7789_DRIVER而非ST7735_DRIVER。 |
| 屏幕显示错乱、花屏 | 1. 数据/命令(DC)引脚电平错误。 2. 颜色格式或扫描方向设置错误。 3. 电源噪声干扰。 | 1. 用逻辑分析仪捕获SPI时序,确认在发送像素数据时DC为高,发送命令时DC为低。 2. 尝试在 User_Setup.h中启用或禁用TFT_RGB_ORDER、TFT_INVERSION_ON等宏定义。3. 在VCC和GND之间靠近模块引脚处并联一个10uF和0.1uF的电容,以滤除电源噪声。 |
6.2 显示颜色异常或图像错位
如果屏幕能亮,但颜色不对(比如红色显示为蓝色),或者图像被旋转、偏移。
红蓝颜色交换:这是RGB排列顺序的问题。在ST7789的初始化序列中,有一个命令(通常是
0x36,内存访问控制,MAC)的某个位控制着RGB还是BGR顺序。在TFT_eSPI中,你可以通过修改User_Setup.h中的TFT_RGB_ORDER来切换:// #define TFT_RGB_ORDER TFT_RGB // 正常红绿蓝顺序 #define TFT_RGB_ORDER TFT_BGR // 蓝绿红顺序修改后重新编译上传测试。
屏幕方向不对:使用
tft.setRotation(0)到tft.setRotation(3)进行尝试。参数0-3分别对应0度、90度、180度、270度旋转。这会影响坐标系的起始点和增长方向。显示区域偏移:有时屏幕的驱动IC默认配置的显示区域(Display Window)可能比物理像素区域小或有偏移。这需要在初始化代码中,通过发送特定的命令来设置正确的列地址(X轴)和行地址(Y轴)范围。在TFT_eSPI的驱动文件
TFT_Drivers/ST7789_Init.h中,可以找到初始化命令序列。如果你发现图像只显示在屏幕的一部分,可能需要在这里调整ST7789_CASET(列地址设置)和ST7789_RASET(行地址设置)命令的参数。
6.3 刷新速度慢或操作卡顿
- 检查SPI时钟频率:确认
SPI_FREQUENCY已设置为MCU和模块支持的最高值(如40MHz或80MHz)。过低的频率是速度瓶颈。 - 避免频繁的全屏清屏:
tft.fillScreen(TFT_BLACK)会触发一次全屏数据传输,非常耗时。在制作动画时,考虑只重绘变化的元素,或者使用局部刷新。 - 优化图形绘制函数:例如,画水平或垂直线时,使用
drawFastHLine和drawFastVLine,它们比通用的drawLine函数更快。填充矩形使用fillRect。 - MCU性能瓶颈:如果MCU主频过低(如Arduino Uno的16MHz),处理复杂的图形计算本身就会很慢。考虑升级到更快的平台(如ESP32、STM32F4),或者简化UI逻辑。
6.4 背光闪烁或亮度不均
- PWM频率过低:如果使用PWM调光,并且频率落在人眼可察觉的范围(通常低于100Hz),就会感觉到闪烁。将PWM频率提高到1kHz以上可以有效解决。在Arduino上,可以使用
analogWriteFrequency(pin, 1000)(如果平台支持)来调整频率。 - 电源带载能力不足:当背光全亮时,瞬间电流较大。如果电源(如USB口或LDO)输出能力不足或响应慢,会导致电压跌落,可能引起屏幕复位或显示异常。确保电源能提供至少500mA的稳定电流,并在电源输入端并联一个大电容(如100uF电解电容)。
- 亮度不均:这是LCD面板本身的工艺问题,边缘可能比中心稍暗。通常属于正常现象,如果非常严重,可能是背光导光板或LED灯条有问题。
经过这些步骤,你应该能完全驾驭这块1.9英寸的LCD模块了。从硬件连接到软件驱动,从基础显示到性能优化,每一个环节的细节都决定了最终项目的稳定性和用户体验。这块小屏幕虽然不起眼,但它却是连接数字世界与物理世界、连接代码逻辑与用户感知的重要桥梁。多动手尝试,多思考优化,你会发现它能实现的远比想象中更多。
