当前位置: 首页 > news >正文

ST7789驱动实战:从SPI时序到RGB565显存映射的完整解析

1. ST7789液晶屏驱动入门指南

第一次拿到ST7789液晶屏和STM32开发板时,我完全不知道从何下手。这块240x240分辨率的彩色屏幕看起来简单,但数据手册里密密麻麻的时序图和寄存器说明让人望而生畏。经过几天的摸索,我发现只要抓住几个关键点,就能让这块屏幕亮起来。

ST7789是一款采用SPI接口的TFT液晶驱动芯片,支持最高18位色深(RGB666),但最常用的是16位RGB565模式。它的核心功能可以概括为:通过SPI接收控制命令和图像数据,将数据存入内部GRAM(图形存储器),然后自动刷新到屏幕上显示。对于嵌入式开发者来说,重点需要关注三个部分:SPI通信时序、显示控制命令和GRAM操作。

我使用的硬件平台是STM32F103C8T6最小系统板,通过4线SPI(SCK、MOSI、DC、CS)连接ST7789。选择这个组合是因为STM32的硬件SPI性能稳定,而4线模式比3线模式操作更简单。在实际接线时,除了SPI信号线,别忘了连接RESET和背光控制引脚,这些在初始化阶段都很重要。

2. SPI时序配置详解

2.1 解读数据手册的SPI时序

打开ST7789数据手册的第36页,可以看到4线SPI接口的时序图。这里有几个关键参数需要注意:

  • CPOL(时钟极性)= 0:空闲时SCK保持低电平
  • CPHA(时钟相位)= 0:数据在时钟第一个边沿采样
  • 数据位顺序:MSB(高位)先传输
  • 最大SPI时钟频率:62.5MHz(实际使用建议不超过30MHz)

在STM32CubeMX中配置SPI时,这些参数对应以下设置:

hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; // 36MHz/2=18MHz

2.2 DC引脚的关键作用

ST7789的DC(Data/Command)引脚决定了传输的是命令还是数据:

  • DC=0:当前字节是命令(如设置显示模式)
  • DC=1:当前字节是数据(如像素颜色值)

这个引脚需要配合SPI时序精确控制。我通常这样实现发送函数:

void ST7789_SendCommand(uint8_t cmd) { HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1, &cmd, 1, HAL_MAX_DELAY); } void ST7789_SendData(uint8_t data) { HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_SET); HAL_SPI_Transmit(&hspi1, &data, 1, HAL_MAX_DELAY); }

3. 关键寄存器配置实战

3.1 显示方向控制(0x36命令)

数据手册第156页的0x36命令控制显示方向,这个寄存器特别重要:

/* * BIT7: MY - 行地址顺序 * BIT6: MX - 列地址顺序 * BIT5: MV - 行列交换 * BIT4: ML - 垂直刷新顺序 * BIT3: RGB - RGB/BGR顺序 * BIT2: MH - 水平刷新顺序 */ #define MADCTL_MY 0x80 #define MADCTL_MX 0x40 #define MADCTL_MV 0x20 #define MADCTL_ML 0x10 #define MADCTL_RGB 0x08 #define MADCTL_MH 0x04 // 常用配置:正常方向+RGB顺序 uint8_t madctl = MADCTL_RGB; ST7789_SendCommand(0x36); ST7789_SendData(madctl);

3.2 颜色模式设置(0x3A命令)

ST7789支持多种颜色格式,我们选择RGB565:

// 0x55: 16位/pixel (RGB565) // 0x66: 18位/pixel (RGB666) ST7789_SendCommand(0x3A); ST7789_SendData(0x55);

4. GRAM操作与图像显示

4.1 设置显示窗口

在写入像素数据前,必须设置显示窗口(行列地址):

void ST7789_SetWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { // 设置列地址 ST7789_SendCommand(0x2A); ST7789_SendData(x0 >> 8); ST7789_SendData(x0 & 0xFF); ST7789_SendData(x1 >> 8); ST7789_SendData(x1 & 0xFF); // 设置行地址 ST7789_SendCommand(0x2B); ST7789_SendData(y0 >> 8); ST7789_SendData(y0 & 0xFF); ST7789_SendData(y1 >> 8); ST7789_SendData(y1 & 0xFF); // 准备写入GRAM ST7789_SendCommand(0x2C); }

4.2 实现清屏函数

基于窗口设置,可以写出高效的清屏函数:

void ST7789_FillScreen(uint16_t color) { ST7789_SetWindow(0, 0, 239, 239); uint8_t data[2] = {color >> 8, color & 0xFF}; HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_SET); for(uint32_t i=0; i<240*240; i++) { HAL_SPI_Transmit(&hspi1, data, 2, HAL_MAX_DELAY); } } // 常用颜色定义 #define ST7789_BLACK 0x0000 #define ST7789_BLUE 0x001F #define ST7789_RED 0xF800 #define ST7789_GREEN 0x07E0 #define ST7789_WHITE 0xFFFF

5. 完整初始化流程

5.1 硬件复位序列

正确的上电时序对屏幕稳定工作至关重要:

