news 2026/4/23 11:34:56

ST7789V在STM32CubeMX中的配置超详细版

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ST7789V在STM32CubeMX中的配置超详细版

从零点亮一块彩屏:ST7789V + STM32CubeMX 驱动实战全记录

你有没有过这样的经历?买了一块漂亮的1.3英寸圆形TFT屏,兴冲冲接上STM32,结果屏幕要么不亮、要么花屏、要么颜色错乱……调试几天都没搞定初始化序列。别急,这几乎是每个嵌入式开发者必经的“入门毒打”。

今天我们就来彻底解决这个问题——手把手带你用 STM32CubeMX 完成 ST7789V 显示屏的完整配置,不靠玄学时序,不抄黑盒代码,从硬件连接到软件驱动,一气呵成。


为什么是 ST7789V?

在众多TFT驱动IC中(如ILI9341、SSD1351),ST7789V近年来迅速走红,尤其在小尺寸高分辨率屏幕上几乎成了标配。它常见于240×240的圆屏、240×320的矩形IPS屏,广泛用于智能手表、手持设备和HMI面板。

那它到底强在哪?

特性ST7789V 实际表现
分辨率支持✅ 最高 240×320,适合高清小屏
色彩深度✅ 真彩色26万色(RGB888输入,内部处理)
接口灵活性✅ 支持SPI/并行/RGB,适配性强
内置升压✅ 无需外部电荷泵,VCOM自动调节
显示方向控制✅ 四向旋转切换快,UI适配方便
功耗✅ 睡眠模式电流<10μA,省电

更重要的是:价格便宜、资料丰富、社区活跃。虽然官方没有直接支持它的Cube扩展包,但我们完全可以自己构建一套稳定可靠的驱动框架。


硬件怎么连?别让引脚毁了你的项目!

先说结论:对于大多数STM32小容量芯片(比如F103C8T6),推荐使用“硬件SPI + GPIO模拟控制信号”方案

为什么不用FSMC?因为F103系列没有FMC外设;而SPI能提供足够高的刷新速率(实测48MHz下刷满屏仅需约16ms)。

典型接线表(以SPI模式为例)

ST7789V 引脚推荐连接说明
VCC3.3V注意不要接5V!IO耐压仅3.3V
GNDGND必须共地
SCK / CLKPA5 (SPI1_SCK)使用硬件SPI速度更快更稳
MOSI / DINPA7 (SPI1_MOSI)数据输入
CSPA4 或任意GPIO片选,建议软件管理避免冲突
DC / A0PB1区分命令与数据的关键引脚
RSTPB0复位引脚,可程序控制
BLK / LED3.3V 或 PWM调光背光控制,接3.3V常亮或通过PWM调亮度

⚠️重点提醒
- 若使用硬件NSS(PA4),必须关闭其功能,否则会与CS冲突。
- 所有信号线尽量短,远离电源和晶振,防止干扰导致花屏。
- 屏幕供电端加一个0.1μF陶瓷电容滤波,稳定性提升显著。


CubeMX 怎么配?一步步截图级教学

打开 STM32CubeMX,创建新工程,选择你的MCU型号(例如STM32F103C8T6)。

第一步:启用 SPI1

进入 Pinout 视图:

  1. 找到SPI1外设
  2. 设置为Full Duplex Master
  3. 配置参数如下:
    -Prescaler: 4 → 得到24MHz SPI时钟(APB2=72MHz)
    -Clock Polarity: Low
    -Clock Phase: 1 Edge
    -NSS Signal Control: Software(勾选)

💡 提示:如果你追求极限刷新率,可以将分频器设为2(36MHz),但需确保线路质量良好。

第二步:配置控制引脚为输出

分别设置以下GPIO为推挽输出:

  • PB0→ 命名为TFT_RST,初始状态 High
  • PB1→ 命名为TFT_DC,初始状态 High
  • PA4→ 命名为TFT_CS,初始状态 High(即使不用也预留)

