news 2026/4/16 15:06:49

零基础学习ST7789:SPI接口连接操作指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
零基础学习ST7789:SPI接口连接操作指南

从零点亮一块彩屏:手把手教你用SPI驱动ST7789显示屏

你有没有想过,自己亲手让一块小小的彩色屏幕亮起来,显示文字、图形甚至动画?听起来像是高手才玩得转的事,但其实只要掌握正确的方法,哪怕你是嵌入式开发的“小白”,也能在几小时内完成这个看似高深的操作。

今天我们要聊的是ST7789—— 一块在1.3英寸到2.0英寸小屏幕上几乎无处不在的TFT控制器芯片。它被广泛用于智能手表、便携仪表、DIY项目中,而最常用、也最适合初学者上手的方式,就是通过SPI接口来控制它。

别担心没基础。这篇文章不堆术语、不甩理论,只讲你能看懂、能动手、能成功的实战路径。我们会从接线开始,一步步走到屏幕全亮、刷出颜色,最后告诉你怎么避免那些让人抓狂的“黑屏”、“花屏”坑。


为什么是 ST7789?又为什么选 SPI?

先说个现实:现在做嵌入式项目,谁还愿意为一个屏幕拉十几根线搞并口通信?MCU引脚宝贵得很,尤其是像ESP32-Sx系列或者STM32G0这类资源紧张的芯片,省一根是一根。

ST7789 的好处就在于——功能强,还省事

它支持最高 240×320 分辨率,原生支持 RGB565 色彩格式(也就是常说的16位色,约6.5万色),内置升压电路和伽马校正,最关键的是,它可以用四根线就跑起来:SCK、MOSI、CS、DC。加上 RST 和电源,总共也就七八个引脚搞定。

而这四根核心信号线走的就是SPI 协议。SPI 是什么?你可以把它想象成一种“对讲机式”的通信方式:主控(比如你的单片机)说话,屏幕听着,不需要回话(因为大多数时候我们只写不读)。简单、高效、通用性强。

更重要的是,几乎所有主流开发平台都原生支持 SPI:
- Arduino 有SPI.h
- ESP32 支持硬件 SPI + DMA 加速
- 树莓派 Pico(RP2040)用 C/C++ SDK 轻松配置
- STM32 HAL 库直接调用传输函数

所以,选择 ST7789 + SPI 组合,等于选择了低成本、低门槛、高兼容性的入门方案。


接线很简单,但每根线都有讲究

先来看一张最基础的连接图:

MCU 引脚ST7789 模块
GPIOx (SCK)SCK / CLK
GPIOy (MOSI)MOSI / DIN
GPIOz (CS)CS / SS
GPIOa (DC)DC / A0
GPIOb (RST)RST
3.3VVCC
GNDGND
(可选)PWMBLK / LED_K

⚠️ 注意:有些模块标的是 VIN 而不是 VCC,其实是同一个意思;BLK 是背光控制脚,接 PWM 可调亮度。

这里面最容易忽略的细节是电平匹配。虽然 ST7789 支持 1.8V~3.3V IO 电压,但如果你用的是 5V 系统(比如老款 Arduino Uno),必须加电平转换器或串电阻限流,否则可能烧毁模块!

另外,RST 引脚不能省。虽然有些代码里看到“不用硬件复位”,但强烈建议接上。很多初始化失败的问题,根源就是芯片没真正重启。


SPI 模式怎么选?Mode 0 还是 Mode 3?

这是新手最容易栽的第一个坑。

SPI 有四种工作模式,由两个参数决定:CPOL(时钟极性)和 CPHA(时钟相位)。ST7789 官方文档写着支持 Mode 0 和 Mode 3,那到底该用哪个?

答案是:优先试 Mode 0(CPOL=0, CPHA=0)

什么意思?
- 空闲时 SCK 为低电平
- 数据在上升沿采样(即每个时钟周期的后半段稳定)

这几乎是市面上绝大多数开发板默认的设置。你在 Arduino 或 STM32CubeMX 中启用 SPI 外设时,默认就是这个模式。