void ST7789_Reset(void) { // 拉低复位引脚至少10us HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_RESET); HAL_Delay(20); HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_SET); HAL_Delay(120); // 等待120ms复位完成 }

5.2 完整的初始化代码

结合所有关键步骤的初始化函数:

void ST7789_Init(void) { ST7789_Reset(); // 退出睡眠模式 ST7789_SendCommand(0x11); HAL_Delay(120); // 颜色接口设置 ST7789_SendCommand(0x3A); ST7789_SendData(0x55); // RGB565 // 显示方向设置 ST7789_SendCommand(0x36); ST7789_SendData(0x00); // 正常方向 // 关闭反显 ST7789_SendCommand(0x21); // 显示开 ST7789_SendCommand(0x29); // 清屏为蓝色 ST7789_FillScreen(ST7789_BLUE); }

6. 性能优化技巧

6.1 使用DMA加速数据传输

当刷新全屏时,SPI传输可能成为瓶颈。使用DMA可以显著提升性能:

// 在CubeMX中启用SPI TX DMA void ST7789_FillScreen_DMA(uint16_t color) { ST7789_SetWindow(0, 0, 239, 239); static uint16_t buffer[240]; // 一行像素缓冲区 for(int i=0; i<240; i++) buffer[i] = color; HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_SET); for(int y=0; y<240; y++) { HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)buffer, 480); while(HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY); } }

6.2 部分刷新优化

只刷新变化区域可以大幅减少数据传输量:

void ST7789_UpdateRegion(uint16_t x0, uint16_t y0, uint16_t width, uint16_t height, uint16_t *pixels) { ST7789_SetWindow(x0, y0, x0+width-1, y0+height-1); HAL_GPIO_WritePin(DC_GPIO_Port, DC_Pin, GPIO_PIN_SET); HAL_SPI_Transmit(&hspi1, (uint8_t*)pixels, width*height*2, HAL_MAX_DELAY); }

7. 常见问题排查

7.1 屏幕显示异常

如果屏幕出现花屏、颜色错乱等问题,可以按以下步骤排查:

  1. 检查SPI时钟极性(CPOL)和相位(CPHA)设置
  2. 确认DC引脚电平切换时机正确
  3. 验证RGB颜色顺序设置(0x36命令的RGB位)
  4. 检查电源稳定性,ST7789需要稳定的3.3V供电

7.2 数据传输速度问题

当屏幕刷新率低时:

  1. 提高SPI时钟频率(但不要超过芯片规格)
  2. 使用DMA传输代替轮询模式
  3. 减少每次传输的数据量(如只刷新变化区域)
  4. 优化代码结构,减少不必要的延迟

我在实际项目中遇到过屏幕偶尔闪屏的问题,后来发现是电源线过长导致电压不稳。缩短电源线并增加一个100μF的电容后问题解决。另一个常见问题是SPI时钟速度过高导致数据错误,特别是在面包板连接时,建议初期使用较低时钟频率(如10MHz),稳定后再逐步提高。

http://www.cnnetsun.cn/news/1801464.html

相关文章:

  • GraspNet-API之Grasp Label数据结构解析与应用
  • MySQL性能优化新思路:Cosmos-Reason1-7B智能调参实践
  • 从零到一:C#集成YOLO26实战指南(原理剖析+性能优化+工程落地)
  • 从基础到高级:用C#开发YOLO26物体检测应用(全维度实战指南)
  • Bidili Generator变现指南:用SDXL模型创建被动收入流
  • 终极指南:如何用Unpaywall一键免费获取学术论文PDF
  • Omni-Vision Sanctuary 提示词(Prompt)工程入门:从基础到高级的调优策略
  • RAG效果总是不理想?试试Post-Retrieval后检索:重排序与上下文压缩的保姆级指南
  • 如何高效管理ComfyUI ControlNet Aux预处理节点:终极避坑指南与优化策略
  • SpringBoot项目如何对接XXLJob平台
  • x64dbg调试器完整教程:从零开始掌握Windows逆向分析核心技术
  • Cursor使用详解
  • ZED 2相机开箱即用指南:从硬件连接到第一个Python程序(打印序列号)
  • Paimon聚合引擎实战:5分钟搞定Flink实时销售看板(sum/max函数详解)
  • SunnyUI UILightState状态管理实战(从基础到交互)
  • Simulink | 【开源】基于自适应惯量阻尼的虚拟同步发电机(VSG)并网稳定性仿真
  • 手把手教你用C语言复现Matlab的wavedec和wrcoef函数(db4小波四层分解)
  • ssRadio:面向资源受限MCU的NRF24L01+轻量驱动库
  • 别再手写Verilog了!用Simulink HDL Coder快速搭建FPGA原型(附避坑指南)
  • 011、AI赋能传统行业:制造、医疗、金融的改造案例
  • 千问3.5-9B集成SpringBoot实战:构建企业级智能问答API服务
  • 网盘直链下载助手完整指南:轻松获取八大网盘真实下载地址的终极方案
  • Zotero-SciPDF:3分钟实现文献PDF自动下载的完整方案
  • 开源中国教育战略升级:构建AI时代全链条人才培养生态
  • Qwen3-0.6B快速上手:5分钟在Jupyter中调用LangChain对话机器人
  • 面向对象设计实战:如何用Java抽象类与接口模拟真实家居电路?
  • 5分钟快速入门:Wallpaper Engine资源逆向工程与格式转换完整指南
  • 墨语灵犀自动化办公实战:Python脚本批量处理文档与邮件
  • 终极指南:3分钟掌握植物大战僵尸PVZ Toolkit修改器
  • SDMatte多模态实践:结合CLIP模型实现文本引导的智能抠图