news 2026/6/13 23:21:59

ST7735命令集解析及其在STM32中的调用方式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ST7735命令集解析及其在STM32中的调用方式

深入理解ST7735命令集:从寄存器操作到STM32实战驱动

你有没有遇到过这样的情况?明明代码烧录成功,SPI通信也看似正常,但屏幕就是一片白屏、花屏,或者显示方向完全错乱。在调试这类问题时,很多人第一反应是“换库”或“照抄例程”,结果却治标不治本。

其实,根本原因往往出在对ST7735 命令集机制的理解不足上。这款被广泛用于1.8英寸TFT屏的控制器,并不像GPIO外设那样“即写即显”。它的一切行为——从初始化、旋转、色彩格式设置,到最终像素呈现——都依赖于一套精确的命令-数据协议。只有掌握这套底层语言,才能真正掌控显示效果,而不是被“黑盒驱动”牵着鼻子走。

本文将带你彻底拆解 ST7735 的工作原理,结合 STM32 实际工程场景,手把手教你如何通过直接调用命令寄存器,构建一个高效、稳定、可移植的LCD驱动框架。


为什么必须读懂ST7735的“命令语言”?

ST7735 不是一个简单的内存映射设备。它更像是一个拥有自己“操作系统”的微型处理器,而我们主控MCU的任务,就是按照它的“语法规则”发送指令和参数。

命令与数据:D/C 引脚决定一切

关键就在于那个不起眼的D/C(Data/Command)引脚。这个引脚的状态,决定了SPI总线上接下来传输的是“命令”还是“数据”。

  • D/C = 0:告诉ST7735:“下一个字节是你要执行的操作码。”
  • D/C = 1:告诉ST7735:“接下来的是参数或像素数据。”

比如,你想设置屏幕显示方向,流程如下:
1. 拉低片选(CS)
2. 设置 D/C = 0 → 表示要发命令
3. 发送命令字节0x36(MADCTL,内存访问控制)
4. 设置 D/C = 1 → 表示要发数据
5. 发送参数字节(如0xC0表示180°旋转)
6. 拉高CS,结束

这种机制虽然增加了软件复杂度,但也带来了极高的灵活性——你可以精细控制每一个显示参数。

常见痛点:为什么“照搬例程”常翻车?

很多初学者直接使用别人封装好的驱动库,一旦换一块屏幕或MCU型号稍有不同,就出现白屏、乱码等问题。究其原因:

  • 初始化序列中某个延时不够;
  • MADCTL 配置与实际屏幕贴合方向不符;
  • SPI 模式(CPOL/CPHA)配置错误;
  • 忘记等待睡眠退出后的稳定时间(≥120ms)。

这些问题,只有当你真正理解每一条命令的作用,才能快速定位并修复。


核心命令集速览:ST7735最常用的几个“动词”

不必死记所有100多个命令,先掌握这几个最关键的,就能解决90%的日常需求。

命令 (Hex)名称功能说明是否需要参数
0x01SWRESET软件复位,重启控制器
0x11SLPOUT退出睡眠模式
0x29DISPON开启显示
0x2ACASET设置列地址范围(X轴)是(4字节)
0x2BRASET设置行地址范围(Y轴)是(4字节)
0x2CRAMWR写GRAM,开始传输像素数据是(N×2字节)
0x36MADCTL控制显示方向、镜像、RGB/BGR顺序是(1字节)
0x3ACOLMOD设置色彩格式(如16位RGB565)是(1字节)
0xB1FRMCTR1帧率控制(普通模式)是(3字节)

⚠️ 注意:部分命令后必须加延时!例如SLPOUT后需至少延时120ms才能继续发送其他命令,否则可能导致初始化失败。


在STM32上搭建驱动骨架:从硬件连接到基础函数

我们以 STM32F103 系列为例,使用 HAL 库 + SPI1 实现驱动。

硬件连接(SPI四线模式)