如果 Mode 0 不行,再尝试切换到 Mode 3(CPOL=1, CPHA=1)试试。有时候某些厂商改了内部逻辑,会要求空闲高电平。

✅ 实战提示:可以用示波器抓一下 SCK 波形,看看是否符合预期;没有设备的话,就靠换代码配置多试几次。


命令与数据交替传输:ST7789 的“语言规则”

理解这一点,你就掌握了和屏幕“对话”的钥匙。

ST7789 并不像普通外设那样收发固定协议的数据包,它是靠命令 + 参数的方式工作的。就像点菜一样:
- 先告诉它你要干嘛(下命令)
- 再把具体信息传过去(送参数)

而区分“命令”和“数据”的关键,就是那根叫DC的引脚。

DC 状态含义
DC = 0当前传输的是命令字节(例如0x2A表示设置列地址)
DC = 1当前传输的是数据(参数或像素值)

举个例子,你想设置显示区域为左上角 (0,0) 到右下角 (239,319):

拉低 CS → 发送 0x2A (DC=0) → 发起始高位 (DC=1) → 起始低位 → 结束高位 → 结束低位 → CS 拉高

整个过程如下:

void ST7789_WriteCmd(uint8_t cmd) { CS_LOW; DC_LOW; // 命令模式 spi_write(&cmd, 1); DC_HIGH; // 自动切回数据模式,方便后续连续写数据 } void ST7789_WriteData(uint8_t *buf, size_t len) { CS_LOW; spi_write(buf, len); // 此时 DC 已为高,表示数据 CS_HIGH; }

注意看,我们在发送完命令后立刻把 DC 拉高——这是一个小技巧,因为接下来大概率要写参数,提前准备好状态可以减少一次 GPIO 切换,提升效率。


初始化序列:让屏幕“醒过来”的魔法咒语

刚上电的 ST7789 是沉睡的。它需要一系列特定的命令才能进入正常工作状态。这些命令组合起来,叫做初始化序列(Initialization Sequence)

你可以把它理解为“开机自检+系统配置”。

下面是典型的一段初始化流程(适用于大多数 240x320 屏):

void ST7789_Init(void) { // 硬件复位 RST_LOW; delay_ms(10); RST_HIGH; delay_ms(150); // 软件复位 ST7789_WriteCmd(0x01); delay_ms(150); // 退出睡眠模式 ST7789_WriteCmd(0x11); delay_ms(200); // 必须等够!手册要求 ≥120ms // 设置色彩格式为 16-bit (RGB565) ST7789_WriteCmd(0x3A); ST7789_WriteByte(0x05); // 0x05 = 16位色 // 设置内存访问方向(旋转/镜像) ST7789_WriteCmd(0x36); ST7789_WriteByte(0xC0); // 常见竖屏方向,可根据实际调整 // 设置列地址范围(0~239) ST7789_WriteCmd(0x2A); uint8_t col_addr[] = {0x00, 0x00, 0x00, 0xEF}; // 240列 ST7789_WriteData(col_addr, 4); // 设置行地址范围(0~319) ST7789_WriteCmd(0x2B); uint8_t row_addr[] = {0x00, 0x00, 0x01, 0x3F}; // 320行 ST7789_WriteData(row_addr, 4); // 开启显示 ST7789_WriteCmd(0x29); }

其中最关键的几个点:
-0x11(Sleep Out)之后必须延时至少120ms
-0x36(MADCTL)决定了屏幕怎么“躺着”显示,常见值有0x00,0x60,0xC0,0xA0,分别对应不同旋转角度
-0x29(Display On)才是真正点亮屏幕的开关

如果你的屏幕一直黑着,先检查是不是漏了0x11或者0x29,或者延时不达标。


如何画满屏?向 GRAM 写入像素数据

GRAM 是什么?它是 Graphics RAM 的缩写,即图形内存。虽然 ST7789 本身没有大容量 RAM 存储整帧图像,但它提供了一个“窗口机制”:你告诉它一个区域,然后往里面不停地写颜色数据,它就会自动映射到屏幕上。

写像素的核心命令是0x2C(Write Memory Start),意思是:“接下来所有数据都是像素点了。”

比如,我们想把整个屏幕刷成白色(RGB565 下白色是0xFFFF):

void ST7789_FillScreen(uint16_t color) { ST7789_SetWindow(0, 0, 239, 319); // 设定区域 ST7789_WriteCmd(0x2C); // 开始写显存 uint8_t hi = color >> 8; uint8_t lo = color & 0xFF; // 构造重复颜色数组(建议用DMA或缓冲区优化) for (int i = 0; i < 240 * 320; i++) { ST7789_WriteByte(hi); ST7789_WriteByte(lo); } }

当然,这种轮询写法非常慢,尤其是在 SPI 频率只有 4MHz 的情况下,刷一屏可能要几百毫秒。但在调试阶段完全可用。

💡 提升建议:使用 DMA 传输、双缓冲机制,或将颜色预存在数组中批量发送。


屏幕方向怎么调?MADCTL 寄存器详解

很多人第一次点亮屏幕,发现图像是倒的、歪的、镜像的……别慌,这很正常。

这一切都由MADCTL(Memory Access Control)寄存器控制,地址是0x36。它是一个8位寄存器,每一位都有含义:

Bit名称功能
7MY行扫描顺序:1=从下往上
6MX列扫描顺序:1=从右往左
5MVX/Y 是否交换:1=行列互换(实现90度旋转)
4ML扫描方向:1=从底到顶逐行
3RGB接口颜色顺序:1=RGB,0=BGR(重要!)
2:0-保留

常用组合举例:

值(十六进制)效果说明
0x00默认横向,左上起点
0x60旋转90度(适合竖屏)
0xC0旋转180度
0xA0旋转270度
0x20水平翻转

🎯 实战经验:如果你发现颜色偏蓝或偏红,很可能是 RGB/BGR 搞反了。试试把 bit3 取反。


常见问题排查清单:那些年我们一起踩过的坑

❌ 屏幕完全不亮?

  • 检查供电是否正常(3.3V?有无短路?)
  • RST 是否有效触发?可用万用表测复位电平变化
  • 是否发送了0x110x29?缺一不可
  • SPI 是否工作?可用示波器看 SCK 是否有波形

❌ 显示花屏、错位、条纹?

  • CASETRASET设置的坐标范围是否正确?
  • MADCTL 配置是否与物理安装方向一致?
  • SPI 速率是否过高?面包板上超过 8MHz 就容易出错

❌ 颜色不对(发绿、发红)?

  • RGB565 字节顺序是否颠倒?试试交换高低字节
  • MADCTL 的 RGB/BGR 位是否正确?
  • 测试纯色:0xF800=红,0x07E0=绿,0x001F=蓝

❌ 刷新太慢卡顿?

  • 放弃轮询写法,改用 DMA 或 SPI 双缓冲
  • 减少全屏刷新,改为局部更新(Partial Update)
  • 提高 SPI 主频至 10~15MHz(需确保线路质量)

工程级设计建议:不只是点亮,更要稳定可靠

当你不再满足于“能亮”,而是要做产品级应用时,以下几点值得重视:

✅ 电源去耦不能省

在 VCC 引脚附近加一个0.1μF 陶瓷电容,离模块越近越好。最好再并联一个 10μF 钽电容,吸收瞬态电流波动。

✅ 背光单独控制

BLK 引脚通常连接背光LED阴极。若电流较大(>100mA),建议用三极管或MOSFET驱动,避免直接由MCU引脚供电。

✅ 使用分层架构

构建清晰的软件结构:

底层:SPI 读写抽象 │ ├─ 中间层:ST7789 控制(初始化、窗口设置、旋转等) │ └─ 上层:图形库(绘制点线圆、文字、UI框架如LVGL)

这样未来换平台或换屏幕都更容易移植。

✅ 区域更新优于全屏刷新

对于仅变动一小部分画面的应用(如仪表盘指针移动),只需重绘变化区域即可大幅降低带宽占用。


更进一步:结合 GUI 框架打造交互界面

一旦你能稳定驱动 ST7789,下一步就可以接入轻量级 GUI 框架,比如:

  • LVGL:功能强大,支持触摸、动画、主题,适合 STM32/ESP32
  • u8g2:资源占用极低,适合 AVR、nRF 等小内存设备
  • TFT_eSPI + Arduino GFX:ESP32 上最受欢迎的组合之一

它们的背后,其实都是基于我们刚才讲的这套 SPI + 命令-数据模型。你现在打下的基础,正是通往更复杂应用的跳板。


写在最后:每一个高手,都曾从点亮第一块屏开始

你看,整个过程并没有那么神秘。从认识每一根线的作用,到理解命令与数据的区别,再到写出第一个FillScreen()函数——你已经走完了从“看不懂”到“能做到”的全过程。

技术从来不是天才的专利,而是坚持实践的结果。也许你现在连 SPI 是什么都还不太清楚,但只要动手接一次线、烧录一段代码、看到屏幕真的亮起来那一刻,那种成就感,足以让你爱上嵌入式开发。

如果你正在做一个天气站、音乐播放器、或是带界面的小工具,不妨加上这块 ST7789 屏。它不大,却能让你的作品瞬间生动起来。

如果你在调试过程中遇到问题,欢迎留言交流。我们一起解决下一个“黑屏”难题。

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

GenomicSEM完整教程:7天掌握遗传结构方程建模核心技术

GenomicSEM完整教程&#xff1a;7天掌握遗传结构方程建模核心技术 【免费下载链接】GenomicSEM R-package for structural equation modeling based on GWAS summary data 项目地址: https://gitcode.com/gh_mirrors/ge/GenomicSEM GenomicSEM作为遗传学研究领域的革命性…

作者头像 李华
网站建设 2026/4/16 13:44:23

2、Java函数式编程:Lambda表达式带来的变革

Java函数式编程:Lambda表达式带来的变革 1. 引言 Java编程风格正迎来显著变革。新的编程方式让日常任务变得更简单、更轻松且更具表现力。这种在其他语言中已存在数十年的编程方式,如今在Java中得以应用,使我们能编写更简洁、优雅且富有表现力的代码,减少错误,还能轻松实…

作者头像 李华
网站建设 2026/4/16 13:44:02

12、Java 8 中的懒加载与递归优化

Java 8 中的懒加载与递归优化 1. 懒加载评估的优势 在进入 lazyEvaluator() 方法之前,参数不会被评估。在某个版本中,第二次对 evaluate() 的调用被跳过了。调用 lazyEvaluator() 大约只需要两秒,而之前调用 eagerEvaluator() 则大约需要四秒。由此可见,懒加载评估…

作者头像 李华
网站建设 2026/4/16 13:42:57

5大理由告诉你为什么需要这款战双帕弥什游戏自动化工具

5大理由告诉你为什么需要这款战双帕弥什游戏自动化工具 【免费下载链接】MAA_Punish 战双帕弥什每日任务自动化 | Assistant For Punishing Gray Raven 项目地址: https://gitcode.com/gh_mirrors/ma/MAA_Punish 还在为每天重复登录游戏、完成繁琐日常任务而烦恼吗&…

作者头像 李华
网站建设 2026/4/16 13:44:46

4、软件开发中的数据处理与设计要点

软件开发中的数据处理与设计要点 数据与信息的区别 数据是被动的,它就摆在那里,无声且缺乏有效信息。而信息则是能促使用户做出决策、改变方向或采取行动的数据。 例如,按公司名称排序的客户列表对用户来说可能是信息,因为这是他们所需的列表。然而,客户记录中包含电话…

作者头像 李华
网站建设 2026/4/15 14:44:01

IINA:macOS平台最值得拥有的视频播放神器

还在为macOS上找不到一款称心如意的视频播放器而烦恼吗&#xff1f;当你面对各种格式的视频文件&#xff0c;却总是遇到播放卡顿、字幕不匹配、界面操作繁琐的问题时&#xff0c;IINA的出现将彻底改变你的观影体验。 【免费下载链接】iina 项目地址: https://gitcode.com/gh…

作者头像 李华