庆阳市网站建设_网站建设公司_网站建设_seo优化
2025/12/28 5:31:38 网站建设 项目流程

手把手教你用STM32CubeMX点亮ST7789屏幕:从配置到显示全解析

你有没有遇到过这种情况?买了一块漂亮的1.3寸TFT彩屏,接上STM32后却死活不亮——黑屏、花屏、白屏轮番上演。别急,问题大概率不在硬件,而是初始化时序和接口配置没踩对点

今天我们就来彻底解决这个“嵌入式入门拦路虎”:如何使用STM32CubeMX + HAL库快速、稳定地驱动ST7789显示屏。整个过程无需手写一行底层寄存器代码,也能做到一次点亮、长期稳定运行。


为什么是ST7789?

在琳琅满目的TFT驱动IC中(ILI9341、SSD1351、GC9A01…),ST7789近年来迅速走红,尤其是在国产小尺寸彩屏市场几乎成了标配。它到底强在哪?

核心优势一句话总结:

高分辨率 + 低成本 + 接口灵活 + 启动快

我们来看几个关键参数:

特性参数值
最大分辨率240×320(也有135×240等裁剪版)
色深16位 RGB565,65K色真彩
支持接口四线SPI / 8080并行总线
内置GRAM是,无需外部显存
显示方向控制通过MADCTL寄存器自由旋转

相比老将 ILI9341,ST7789 更适合现代小型化设备,比如智能手表、迷你仪表盘、WiFi配网界面等场景。而且它的初始化流程更短,唤醒响应更快,非常适合低功耗应用。


硬件怎么连?先搞清这五根线

ST7789模块通常引出以下关键引脚:

屏端引脚功能说明推荐连接MCU
VCC电源(3.3V)STM32 3.3V输出或LDO
GND共地
SCL / SCKSPI时钟PA5 或任意SPI_SCK
SDA / SI / MOSI数据输入PA7 或任意SPI_MOSI
CS片选(低有效)任意GPIO(如PB6)
DC / RS命令/数据选择任意GPIO(如PB7)
RST复位信号(低有效)任意GPIO(如PB8)
BLK / LED背光控制可接PWM调光或直接拉高

📌重点提醒
-DCCS极容易接反!记住:DC决定传的是命令还是像素数据,而CS只是片选使能。
- 如果发现屏幕完全无反应,请优先检查RST是否正常拉低再释放,并确保电源干净稳定。


STM32CubeMX 图形化配置实战

接下来进入正题。我们将以最常见的SPI + GPIO控制模式为例,带你一步步完成配置。

第一步:创建工程 & 选择芯片

打开 STM32CubeMX,新建项目,选择你的MCU型号(例如STM32F103C8T6、F407ZGT6等均可)。

第二步:启用SPI外设

找到 Pinout 视图,启用一个SPI主设备(推荐SPI1或SPI2)。设置如下:

  • Mode: Full Duplex Master
  • Frame Format: Motorola
  • Data Size: 8 bits
  • Clock Polarity (CPOL): Low
  • Clock Phase (CPHA): 1 Edge → 实际对应SPI MODE 0,0
  • NSS: Software(禁用硬件NSS)
  • Baud Rate Prescaler: fpclk / 16(初始调试建议不要太快)

✅ 为什么选 MODE 0,0?
大多数国产ST7789模组出厂默认使用 CPOL=0, CPHA=0,即空闲时SCK为低,在第一个上升沿采样。虽然手册说支持多种模式,但实际要以模块厂提供的例程为准。

第三步:配置控制引脚(CS/DC/RST)

这些不是SPI标准引脚,需要用普通GPIO模拟:

引脚名GPIO端口模式用户标签(User Label)
CSPB6Output Push PullLCD_CS
DCPB7Output Push PullLCD_DC
RSTPB8Output Push PullLCD_RST

在GPIO配置中给它们加上清晰的标签,生成代码后会自动定义对应的宏。

第四步:开启时钟 & 生成代码

进入 Clock Configuration 页面,确认SPI时钟来源合理(如APB2=72MHz,则SPI速率约为4.5MHz)。

最后点击Project Manager,设置工程名称、路径、工具链(Keil/IAR/CubeIDE),然后生成代码。


添加驱动代码:让屏幕真正“活起来”

CubeMX只帮你搭好架子,真正的灵魂还得靠我们自己加进去。

1. 新建lcd_st7789.h

