1. ESP32与ST7735显示屏开发概述
合宙ESP32C3是一款性价比极高的物联网开发板,搭载RISC-V架构的ESP32-C3芯片,兼具Wi-Fi和蓝牙功能。在嵌入式开发中,显示屏作为重要的人机交互界面,ST7735驱动的TFT液晶屏因其价格低廉、接口简单而广受欢迎。这类屏幕通常具备128x160或128x128的分辨率,支持16位色(RGB565格式)显示。
选择Arduino IDE作为开发环境,主要考虑到其丰富的库支持和跨平台特性。对于刚接触嵌入式开发的工程师来说,Arduino的封装大大降低了开发门槛。Adafruit提供的ST7735库和GFX图形库,更是为显示屏开发提供了完整解决方案。
在实际项目中,我们常遇到两类显示需求:文本和图像。文本显示需要考虑字体编码(特别是中文)、对齐方式和刷新效率;图像显示则涉及格式转换、存储优化和渲染策略。本案例通过U8g2字体库和自定义图像处理函数,实现了这两类需求的完整解决方案。
2. 硬件连接与环境搭建
2.1 硬件准备清单
开发本项目需要以下硬件组件:
- 合宙ESP32C3开发板(约25元)
- ST7735驱动的1.8寸TFT屏幕(约15元)
- 杜邦线若干(建议使用优质线材防止接触不良)
- 可选:3.3V稳压模块(当屏幕功耗较大时使用)
2.2 引脚连接详解
ST7735通常采用SPI接口通信,ESP32C3的硬件SPI引脚为:
- SCK:GPIO2
- MOSI:GPIO3
其余控制引脚可自由定义,但需与代码保持一致:
cpp复制#define TFT_CS 4 // 片选,可接任意GPIO
#define TFT_DC 6 // 数据/命令选择,必须接GPIO
#define TFT_RST -1 // 硬件复位,若接GPIO需修改
注意:ESP32C3的GPIO4和GPIO6是安全引脚,无特殊限制。若使用其他GPIO,需注意部分引脚在启动时有特殊功能(如GPIO9用于USB识别)。
2.3 软件环境配置
- 安装Arduino IDE(建议1.8.19+)
- 添加ESP32支持:
- 首选项添加开发板管理器网址:https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
- 工具→开发板→开发板管理器,搜索安装"ESP32"
- 安装必要库:
- Adafruit ST7735(1.9.3+)
- Adafruit GFX Library(1.11.5+)
- U8g2 for Adafruit GFX(需手动下载放入libraries)
3. 核心代码解析
3.1 显示初始化流程
cpp复制void setup() {
Serial.begin(115200);
tft.initR(INITR_BLACKTAB); // 初始化屏幕,BLACKTAB针对特定屏幕型号
tft.setRotation(0); // 0-3对应不同旋转角度
tft.fillScreen(ST77XX_WHITE); // 清屏为白色
u8g2_for_adafruit_gfx.begin(tft); // 初始化U8g2适配器
u8g2_for_adafruit_gfx.setFontMode(1); // 透明模式
u8g2_for_adafruit_gfx.setForegroundColor(ST77XX_BLACK);
u8g2_for_adafruit_gfx.setFont(u8g2_font_wqy14_t_gb2312); // 中文字体
}
关键点说明:
initR()的参数需与屏幕型号匹配,常见的有INITR_BLACKTAB、INITR_GREENTAB- 旋转角度影响坐标系方向,需与实际安装方向一致
- U8g2字体库支持多种编码,
wqy14_t_gb2312是14像素的文泉驿点阵中文字体
3.2 文本显示实现
cpp复制void displayText(uint16_t bgColor, uint16_t textColor,
const uint8_t *font, const char *text,
int16_t x, int16_t y) {
tft.fillScreen(bgColor);
u8g2_for_adafruit_gfx.setFontMode(1);
u8g2_for_adafruit_gfx.setForegroundColor(textColor);
u8g2_for_adafruit_gfx.setFont(font);
u8g2_for_adafruit_gfx.setCursor(x, y);
u8g2_for_adafruit_gfx.print(text);
}
字体选择建议:
- 英文字体:
u8g2_font_helvB08_tf(8像素) - 中文字体:
u8g2_font_wqy12_t_gb2312(12像素) - 大号字体:
u8g2_font_unifont_t_chinese2(16像素)
3.3 图像显示优化
原始逐像素绘制方法效率较低,改进方案:
cpp复制void showImageOpt(const uint16_t* imageData, int width, int height) {
tft.startWrite();
for (int y = 0; y < height; y++) {
tft.setAddrWindow(0, y, width-1, y); // 设置窗口为一行
tft.writePixels(&imageData[y*width], width); // 批量写入一行
}
tft.endWrite();
}
性能对比:
- 原始方法:显示128x160图像约1.2秒
- 优化方法:仅需200ms,提升6倍
4. 图像转换工具实战
4.1 ImageConverter565使用详解
- 下载工具(Windows平台):ImageConverter565.exe
- 转换步骤:
- 打开工具,点击"Open Image"选择源文件(支持JPG/PNG/BMP)
- 调整参数:
- Output Format: "C Array (RGB565)"
- Resize: 勾选并设置为屏幕分辨率(如128x160)
- Dithering: 建议勾选提升渐变效果
- 点击"Save"生成.h文件
4.2 图像数据优化技巧
- 存储优化:
cpp复制// 使用PROGMEM将图像存入Flash而非RAM
const uint16_t image[20480] PROGMEM = { /*...*/ };
// 读取时使用pgm_read_word
uint16_t pixel = pgm_read_word(&image[y*width + x]);
- 多图像管理:
cpp复制// 在image.h中定义结构体
typedef struct {
const uint16_t *data;
uint16_t width;
uint16_t height;
} Image;
// 定义多个图像
const Image img1 = {image1_data, 128, 160};
const Image img2 = {image2_data, 64, 64};
5. 常见问题与调试技巧
5.1 显示异常排查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 白屏 | 电源不稳 | 检查3.3V供电,必要时外接电源 |
| 花屏 | SPI速率过高 | 在库文件中降低SPI时钟频率 |
| 偏色 | 初始化参数错误 | 尝试不同的initR参数 |
| 文字乱码 | 字体不匹配 | 确认字体编码与文本一致 |
| 图像错位 | 旋转设置错误 | 调整setRotation参数 |
5.2 性能优化实践
- 双缓冲技术:
cpp复制// 在内存中创建缓冲区
uint16_t buffer[128*160];
// 先在缓冲区绘制
renderToBuffer(buffer);
// 再一次性刷新到屏幕
tft.drawRGBBitmap(0, 0, buffer, 128, 160);
- 局部刷新:
cpp复制// 只更新变化区域
tft.setAddrWindow(x, y, x+w, y+h);
tft.writePixels(pixels, w*h);
- 字体缓存:
cpp复制// 预先渲染常用文字到缓冲区
renderTextToCache("温度:");
// 需要时直接调用缓存
6. 项目扩展思路
- 多语言支持:
- 使用U8g2的unicode字体
- 实现UTF-8到GB2312的转换
- 动态效果:
cpp复制// 简单动画示例
for(int i=0; i<128; i++) {
tft.drawPixel(i, 80, ST77XX_RED);
delay(10);
}
- 与传感器结合:
cpp复制// 显示温湿度传感器数据
float temp = dht.readTemperature();
char buf[20];
sprintf(buf, "温度:%.1f℃", temp);
displayText(ST77XX_BLACK, ST77XX_WHITE,
u8g2_font_wqy12_t_gb2312, buf, 10, 30);
实际开发中发现,ST7735屏幕在低温环境下可能出现响应迟缓,建议在室外应用中:
- 添加屏幕加热电路
- 降低刷新频率
- 使用
tft.enableDisplay(true/false)控制电源