ST7735 引脚连接 STM32 引脚功能说明
SCKPB3 (SPI1_SCK)时钟信号
MOSIPB5 (SPI1_MOSI)主机输出
CSPC3片选,低电平有效
DCPC2数据/命令选择
RESPC1复位,低电平有效
VCC/GND3.3V/GND供电
BLKPC4 (PWM)背光控制(可选)

✅ 推荐使用硬件SPI,避免GPIO模拟带来的时序抖动。

SPI 配置要点

// SPI1 初始化(Mode 0, 10MHz 初始频率) hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; // CPOL=0 hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; // CPHA=0 hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; // 72MHz/8 = 9MHz

🔔 提示:初始化阶段建议使用较低频率(≤10MHz),待屏幕稳定后可通过修改预分频器提升至 20~27MHz 以提高刷新率。


封装核心传输函数:让命令调用更清晰

为了提高代码可读性和复用性,我们需要封装两个基本操作函数。

#include "stm32f1xx_hal.h" // 引脚宏定义(根据实际电路调整) #define TFT_CS_PORT GPIOC #define TFT_CS_PIN GPIO_PIN_3 #define TFT_DC_PORT GPIOC #define TFT_DC_PIN GPIO_PIN_2 #define TFT_RES_PORT GPIOC #define TFT_RES_PIN GPIO_PIN_1 // 快捷宏 #define SELECT() HAL_GPIO_WritePin(TFT_CS_PORT, TFT_CS_PIN, GPIO_PIN_RESET) #define DESELECT() HAL_GPIO_WritePin(TFT_CS_PORT, TFT_CS_PIN, GPIO_PIN_SET) #define CMD() HAL_GPIO_WritePin(TFT_DC_PORT, TFT_DC_PIN, GPIO_PIN_RESET) #define DATA() HAL_GPIO_WritePin(TFT_DC_PORT, TFT_DC_PIN, GPIO_PIN_SET) extern SPI_HandleTypeDef hspi1; /** * @brief 发送单个命令字节 */ void lcd_write_cmd(uint8_t cmd) { SELECT(); CMD(); HAL_SPI_Transmit(&hspi1, &cmd, 1, 100); DESELECT(); } /** * @brief 发送多个数据字节 */ void lcd_write_data(uint8_t *buf, size_t len) { SELECT(); DATA(); HAL_SPI_Transmit(&hspi1, buf, len, HAL_MAX_DELAY); DESELECT(); } /** * @brief 发送带参数的命令(常用组合) */ void lcd_send_command(uint8_t cmd, uint8_t *data, size_t len) { lcd_write_cmd(cmd); if (len > 0) { lcd_write_data(data, len); } }

这些函数构成了整个驱动的基础。后续所有高级功能都将基于它们实现。


初始化流程详解:别再盲目复制粘贴了!

很多开发者直接把网上找来的初始化序列扔进项目,却不明白每一行的意义。下面是一段经过验证的ST7735S 初始化代码,并附带详细注释。