#ifndef __LCD_ST7789_H #define __LCD_ST7789_H #include "main.h" #include "spi.h" // 分辨率定义(根据你的屏幕调整) #define LCD_WIDTH 240 #define LCD_HEIGHT 320 // 控制引脚宏定义(自动生成的变量名可能不同,请核对) #define LCD_CS_LOW() HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET) #define LCD_CS_HIGH() HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET) #define LCD_DC_CMD() HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_RESET) #define LCD_DC_DATA() HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET) #define LCD_RST_LOW() HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_RESET) #define LCD_RST_HIGH() HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_SET) // 函数声明 void LCD_Init(void); void LCD_Write_Cmd(uint8_t cmd); void LCD_Write_Data(uint8_t data); void LCD_Write_Buffer(uint8_t *buf, uint16_t len); void LCD_Set_Address(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); void LCD_Fill_Color(uint16_t color); #endif

2. 实现lcd_st7789.c

#include "lcd_st7789.h" #include <string.h> // 发送单个命令 void LCD_Write_Cmd(uint8_t cmd) { LCD_CS_LOW(); LCD_DC_CMD(); HAL_SPI_Transmit(&hspi1, &cmd, 1, HAL_MAX_DELAY); LCD_CS_HIGH(); } // 发送单个数据字节 void LCD_Write_Data(uint8_t data) { LCD_CS_LOW(); LCD_DC_DATA(); HAL_SPI_Transmit(&hspi1, &data, 1, HAL_MAX_DELAY); LCD_CS_HIGH(); } // 批量发送数据(用于填充像素) void LCD_Write_Buffer(uint8_t *buf, uint16_t len) { LCD_CS_LOW(); LCD_DC_DATA(); HAL_SPI_Transmit(&hspi1, buf, len, HAL_MAX_DELAY); LCD_CS_HIGH(); } // 初始化函数 —— 关键中的关键! void LCD_Init(void) { // 硬件复位 LCD_RST_LOW(); HAL_Delay(10); LCD_RST_HIGH(); HAL_Delay(120); // 退出睡眠模式 LCD_Write_Cmd(0x11); HAL_Delay(120); // 设置颜色格式为RGB565 LCD_Write_Cmd(0x3A); LCD_Write_Data(0x05); // 16-bit/pixel // Porch Control(厂商推荐值) LCD_Write_Cmd(0xB2); LCD_Write_Data(0x0C); LCD_Write_Data(0x0C); LCD_Write_Data(0x00); LCD_Write_Data(0x33); LCD_Write_Data(0x33); // Gate Control LCD_Write_Cmd(0xB7); LCD_Write_Data(0x35); // VCOM Setting LCD_Write_Cmd(0xBB); LCD_Write_Data(0x19); // LCM Control LCD_Write_Cmd(0xC0); LCD_Write_Data(0x2C); // Enable porch LCD_Write_Cmd(0xC2); LCD_Write_Data(0x01); // Vref trim LCD_Write_Cmd(0xC3); LCD_Write_Data(0x12); // VDV and VRH enable LCD_Write_Cmd(0xC4); LCD_Write_Data(0x20); // 帧率设置(正常模式下60Hz左右) LCD_Write_Cmd(0xC6); LCD_Write_Data(0x0F); // 电源控制1 LCD_Write_Cmd(0xD0); LCD_Write_Data(0xA4); LCD_Write_Data(0xA1); // 正向Gamma校正 LCD_Write_Cmd(0xE0); uint8_t posGamma[] = { 0xD0,0x04,0x0D,0x11,0x13,0x2B,0x3F,0x54, 0x4C,0x18,0x0D,0x0B,0x1F,0x23 }; LCD_Write_Buffer(posGamma, sizeof(posGamma)); // 负向Gamma校正 LCD_Write_Cmd(0xE1); uint8_t negGamma[] = { 0xD0,0x04,0x0C,0x11,0x13,0x2C,0x3F,0x44, 0x51,0x2F,0x1F,0x1F,0x20,0x23 }; LCD_Write_Buffer(negGamma, sizeof(negGamma)); // 开启显示反转(可选) LCD_Write_Cmd(0x21); // 进入正常显示模式 LCD_Write_Cmd(0x13); // 最终开启显示 LCD_Write_Cmd(0x29); HAL_Delay(10); }

💡注意细节
- Gamma表是厂家调好的色彩优化参数,不要随意修改;
-0x21表示开启显示反转,如果你的屏上下颠倒,可以尝试去掉或替换为0x20
- 初始化完成后必须发0x29才能真正点亮屏幕。


让屏幕动起来:画个彩色方块试试

添加一个简单的测试函数:

