1. 项目概述:0.9寸TFT显示屏与ST7735驱动芯片
最近在折腾一个小型显示项目,用到了这款0.9寸的TFT液晶屏,驱动芯片是ST7735,接口为8针SPI。这种小尺寸屏幕特别适合嵌入式设备和便携式仪表的显示需求,但初次使用时确实遇到了一些坑。今天就把完整的测试代码和调试经验整理出来,给同样在玩这种屏幕的朋友参考。
这块屏幕分辨率通常是128x160或80x160,色彩表现不错,功耗低,价格也亲民。ST7735算是很常见的TFT驱动芯片了,但不同厂商的屏在初始化序列和引脚定义上会有差异。我用的这款是直接焊排针的裸屏,没有转接板,所以需要自己处理所有接线和初始化配置。
2. 硬件连接与引脚定义
2.1 屏幕引脚说明
先来看8针接口的引脚定义,这是最容易出错的地方:
| 引脚编号 | 标号 | 功能说明 |
|---|---|---|
| 1 | GND | 接地 |
| 2 | VCC | 3.3V电源输入 |
| 3 | SCL | SPI时钟线 |
| 4 | SDA | SPI数据线 |
| 5 | RES | 复位信号(低电平有效) |
| 6 | DC | 数据/命令选择 |
| 7 | CS | 片选信号(低电平有效) |
| 8 | BLK | 背光控制 |
注意:不同厂商的屏幕引脚顺序可能不同,务必以实际屏幕标注或规格书为准。我就曾经因为看错引脚顺序烧坏过一块屏。
2.2 与开发板的连接
以常见的STM32F103C8T6开发板为例,接线方式如下:
- VCC → 3.3V
- GND → GND
- SCL → PA5(SPI1 SCK)
- SDA → PA7(SPI1 MOSI)
- RES → PA1(自定义GPIO)
- DC → PA2(自定义GPIO)
- CS → PA4(SPI1 NSS)
- BLK → 3.3V(常亮)或PB0(PWM调光)
提示:如果背光控制接的是PWM引脚,可以通过代码调节亮度。直接接3.3V会让背光常亮。
3. 软件环境准备
3.1 开发环境配置
我使用的是PlatformIO + STM32duino开发环境,也可以直接用Arduino IDE。需要安装以下库:
- Adafruit ST7735 Library:官方驱动库
- Adafruit GFX Library:图形基础库
PlatformIO的platformio.ini配置示例:
ini复制[env:bluepill_f103c8]
platform = ststm32
board = bluepill_f103c8
framework = arduino
lib_deps =
adafruit/Adafruit GFX Library@^1.11.3
adafruit/Adafruit ST7735 and ST7789 Library@^1.9.3
3.2 基础驱动代码
先创建一个基本的显示测试程序:
cpp复制#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
// 引脚定义
#define TFT_CS PA4
#define TFT_RST PA1
#define TFT_DC PA2
#define TFT_SCLK PA5
#define TFT_MOSI PA7
// 初始化ST7735对象
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
void setup() {
// 初始化屏幕
tft.initR(INITR_BLACKTAB); // 初始化特定屏幕类型
tft.fillScreen(ST7735_BLACK);
// 测试显示文本
tft.setCursor(0, 0);
tft.setTextColor(ST7735_WHITE);
tft.setTextSize(1);
tft.println("Hello, ST7735!");
// 测试显示图形
tft.drawRect(10, 20, 50, 30, ST7735_RED);
tft.fillCircle(80, 40, 15, ST7735_BLUE);
}
void loop() {
// 主循环可以添加动态效果
}
4. 初始化参数详解
4.1 初始化模式选择
ST7735驱动的屏幕有不同的初始化参数,常见的有:
- INITR_GREENTAB:针对绿标签的0.96"屏
- INITR_REDTAB:针对红标签的0.96"屏
- INITR_BLACKTAB:针对黑标签的1.8"屏
- INITR_MINI160x80:针对160x80的小屏
对于0.9寸屏,通常使用INITR_BLACKTAB或INITR_MINI160x80。如果显示方向不对或颜色异常,可以尝试不同的初始化模式。
4.2 自定义初始化序列
有些屏幕可能需要自定义初始化序列。可以通过重写初始化函数来实现:
cpp复制void customInit() {
tft.writecommand(ST7735_SWRESET); // 软件复位
delay(150);
tft.writecommand(ST7735_SLPOUT); // 退出睡眠模式
delay(255);
// 设置颜色模式
tft.writecommand(ST7735_COLMOD);
tft.writedata(0x05); // 16位色
// 设置显示方向
tft.writecommand(ST7735_MADCTL);
tft.writedata(0xC0); // MX, MY, RGB顺序
// 更多初始化命令...
tft.writecommand(ST7735_DISPON); // 开启显示
delay(100);
}
5. 高级显示功能实现
5.1 屏幕旋转与方向控制
ST7735支持多种显示方向,通过MADCTL命令控制:
cpp复制// 设置显示方向
void setRotation(uint8_t m) {
tft.writecommand(ST7735_MADCTL);
switch (m % 4) {
case 0: // 纵向
tft.writedata(0xC0);
tft._width = 80;
tft._height = 160;
break;
case 1: // 横向(顺时针90度)
tft.writedata(0xA0);
tft._width = 160;
tft._height = 80;
break;
case 2: // 倒置纵向
tft.writedata(0x00);
tft._width = 80;
tft._height = 160;
break;
case 3: // 横向(逆时针90度)
tft.writedata(0x60);
tft._width = 160;
tft._height = 80;
break;
}
}
5.2 自定义颜色与图形绘制
ST7735使用16位RGB565颜色格式。可以这样定义常用颜色:
cpp复制#define ST7735_BLACK 0x0000
#define ST7735_BLUE 0x001F
#define ST7735_RED 0xF800
#define ST7735_GREEN 0x07E0
#define ST7735_CYAN 0x07FF
#define ST7735_MAGENTA 0xF81F
#define ST7735_YELLOW 0xFFE0
#define ST7735_WHITE 0xFFFF
// 自定义RGB颜色转换
uint16_t colorRGB(uint8_t r, uint8_t g, uint8_t b) {
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
绘制复杂图形的示例:
cpp复制void drawDemo() {
// 渐变背景
for(int y=0; y<tft.height(); y++) {
uint16_t color = colorRGB(0, y/2, 255-y/2);
tft.drawFastHLine(0, y, tft.width(), color);
}
// 绘制文本
tft.setTextColor(ST7735_WHITE, ST7735_BLACK);
tft.setTextSize(2);
tft.setCursor(10, 10);
tft.println("0.9\" TFT");
// 绘制图形
tft.fillRoundRect(20, 40, 80, 40, 10, ST7735_RED);
tft.drawTriangle(30, 100, 50, 70, 70, 100, ST7735_YELLOW);
// 绘制像素点
for(int i=0; i<50; i++) {
tft.drawPixel(random(tft.width()), random(tft.height()), ST7735_WHITE);
}
}
6. 性能优化技巧
6.1 加速屏幕刷新
SPI时钟速度直接影响刷新率。可以尝试提高SPI速度:
cpp复制// 在setup()中初始化SPI
SPI.beginTransaction(SPISettings(24000000, MSBFIRST, SPI_MODE0));
注意:过高的SPI速度可能导致显示异常,需要根据实际硬件调整。我的经验是STM32F103最高可以到18MHz。
6.2 部分刷新技术
只刷新屏幕变化的部分可以大幅提高性能:
cpp复制// 设置刷新区域
void setRefreshArea(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) {
tft.writecommand(ST7735_CASET);
tft.writedata(0); tft.writedata(x0);
tft.writedata(0); tft.writedata(x1);
tft.writecommand(ST7735_RASET);
tft.writedata(0); tft.writedata(y0);
tft.writedata(0); tft.writedata(y1);
tft.writecommand(ST7735_RAMWR);
}
// 只刷新特定区域
void partialRefresh() {
setRefreshArea(10, 10, 50, 50);
// 只写入这个区域的数据...
}
7. 常见问题与解决方案
7.1 屏幕无显示或白屏
- 检查电源:确保VCC接3.3V,GND正确连接
- 检查背光:BLK引脚需要接高电平
- 检查复位信号:RES引脚上电时需要低脉冲
- 检查SPI接线:SCL和SDA不要接反
7.2 显示颜色异常
- 尝试不同的初始化模式(INITR_BLACKTAB/INITR_MINI160x80)
- 检查颜色格式设置(通常是16位RGB565)
- 确认MADCTL寄存器中的RGB顺序
7.3 显示内容错位
- 调整显示方向(setRotation函数)
- 检查屏幕分辨率设置是否正确
- 确认初始化序列是否适合你的屏幕型号
7.4 SPI通信问题
- 降低SPI时钟速度测试
- 检查CS片选信号是否正确
- 确认SPI模式设置(通常为模式0)
8. 实际项目应用示例
8.1 简易数字仪表盘
cpp复制void drawDashboard(float temp, float humi, int batt) {
tft.fillScreen(ST7735_BLACK);
// 绘制边框
tft.drawRoundRect(5, 5, 70, 70, 5, ST7735_WHITE);
// 显示温度
tft.setTextColor(ST7735_RED);
tft.setTextSize(2);
tft.setCursor(15, 15);
tft.print(temp, 1);
tft.println(" C");
// 显示湿度
tft.setTextColor(ST7735_BLUE);
tft.setCursor(15, 40);
tft.print(humi, 0);
tft.println(" %");
// 电池电量指示
int battWidth = map(batt, 0, 100, 0, 60);
tft.drawRect(10, 60, 60, 10, ST7735_WHITE);
tft.fillRect(10, 60, battWidth, 10, ST7735_GREEN);
}
8.2 波形显示实现
cpp复制#define HISTORY_SIZE 100
int waveData[HISTORY_SIZE];
void updateWaveform(int newValue) {
// 移动历史数据
for(int i=0; i<HISTORY_SIZE-1; i++) {
waveData[i] = waveData[i+1];
}
waveData[HISTORY_SIZE-1] = newValue;
// 重绘波形
tft.fillRect(0, 0, 128, 60, ST7735_BLACK);
for(int i=1; i<HISTORY_SIZE; i++) {
int y1 = map(waveData[i-1], 0, 1023, 60, 0);
int y2 = map(waveData[i], 0, 1023, 60, 0);
tft.drawLine(i-1, y1, i, y2, ST7735_GREEN);
}
}
9. 电源管理与低功耗设计
9.1 背光控制
cpp复制// PWM控制背光亮度
void setBacklight(uint8_t brightness) {
analogWrite(BLK_PIN, brightness);
}
// 在setup()中初始化PWM
pinMode(BLK_PIN, OUTPUT);
setBacklight(128); // 50%亮度
9.2 睡眠模式
ST7735支持睡眠模式以降低功耗:
cpp复制void enterSleepMode() {
tft.writecommand(ST7735_SLPIN);
delay(120); // 等待进入睡眠
}
void wakeUp() {
tft.writecommand(ST7735_SLPOUT);
delay(120); // 等待唤醒
}
10. 进阶开发建议
- 使用双缓冲技术减少闪烁:先在内存中绘制完整帧,再一次性写入屏幕
- 实现自定义字体:将字体数据存储在程序存储器中
- 添加触摸功能:如果屏幕支持触摸,可以结合XPT2046驱动开发交互界面
- 优化SPI DMA传输:在支持DMA的MCU上可以大幅提高刷新率
- 开发UI框架:基于状态机实现简单的用户界面系统
我在实际项目中发现,这种小屏幕最适合用来显示关键数据和简单状态。虽然尺寸有限,但合理设计界面后,信息传达效率非常高。特别是在电池供电的设备上,低功耗特性让它成为理想选择。