void st7735_init(void) { // === 步骤1:硬件复位 === HAL_GPIO_WritePin(TFT_RES_PORT, TFT_RES_PIN, GPIO_PIN_RESET); HAL_Delay(10); // 至少保持10ms低电平 HAL_GPIO_WritePin(TFT_RES_PORT, TFT_RES_PIN, GPIO_PIN_SET); HAL_Delay(120); // 等待内部电路稳定 // === 步骤2:退出睡眠模式 === lcd_write_cmd(0x11); // SLPOUT HAL_Delay(120); // 关键!必须等待 ≥120ms // === 步骤3:帧率设置(正常模式)=== uint8_t frmctr1[] = {0x01, 0x2C, 0x2D}; lcd_send_command(0xB1, frmctr1, 3); // === 步骤4:显示反转控制 === uint8_t invctrl[] = {0x07}; lcd_send_command(0xB4, invctrl, 1); // 改变部分行反转 // === 步骤5:电源控制设置 === uint8_t pwctrl[] = {0xA2, 0x02, 0x84}; // AVDD=4.6V, AVEE=-4.6V, VDS=2.6V lcd_send_command(0xC0, pwctrl, 3); // === 步骤6:VCOM控制 === uint8_t vmctrl[] = {0x0A, 0x00}; lcd_send_command(0xC5, vmctrl, 2); // === 步骤7:设置MADCTL(关键!控制显示方向)=== lcd_write_cmd(0x36); uint8_t madctl = 0xC0; // MY=0, MX=1, MV=1, ML=0 → 180°旋转 lcd_write_data(&madctl, 1); // === 步骤8:设置色彩格式为16位(RGB565)=== lcd_write_cmd(0x3A); uint8_t colmod = 0x05; lcd_write_data(&colmod, 1); // === 步骤9:使能内部升压电路 === lcd_write_cmd(0xF2); uint8_t enable_tf = {0x02}; lcd_write_data(&enable_tf, 1); // === 步骤10:伽马校正设置(典型值)=== uint8_t gamma_p[] = {0x05, 0x3C, 0x30, 0x3C, 0x0F, 0x0F, 0x33, 0x33}; uint8_t gamma_n[] = {0x00, 0x3C, 0x30, 0x3C, 0x0F, 0x0F, 0x33, 0x33}; lcd_send_command(0xE0, gamma_p, 8); // 正极性 lcd_send_command(0xE1, gamma_n, 8); // 负极性 // === 步骤11:开启显示 === lcd_write_cmd(0x29); // DISPON }

📌重点说明
-0x36(MADCTL)是控制显示方向的核心。常见取值如下:
-0x00:0°(默认)
-0x60:90°
-0xC0:180°
-0xA0:270°
- 若你的屏幕显示倒置或左右翻转,优先检查此项。
- 伽马设置影响色彩饱和度和对比度,可根据视觉效果微调。


实战:绘制一个像素点

有了初始化和基础函数,就可以开始绘图了。以下是绘制单个像素的核心逻辑。

void st7735_draw_pixel(uint8_t x, uint8_t y, uint16_t color) { // 设置列地址(CASET) lcd_write_cmd(0x2A); uint8_t col_start[4] = {0x00, x + 2, 0x00, x + 2}; // 补偿偏移 lcd_write_data(col_start, 4); // 设置行地址(RASET) lcd_write_cmd(0x2B); uint8_t row_start[4] = {0x00, y + 1, 0x00, y + 1}; lcd_write_data(row_start, 4); // 写入像素数据(RAMWR) lcd_write_cmd(0x2C); uint8_t pixel[2] = {color >> 8, color & 0xFF}; // RGB565 分高低字节 lcd_write_data(pixel, 2); }

⚠️ 注意:很多ST7735模块存在坐标偏移(如原点在(2,1)处),因此需要在x+2,y+1进行补偿。具体数值请参考模块规格书。


常见问题与调试秘籍

❌ 白屏/花屏怎么办?

  1. 查复位:确认RES引脚是否有足够宽度的低脉冲(≥10ms);
  2. 查时序:SPI是否为 Mode 0(CPOL=0, CPHA=0);
  3. 查延时0x11后是否延时 ≥120ms;
  4. 查电压:VCC是否稳定在3.3V?建议并联0.1μF陶瓷电容;
  5. 查接线:MOSI/SCK是否接反?CS是否接地导致一直选中?

🔄 显示方向不对?

修改MADCTL参数即可。推荐封装一个函数:

void st7735_set_rotation(uint8_t rotation) { static const uint8_t values[] = {0x00, 0x60, 0xC0, 0xA0}; lcd_write_cmd(0x36); lcd_write_data(&values[rotation % 4], 1); }

🐢 刷新太慢怎么优化?

  • 启用DMA:对于大块区域填充,使用DMA传输像素数据,释放CPU;
  • 提高SPI频率:在保证信号质量前提下,将SPI时钟提升至20MHz以上;
  • 局部刷新:只更新变化区域,避免全屏重绘;
  • 关闭不必要的动画效果:如滚动、渐变等。

高级技巧:迈向高性能显示系统

掌握了基础之后,可以进一步优化:

使用DMA批量传输像素

HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)pixel_buffer, length);

