针对 TFT 彩屏 GUI 开发,最稳妥的方案是 "底层驱动 + 中间件 + 应用 API" 三层结构。
一、推荐方案组合
| 方案 | 适用 MCU | RAM 需求 | 效果 |
|---|---|---|---|
| LVGL + 屏驱 | F4 / G4 / H7 | ≥ 16KB | 手机级 UI |
| STemWin | STM32 全系 | ≥ 8KB | 工业稳定 |
| TFT_eSPI | ESP32 / ESP8266 | 低 | 快速原型 |
| 自制 GUI | 51 / F103 | 极低 | 简单按钮 |
建议 :STM32F407 及以上直接用 LVGL ;F103 用 STemWin 或精简版 LVGL。
二、底层驱动源码(以 ILI9341 为例)
1、 硬件接口定义(SPI)
c
#define TFT_CS_PIN GPIO_PIN_4
#define TFT_DC_PIN GPIO_PIN_5
#define TFT_RST_PIN GPIO_PIN_6
#define TFT_PORT GPIOA
2、 写命令 / 写数据(底层核心)
c
void TFT_WriteCmd(uint8_t cmd)
{
HAL_GPIO_WritePin(TFT_DC_PORT, TFT_DC_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(TFT_CS_PORT, TFT_CS_PIN, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1, &cmd, 1, 10);
HAL_GPIO_WritePin(TFT_CS_PORT, TFT_CS_PIN, GPIO_PIN_SET);
}
void TFT_WriteData(uint8_t dat)
{
HAL_GPIO_WritePin(TFT_DC_PORT, TFT_DC_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(TFT_CS_PORT, TFT_CS_PIN, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1, &dat, 1, 10);
HAL_GPIO_WritePin(TFT_CS_PORT, TFT_CS_PIN, GPIO_PIN_SET);
}
3、 设置显示窗口(GUI 必用)
c
void TFT_SetWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
TFT_WriteCmd(0x2A); // Column Address Set
TFT_WriteData(x0 >> 8); TFT_WriteData(x0 & 0xFF);
TFT_WriteData(x1 >> 8); TFT_WriteData(x1 & 0xFF);
TFT_WriteCmd(0x2B); // Page Address Set
TFT_WriteData(y0 >> 8); TFT_WriteData(y0 & 0xFF);
TFT_WriteData(y1 >> 8); TFT_WriteData(y1 & 0xFF);
TFT_WriteCmd(0x2C); // Memory Write
}
4、 画点 / 填充(GUI 基础函数)
c
void TFT_DrawPixel(uint16_t x, uint16_t y, uint16_t color)
{
TFT_SetWindow(x, y, x, y);
TFT_WriteData(color >> 8);
TFT_WriteData(color & 0xFF);
}
void TFT_Fill(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color)
{
uint32_t i, total = (x1 - x0 + 1) * (y1 - y0 + 1);
TFT_SetWindow(x0, y0, x1, y1);
for(i = 0; i < total; i++)
{
TFT_WriteData(color >> 8);
TFT_WriteData(color & 0xFF);
}
}
三、GUI 基础函数(自建简易 UI)
1、 画矩形 / 按钮
c
void GUI_DrawButton(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color)
{
TFT_Fill(x, y, x + w - 1, y + h - 1, color);
}
2、 显示字符(ASCII 8x16)
c
void GUI_DrawChar(uint16_t x, uint16_t y, uint8_t chr, uint16_t color)
{
uint8_t i, j;
uint8_t temp;
for(i = 0; i < 16; i++)
{
temp = ascii_8x16[chr * 16 + i];
for(j = 0; j < 8; j++)
{
if(temp & (0x80 >> j))
TFT_DrawPixel(x + j, y + i, color);
}
}
}
3、 触摸校准(XPT2046)
c
typedef struct
{
uint16_t x;
uint16_t y;
} TouchPoint;
TouchPoint TP_GetPoint(void)
{
TouchPoint p;
p.x = XPT2046_Read(XP);
p.y = XPT2046_Read(YP);
return p;
}
四、LVGL 移植核心代码(工业级 GUI )
1、 显示刷新回调
c
void my_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
TFT_SetWindow(area->x1, area->y1, area->x2, area->y2);
uint32_t size = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1);
HAL_SPI_Transmit(&hspi1, (uint8_t *)color_p, size * 2, 100);
lv_disp_flush_ready(disp);
}
2、 心跳节拍(1ms)
c
void HAL_SYSTICK_Callback(void)
{
lv_tick_inc(1);
}
参考代码 TFT彩屏GUI函数和驱动源码 www.youwenfan.com/contentcst/182151.html
五、常用颜色定义
c
#define RED 0xF800
#define GREEN 0x07E0
#define BLUE 0x001F
#define WHITE 0xFFFF
#define BLACK 0x0000
#define YELLOW 0xFFE0
六、调试与性能优化
| 问题 | 解决 |
|---|---|
| 花屏 | 检查 SPI 速率(≤ 40MHz) |
| 刷屏慢 | 开启 DMA |
| 触摸不准 | 四点校准 |
| 内存不足 | 减少 LVGL 缓冲区 |
性能提升技巧:
- 使用 DMA + SPI
- 双缓冲机制
- 局部刷新(Partial Update)