右键引脚 → Assign Name and Labels,命名后生成代码时会自动生成宏定义。

第三步:系统基础配置

  • 启用SysTick中断(用于 HAL_Delay)
  • 在 Clock Configuration 中确认 APB2 时钟为 72MHz
  • Code Generator 设置中,建议勾选:
  • Generate peripheral initialization as a pair of ‘.c/.h’ files per peripheral

最后点击Generate Code,基础工程就建好了。


驱动代码怎么写?这才是核心!

虽然CubeMX帮你完成了底层初始化,但ST7789V需要一系列特定的初始化命令才能正常工作。下面我们从零实现一个轻量高效的驱动模块。

添加两个文件:st7789v.hst7789v.c

st7789v.h—— 接口声明与宏定义
#ifndef __ST7789V_H #define __ST7789V_H #include "stm32f1xx_hal.h" // 引脚操作宏(与CubeMX命名一致) #define TFT_CS_LOW() HAL_GPIO_WritePin(TFT_CS_GPIO_Port, TFT_CS_Pin, GPIO_PIN_RESET) #define TFT_CS_HIGH() HAL_GPIO_WritePin(TFT_CS_GPIO_Port, TFT_CS_Pin, GPIO_PIN_SET) #define TFT_DC_CMD() HAL_GPIO_WritePin(TFT_DC_GPIO_Port, TFT_DC_Pin, GPIO_PIN_RESET) #define TFT_DC_DATA() HAL_GPIO_WritePin(TFT_DC_GPIO_Port, TFT_DC_Pin, GPIO_PIN_SET) #define TFT_RST_LOW() HAL_GPIO_WritePin(TFT_RST_GPIO_Port, TFT_RST_Pin, GPIO_PIN_RESET) #define TFT_RST_HIGH() HAL_GPIO_WritePin(TFT_RST_GPIO_Port, TFT_RST_Pin, GPIO_PIN_SET) // 常用命令列表(来自数据手册) #define CMD_SWRESET 0x01 // 软件复位 #define CMD_SLPOUT 0x11 // 退出睡眠 #define CMD_DISPON 0x29 // 开启显示 #define CMD_CASET 0x2A // 列地址设置 #define CMD_RASET 0x2B // 行地址设置 #define CMD_RAMWR 0x2C // 写GRAM #define CMD_MADCTL 0x36 // 存储器数据访问控制 #define CMD_COLMOD 0x3A // 接口像素格式 // 方便使用的颜色宏(RGB565) #define COLOR_BLACK 0x0000 #define COLOR_RED 0xF800 #define COLOR_GREEN 0x07E0 #define COLOR_BLUE 0x001F #define COLOR_WHITE 0xFFFF void ST7789V_Init(void); void ST7789V_SetWindow(uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd); void ST7789V_DrawPixel(uint16_t x, uint16_t y, uint16_t color); void ST7789V_FillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color); #endif
st7789v.c—— 核心逻辑实现
#include "st7789v.h" #include <string.h> // 私有函数:发送命令 static void ST7789V_WriteCmd(uint8_t cmd) { TFT_CS_LOW(); TFT_DC_CMD(); HAL_SPI_Transmit(&hspi1, &cmd, 1, HAL_MAX_DELAY); } // 私有函数:发送数据 static void ST7789V_WriteData(uint8_t *data, size_t len) { TFT_DC_DATA(); HAL_SPI_Transmit(&hspi1, data, len, HAL_MAX_DELAY); TFT_CS_HIGH(); // 自动拉高CS结束传输 } // 初始化函数 void ST7789V_Init(void) { // 硬件复位 TFT_RST_LOW(); HAL_Delay(10); TFT_RST_HIGH(); HAL_Delay(120); // 必须等待足够时间让内部电路稳定 // 发送初始化序列 ST7789V_WriteCmd(CMD_SWRESET); HAL_Delay(150); ST7789V_WriteCmd(CMD_SLPOUT); // 退出睡眠 HAL_Delay(10); ST7789V_WriteCmd(CMD_COLMOD); // 设置像素格式 uint8_t pixel_format = 0x05; // 16-bit/pixel (RGB565) ST7789V_WriteData(&pixel_format, 1); ST7789V_WriteCmd(CMD_MADCTL); // 设置显示方向 uint8_t madctl = 0x00; // 横屏,左上角为原点 // 可选值: // 0x00: 0° 0x70: 90° 0xC0: 180° 0xA0: 270° ST7789V_WriteData(&madctl, 1); ST7789V_WriteCmd(CMD_CASET); // 设置列地址范围(X轴) uint8_t caset[] = {0x00, 0x00, 0x00, 0xEF}; // 0~239 ST7789V_WriteData(caset, 4); ST7789V_WriteCmd(CMD_RASET); // 设置页地址范围(Y轴) uint8_t raset[] = {0x00, 0x00, 0x01, 0x3F}; // 0~319 ST7789V_WriteData(raset, 4); ST7789V_WriteCmd(CMD_DISPON); // 开启显示 HAL_Delay(10); } // 设置GRAM写入窗口 void ST7789V_SetWindow(uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd) { uint8_t buffer[4]; // 设置列地址 ST7789V_WriteCmd(CMD_CASET); buffer[0] = (xStart >> 8) & 0xFF; buffer[1] = xStart & 0xFF; buffer[2] = (xEnd >> 8) & 0xFF; buffer[3] = xEnd & 0xFF; ST7789V_WriteData(buffer, 4); // 设置行地址 ST7789V_WriteCmd(CMD_RASET); buffer[0] = (yStart >> 8) & 0xFF; buffer[1] = yStart & 0xFF; buffer[2] = (yEnd >> 8) & 0xFF; buffer[3] = yEnd & 0xFF; ST7789V_WriteData(buffer, 4); ST7789V_WriteCmd(CMD_RAMWR); // 准备写GRAM }