配合双缓冲机制,可实现流畅动画。

封装命令序列数组

将初始化命令封装为结构体数组,便于管理和调试输出:

typedef struct { uint8_t cmd; const uint8_t *data; uint8_t len; uint8_t delay_ms; } lcd_init_cmd_t; static const lcd_init_cmd_t init_cmds[] = { {0x11, NULL, 0, 120}, {0xB1, (uint8_t[]){0x01,0x2C,0x2D}, 3, 0}, {0x36, (uint8_t[]){0xC0}, 1, 0}, ... };

这样可以在不同屏幕间轻松切换配置。


如果你正在开发一款基于STM32的小型HMI设备,无论是智能仪表、传感器终端还是DIY电子玩具,掌握ST7735的命令级操作能力,将让你摆脱对第三方库的依赖,真正做到“知其然,更知其所以然”。

当你下次面对一块新买的TFT屏时,不再需要到处搜索“适配代码”,而是能够根据数据手册,独立写出可靠的初始化流程——这才是嵌入式开发的魅力所在。

欢迎在评论区分享你在驱动LCD过程中踩过的坑,我们一起讨论解决方案!

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

教育辅导机器人定制:让通用LLM具备学科专业能力

教育辅导机器人定制:让通用LLM具备学科专业能力 在当前智能教育快速演进的背景下,越来越多的学校和培训机构开始探索如何利用大语言模型(LLM)提升教学效率。然而,一个普遍存在的现实是:尽管像 LLaMA、ChatG…

作者头像 李华
网站建设 2026/6/13 16:48:31

前后端分离架构建议:未来lora-scripts可能的演进方向

前后端分离架构建议:未来lora-scripts可能的演进方向 在生成式AI快速落地的今天,越来越多企业和创作者希望拥有定制化的模型能力——无论是打造专属画风的图像生成器,还是训练具备行业知识的智能客服。然而,通用大模型往往“懂很…

作者头像 李华
网站建设 2026/6/12 21:40:19

谷歌镜像站点列表:提升外文资料查阅效率的辅助工具

lora-scripts:让 LoRA 微调像搭积木一样简单 在 AI 模型日益庞大的今天,动辄数十 GB 的大模型虽然能力惊人,但对普通人来说却像一座难以翻越的高山。你有没有遇到过这种情况:手头有一批风格独特的图片,想训练一个专属的…

作者头像 李华
网站建设 2026/6/13 15:24:01

Linux服务器安装lora-scripts全流程:Ubuntu系统适配指南

Linux服务器安装lora-scripts全流程:Ubuntu系统适配指南 在生成式AI迅速渗透各行各业的今天,如何以较低成本定制专属模型,成为开发者和企业关注的核心问题。尤其是对于资源有限的个人开发者或中小企业而言,全参数微调动辄需要数张…

作者头像 李华
网站建设 2026/6/12 21:45:15

Keil5安装配置完整指南:从零开始搭建嵌入式开发环境

从零搭建Keil5开发环境:嵌入式工程师的实战入门指南 你有没有遇到过这样的情况?刚拿到一块STM32开发板,满心欢喜地打开电脑准备“点灯”,结果卡在第一步——编译器装不上、头文件找不到、下载失败……明明代码写得没问题&#xf…

作者头像 李华
网站建设 2026/6/12 18:56:00

蔚来ET7车载屏幕:lora-scripts适配个性化壁纸

蔚来ET7车载屏幕:lora-scripts适配个性化壁纸 在高端智能电动车的座舱设计中,视觉体验早已超越“能看导航”这一基础功能。以蔚来ET7为例,其搭载的12.8英寸AMOLED中控屏与全液晶仪表构成沉浸式交互界面,用户不再满足于千篇一律的出…

作者头像 李华