1. 项目概述与硬件准备
最近在做一个基于ESP32-S3-CAM的智能硬件项目,需要连接一块1.54英寸的ST7789驱动LCD显示屏。这块240×240分辨率的IPS屏幕虽然小巧,但显示效果相当不错。下面我将详细记录整个连接和调试过程,包括硬件连接、代码编写和常见问题排查。
1.1 硬件选型考量
选择ST7789驱动的LCD主要基于以下几点考虑:
- 驱动芯片成熟稳定,社区支持完善
- 240×240分辨率在1.54英寸屏幕上PPI达到218,显示细腻
- IPS面板视角广,色彩表现好
- SPI接口占用GPIO少,适合资源有限的ESP32-S3
这块屏幕的引脚定义如下:
- BLK:背光控制,支持PWM调光
- CS:片选信号,低电平有效
- DC:数据/命令选择
- RES:复位信号,低电平复位
- SDA:SPI数据输入(MOSI)
- SCL:SPI时钟
- VCC:3.3V电源输入
- GND:地线
1.2 ESP32-S3-CAM引脚规划
ESP32-S3-CAM的GPIO资源有限,需要特别注意:
- 避开Strapping引脚(G0等)
- 避开板载外设使用的引脚(如G48控制RGB LED)
- 优先使用支持硬件SPI的引脚
最终确定的连接方案:
- SCL → G19 (硬件SPI时钟)
- SDA → G20 (硬件SPI MOSI)
- RES → G21
- DC → G47
- CS → G45
- BLK → G35 (支持PWM调光)
2. 硬件连接与测试
2.1 面包板接线详解
使用面包板连接时要注意:
- 先连接电源线(3.3V和GND)
- 确保电源稳定后再接信号线
- 使用合适长度的跳线避免杂乱
具体接线步骤:
- 将ESP32-S3的3.3V引脚连接到面包板正极排
- 将GND引脚连接到面包板负极排
- 屏幕VCC接正极,GND接负极
- 按规划连接各信号线
提示:建议使用不同颜色的跳线区分电源和信号线,方便排查问题。红色通常用于3.3V,黑色用于GND,其他颜色用于信号线。
2.2 上电检查要点
接好线后首次上电需要检查:
- 屏幕背光是否点亮(确认电源连接正确)
- 触摸各芯片温度是否异常(防止短路)
- 测量各引脚电压是否正常:
- VCC应为3.3V±5%
- 信号线在空闲时应为高电平(3.3V)
如果背光不亮,检查:
- 电源极性是否接反
- 跳线是否接触良好
- 万用表测量电源通路是否导通
3. 软件环境配置
3.1 Arduino IDE设置
-
安装ESP32-S3开发板支持:
- 首选项添加开发板管理器网址:https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
- 开发板管理器安装"esp32"平台
-
选择正确的开发板配置:
- 开发板:ESP32S3 Dev Module
- Flash Mode: QIO
- Flash Size: 16MB
- Partition Scheme: Huge APP (3MB No OTA)
3.2 库安装
需要安装以下库:
-
Adafruit ST7789 Library:
- 提供ST7789驱动的基本功能
- 通过库管理器搜索安装
-
Adafruit GFX Library:
- 图形显示基础库
- 会自动作为依赖安装
安装完成后,建议运行示例程序测试库是否正常工作。
4. 驱动代码实现
4.1 基础显示功能
完整的屏幕驱动代码如下:
cpp复制#include <Arduino.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7789.h>
// 引脚定义
#define TFT_SCL 19 // SPI时钟
#define TFT_SDA 20 // SPI数据(MOSI)
#define TFT_RES 21 // 复位
#define TFT_DC 47 // 数据/命令选择
#define TFT_CS 45 // 片选
#define TFT_BLK 35 // 背光控制
// 初始化ST7789对象
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_SDA, TFT_SCL, TFT_RES);
void setup() {
Serial.begin(115200);
// 初始化背光(PWM调光)
pinMode(TFT_BLK, OUTPUT);
digitalWrite(TFT_BLK, HIGH); // 全亮
// 屏幕初始化
tft.init(240, 240); // 初始化240x240屏幕
tft.setRotation(0); // 设置方向
// 显示测试图案
testDisplay();
}
void testDisplay() {
// 填充白色背景
tft.fillScreen(ST77XX_WHITE);
// 设置文本属性
tft.setTextColor(ST77XX_BLACK);
tft.setTextSize(3);
// 计算居中位置
const char* text = "Hello World";
int16_t x1, y1;
uint16_t w, h;
tft.getTextBounds(text, 0, 0, &x1, &y1, &w, &h);
int x = (240 - w) / 2;
int y = (240 - h) / 2;
// 显示文本
tft.setCursor(x, y);
tft.println(text);
}
void loop() {
// 主循环无需操作
delay(1000);
}
4.2 代码关键点解析
-
背光控制:
- 直接设置为HIGH常亮
- 可改为PWM输出实现亮度调节
-
屏幕初始化:
- init()函数指定分辨率
- setRotation()设置显示方向(0-3)
-
文本显示:
- 先计算文本占用的空间(getTextBounds)
- 再计算居中位置
- 最后用setCursor定位显示
-
颜色定义:
- ST77XX_WHITE/ST77XX_BLACK等预定义颜色
- 也可用RGB565颜色值(0xFFFF等)
5. 功能扩展与优化
5.1 背光PWM调光
修改背光控制为PWM调光:
cpp复制// 在setup()中添加:
ledcSetup(0, 5000, 8); // 通道0, 5kHz, 8位分辨率
ledcAttachPin(TFT_BLK, 0); // 绑定GPIO
// 调节亮度(0-255):
ledcWrite(0, 128); // 50%亮度
5.2 高级图形功能
- 绘制基本图形:
cpp复制tft.drawPixel(x, y, color); // 画点
tft.drawLine(x0, y0, x1, y1, color); // 画线
tft.drawRect(x, y, w, h, color); // 画矩形
tft.fillRect(x, y, w, h, color); // 填充矩形
tft.drawCircle(x, y, r, color); // 画圆
- 显示位图:
cpp复制// 需要先将图片转换为位图数组
tft.drawBitmap(x, y, bitmap, w, h, color);
5.3 性能优化技巧
-
使用双缓冲:
- 先在内存中绘制完整帧
- 再一次性刷新到屏幕
-
减少SPI时钟延迟:
cpp复制// 在初始化后设置SPI时钟
tft.setSPISpeed(40000000); // 40MHz
- 局部刷新:
- 只更新需要改变的区域
- 避免全屏刷新
6. 常见问题排查
6.1 屏幕无反应
可能原因及解决方案:
-
电源问题:
- 测量VCC电压是否为3.3V
- 检查GND连接是否良好
-
复位问题:
- 确保RES引脚初始为高电平
- 可尝试手动复位(拉低再拉高)
-
SPI信号问题:
- 用逻辑分析仪检查SCL/SDA信号
- 确认CS引脚在传输时为低电平
6.2 显示花屏
可能原因:
- 时钟速度过高 - 降低SPI速度
- 电源噪声 - 增加滤波电容
- 接线过长 - 缩短信号线长度
- 初始化顺序错误 - 确保按RES→初始化→显示的流程
6.3 文本显示不正常
常见问题:
-
字符乱码:
- 检查字体编码
- 确认文本大小设置合适
-
位置偏移:
- 确认rotation设置正确
- 重新计算文本位置
-
颜色异常:
- 检查颜色格式是否为RGB565
- 确认颜色值定义正确
7. 实际应用建议
-
电源管理:
- 屏幕工作电流约100mA,确保电源足够
- 长时间不用时可关闭背光节能
-
机械固定:
- 使用热熔胶或3D打印支架固定屏幕
- 避免接线受力
-
扩展应用:
- 结合摄像头实现实时预览
- 添加触摸功能实现交互
- 作为设备状态显示器
经过实际测试,这套方案稳定可靠,刷新率可达60fps,能够满足大多数嵌入式显示需求。后续可以考虑添加GUI库如LVGL,实现更复杂的用户界面。