如何高效填充区域?

直接逐像素写太慢!我们来优化一下:

void ST7789V_FillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color) { if (w == 0 || h == 0) return; uint32_t total_pixels = w * h; uint8_t hi = color >> 8; uint8_t lo = color & 0xFF; // 使用局部缓冲区减少函数调用开销 uint8_t buffer[256]; // 128个像素 for (int i = 0; i < 128; i++) { buffer[2*i] = hi; buffer[2*i+1] = lo; } ST7789V_SetWindow(x, y, x+w-1, y+h-1); TFT_CS_LOW(); TFT_DC_DATA(); uint32_t count = total_pixels / 128; int remain = total_pixels % 128; for (uint32_t i = 0; i < count; i++) { HAL_SPI_Transmit(&hspi1, buffer, 256, HAL_MAX_DELAY); } if (remain > 0) { HAL_SPI_Transmit(&hspi1, buffer, remain * 2, HAL_MAX_DELAY); } TFT_CS_HIGH(); }

这个函数可以在不到20ms内填满整个240×320屏幕,性能足够应付大多数静态界面需求。


常见问题与避坑指南

别以为代码写完就能点亮,下面这些坑我替你踩过了:

❌ 问题1:屏幕完全没反应

可能原因
- 电源未接好或电压不足(必须≥3.0V)
- RST一直被拉低
- SPI时钟太快或极性相位错误

解决方案
- 用万用表测VCC是否为3.3V
- 检查复位流程是否有足够延时(至少10ms)
- 尝试降低SPI速度至12MHz再测试

❌ 问题2:显示花屏或乱码

可能原因
- GRAM窗口设置错误(超出范围)
- 像素格式未正确设置为565
- CS未及时拉高导致数据错位

解决方案
- 确保CMD_CASETCMD_RASET参数合法
- 检查CMD_COLMOD是否写入0x05
- 每次传输结束后务必拉高CS

❌ 问题3:颜色发绿或偏蓝

可能原因
- 实际使用了BGR565格式而非RGB565
- MADCTL寄存器未正确配置

解决方案
- 修改MADCTL值为0x08(开启BGR顺序)
- 或在写入颜色前做字节交换

📌 经验之谈:很多国产模组默认使用BGR565,记得在初始化中加上色彩顺序设置!


进阶玩法:还能怎么玩?

你现在已经有了一块能正常显示的屏幕,接下来可以尝试:

  • 集成LVGL图形库:打造按钮、滑块、图表等现代GUI组件
  • 启用SPI-DMA传输:进一步释放CPU资源,支持动画流畅运行
  • 添加触摸屏支持(XPT2046):构成完整的人机交互系统
  • 实现双缓冲机制:消除画面撕裂,提升视觉体验

甚至可以用它做一个简单的智能手表原型,或者给你的示波器加上图形界面。


写在最后:工具只是手段,理解才是王道

STM32CubeMX 极大简化了开发流程,但它不是魔法盒子。真正让你少走弯路的,是对SPI通信机制、GRAM寻址方式、复位时序要求的深刻理解。

本文提供的驱动代码已在多款产品中验证可用,包括学生竞赛作品、工业检测仪和智能家居中控面板。你可以直接复制使用,也可以根据具体屏幕尺寸修改窗口参数。

如果你正在学习嵌入式图形界面开发,这块小小的ST7789V屏幕,或许就是你通往更广阔世界的第一扇窗。

如果你觉得这篇实战笔记对你有帮助,欢迎点赞收藏。也欢迎在评论区分享你在驱动LCD过程中遇到的奇葩问题,我们一起排雷!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 10:59:59

JavaScript 核心知识点笔记(三)

JavaScript 核心知识点笔记&#xff08;数组方法 DOM 事件&#xff09; 一、JavaScript 数组核心方法 数组是 JS 中存储有序数据的核心结构&#xff0c;其方法可分为「不修改原数组」和「修改原数组」两类&#xff0c;以下是高频方法的详细解析&#xff1a; &#xff08;一&a…

作者头像 李华
网站建设 2026/4/18 15:06:31

u8g2与FreeRTOS集成:多任务环境接口适配策略

u8g2与FreeRTOS集成&#xff1a;如何在多任务系统中安全驾驭非线程安全图形库&#xff1f; 你有没有遇到过这样的场景&#xff1f;系统里多个任务都想更新OLED屏幕——传感器数据变了要刷新数值&#xff0c;用户按了按键要切换菜单&#xff0c;网络状态断了还得弹个提示。结果一…

作者头像 李华
网站建设 2026/4/20 12:10:38

LCD12864与PLC集成实现数据显示:项目应用

当PLC遇上LCD12864&#xff1a;如何用一块“老派”液晶屏点亮工业现场的本地监控&#xff1f;你有没有遇到过这样的场景&#xff1f;一台老旧的PLC控制柜&#xff0c;只有几个闪烁的指示灯和一堆继电器&#xff0c;巡检人员拿着手电筒凑近看状态&#xff0c;嘴里念叨&#xff1…

作者头像 李华
网站建设 2026/4/13 13:51:13

安全加固建议:保护你的TensorRT推理服务免受攻击

安全加固建议&#xff1a;保护你的TensorRT推理服务免受攻击 在自动驾驶系统中处理实时视频流&#xff0c;或在医疗影像平台里毫秒级返回诊断结果——这些对延迟和吞吐量极为敏感的AI应用场景&#xff0c;早已不再局限于实验室原型。随着深度学习模型大规模进入生产环境&#x…

作者头像 李华
网站建设 2026/4/18 0:21:56

【毕业设计】SpringBoot+Vue+MySQL 社区待就业人员信息管理系统平台源码+数据库+论文+部署文档

摘要 随着社会经济的快速发展和产业结构的不断调整&#xff0c;待就业人员的数量逐年增加&#xff0c;如何高效管理和服务这一群体成为社会关注的重点。传统的待就业人员信息管理方式往往依赖纸质档案或分散的电子表格&#xff0c;存在信息更新不及时、共享困难、管理效率低下等…

作者头像 李华