// 在 lcd_st7789.c 中添加 void LCD_Draw_Filled_Rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color) { uint16_t x_end = x + w - 1; uint16_t y_end = y + h - 1; LCD_Set_Address(x, y, x_end, y_end); uint8_t color_buf[2]; color_buf[0] = color >> 8; color_buf[1] = color; uint8_t pixel[2] = {color_buf[0], color_buf[1]}; uint32_t total_pixels = w * h; LCD_CS_LOW(); LCD_DC_DATA(); for (uint32_t i = 0; i < total_pixels; i++) { HAL_SPI_Transmit(&hspi1, pixel, 2, HAL_MAX_DELAY); } LCD_CS_HIGH(); } // 设置显示区域 void LCD_Set_Address(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { LCD_Write_Cmd(0x2A); // Column Address Set LCD_Write_Data(x1 >> 8); LCD_Write_Data(x1 & 0xFF); LCD_Write_Data(x2 >> 8); LCD_Write_Data(x2 & 0xFF); LCD_Write_Cmd(0x2B); // Row Address Set LCD_Write_Data(y1 >> 8); LCD_Write_Data(y1 & 0xFF); LCD_Write_Data(y2 >> 8); LCD_Write_Data(y2 & 0xFF); LCD_Write_Cmd(0x2C); // Memory Write }

然后在main.cwhile循环前加入测试代码:

LCD_Init(); LCD_Draw_Filled_Rect(50, 50, 100, 100, 0xF800); // 红色矩形(RGB565: 11111 000000 00000)

编译下载,如果一切顺利,你应该能看到屏幕上出现一块醒目的红色区域!


常见坑点与调试秘籍

即使按步骤操作,也难免遇到问题。以下是我在多个项目中总结的“排雷清单”:

🔴 黑屏无反应?

  • ✅ 检查供电是否达到3.3V且无压降;
  • ✅ RST是否真的完成了“拉低→延时→拉高”全过程;
  • ✅ 使用示波器抓SCK和MOSI,看是否有数据发出。

🟡 花屏、乱码?

  • ✅ 确认SPI模式是否为 MODE 0,0(CPOL=0, CPHA=0);
  • ✅ 尝试降低SPI速率(把Prescaler从÷4改成÷16);
  • ✅ 检查DC引脚电平是否正确切换。

🟢 白屏但无内容?

  • ✅ 初始化命令未成功发送,重点排查CS和DC控制逻辑;
  • ✅ 可临时将所有写操作强制设为DATA模式,观察是否变为全彩噪点(验证通信通路)。

🔄 显示倒置或镜像?

加一句即可修复:

LCD_Write_Cmd(0x36); LCD_Write_Data(0x70); // 旋转90度(其他值见下表)
数据值显示方向
0x00
0x6090°
0xC0180°
0xA0270°

性能优化建议(进阶必看)

当你已经能稳定显示内容后,下一步就是提升体验:

✅ 启用DMA传输

对于大量像素数据(如图片刷屏),使用DMA可极大减轻CPU负担:

HAL_SPI_Transmit_DMA(&hspi1, buffer, size);

记得开启DMA中断并在回调中释放CS。

✅ 局部刷新替代全屏重绘

只更新变化区域,显著提高帧率和降低功耗。

✅ 结合FreeRTOS做异步渲染

把UI绘制放在独立任务中,避免阻塞主逻辑。

✅ 预留多分辨率支持

通过宏定义切换不同屏幕尺寸:

#ifdef ST7789_135_240 #define LCD_WIDTH 135 #define LCD_HEIGHT 240 #elif defined(ST7789_240_320) #define LCD_WIDTH 240 #define LCD_HEIGHT 320 #endif

写在最后:不只是点亮,更是起点

当那个小小的彩屏第一次亮起,你会发现——这不仅仅是一次成功的硬件对接,更是通往图形化人机交互世界的大门被推开。

掌握了 ST7789 的驱动方法,你就拥有了构建完整GUI系统的基石。下一步,你可以轻松集成:
-LVGL:轻量级开源GUI框架,支持按钮、滑条、动画;
-TouchGFX:ST官方高级图形引擎,媲美手机UI;
- 自定义菜单系统、实时曲线绘制、二维码生成……

而这一切的起点,就是你现在看到的这几行初始化代码。

所以,别再让屏幕躺在角落吃灰了。打开CubeMX,接好线,跑一遍代码——下一秒,属于你的彩色界面就要诞生了。

如果你在实现过程中遇到了其他挑战,欢迎在评论区分享讨论。我们一起把每一块屏幕都点亮。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询