1. 基于ESP32-S3的1.9寸ST7789V3彩屏SPI驱动移植与实战
基于ESP32-S3的1.9寸ST7789V3彩屏SPI驱动移植与实战
最近在ESP32-S3上折腾一个小屏幕,发现这块1.9寸的ST7789V3彩屏性价比挺高,显示效果也不错,但网上的驱动资料比较零散。我花了不少时间把软件SPI和硬件SPI两种驱动方式都调通了,今天就把完整的移植过程分享出来,手把手教你怎么让这块屏幕在ESP32-S3上亮起来。
这篇教程适合正在用ESP32-S3做显示项目的朋友,无论你是刚入门还是有一定经验的开发者,都能跟着步骤完成。咱们会从硬件接线开始,讲到驱动代码的获取和集成,最后用实际代码验证显示效果。过程中我会分享一些调试时踩过的坑,帮你少走弯路。
1. 屏幕与硬件准备
1.1 屏幕规格与资料获取
咱们用的这块是1.9寸的彩色LCD屏幕,驱动芯片是ST7789V3。先来看看它的基本参数:
| 参数 | 规格 |
|---|---|
| 工作电压 | 3.3V |
| 工作电流 | 约50mA |
| 模块尺寸 | 29mm (高) x 62mm (宽) |
| 显示分辨率 | 170 (水平) x 320 (垂直) RGB |
| 通信协议 | SPI (支持软件SPI和硬件SPI) |
| 引脚数量 | 8 Pin (2.54mm间距排针) |
屏幕的采购链接和资料包我都放在这里,方便你获取:
- 采购链接:淘宝商品链接
- 资料下载:链接: https://pan.baidu.com/s/1ArmQST7I84UYY7n0aJdEBw 提取码: 8888
资料包里包含了完整的驱动代码、示例程序和一些文档,是咱们后续移植的基础。
1.2 通信原理:SPI简介
这块屏幕通过SPI接口和ESP32-S3通信。SPI是一种高速、全双工的同步通信协议,简单理解就是主设备(MCU)和从设备(屏幕)之间用几根线来“对话”。
- SCK (SCL):时钟线,由主设备产生,像打拍子一样同步数据收发。
- MOSI (SDA):主设备输出、从设备输入线,主设备通过这根线发送数据给屏幕。
- CS:片选线,当主设备要和某个从设备通信时,就把对应从设备的这根线拉低(选中它)。
- 其他引脚:除了上述SPI必需的引脚,屏幕还有
DC(数据/命令选择)、RES(复位)、BLK(背光控制)等控制引脚。
ESP32-S3芯片内部集成了多个SPI控制器:
- SPI0 & SPI1:主要预留给内部访问外部Flash和PSRAM,我们一般不用。
- SPI2 (GP-SPI2) & SPI3 (GP-SPI3):这两个是通用的SPI控制器,我们可以自由使用,也就是常说的“硬件SPI”。
“软件SPI”则是用普通的GPIO引脚,通过程序模拟SPI的时序来通信,好处是引脚选择灵活,但速度比硬件SPI慢。
2. 硬件连接:引脚接线图
接线是第一步,也是最容易出错的一步。屏幕有8个引脚,我们需要根据选择的通信方式(软件SPI或硬件SPI)连接到ESP32-S3对应的GPIO上。
2.1 软件SPI接线
软件SPI不挑剔引脚,你可以选择ESP32-S3上任意空闲的GPIO。下面是我推荐的一组引脚连接,比较常用:
表2.1-1 1.9寸屏引脚说明
| 屏幕引脚标号 | 引脚名称 | 功能说明 |
|---|---|---|
| 1 | GND | 电源地 |
| 2 | VCC | 电源正 (3.3V) |
| 3 | SCL | SPI时钟线 (SCK) |
| 4 | SDA | SPI数据线 (MOSI) |
| 5 | RES | 复位引脚 (低电平有效) |
| 6 | DC | 数据/命令选择引脚 |
| 7 | CS | 片选引脚 (低电平有效) |
| 8 | BLK | 背光控制 (高电平点亮) |
表2.1-2 软件SPI推荐接线方式
| ESP32-S3 GPIO | 连接至屏幕引脚 | 备注 |
|---|---|---|
| GPIO2 | SCL (3) | SPI时钟 |
| GPIO3 | SDA (4) | SPI数据输出 |
| GPIO4 | RES (5) | 复位信号 |
| GPIO5 | DC (6) | 数据/命令选择 |
| GPIO6 | CS (7) | 片选信号 |
| GPIO7 | BLK (8) | 背光控制 |
| 3.3V | VCC (2) | 电源 |
| GND | GND (1) | 电源地 |
注意:如果你的项目GPIO紧张,有两个引脚可以简化:
- RES引脚:可以接到ESP32-S3的复位引脚(EN)。这样开发板复位时,屏幕也跟着复位,省下一个GPIO。代价是无法通过软件单独复位屏幕。
- BLK引脚:可以直接接到3.3V或悬空。接到3.3V则背光常亮,悬空则背光不亮(通常内部有弱上拉,可能微亮)。代价是失去了通过程序调节背光亮度的能力。
2.2 硬件SPI接线
硬件SPI需要连接到ESP32-S3指定的SPI功能引脚上,这样才能发挥硬件加速的优势。这里我们以使用SPI2_HOST(即GP-SPI2)为例。
表2.2-1 硬件SPI推荐接线方式 (使用SPI2)
| ESP32-S3 GPIO | 默认SPI2功能 | 连接至屏幕引脚 |
|---|---|---|
| GPIO12 | SPI2_CLK | SCL (3) |
| GPIO11 | SPI2_MOSI | SDA (4) |
| GPIO4 | (自定义GPIO) | RES (5) |
| GPIO5 | (自定义GPIO) | DC (6) |
| GPIO6 | (自定义GPIO) | CS (7) |
| GPIO7 | (自定义GPIO) | BLK (8) |
可以看到,对于硬件SPI,只有时钟(SCK)和数据输出(MOSI)必须使用固定的功能引脚(GPIO12和GPIO11)。RES、DC、CS、BLK这些控制引脚依然可以像软件SPI一样自由分配普通GPIO。
3. 驱动移植:将代码集成到你的工程
硬件接好线,接下来就是把驱动代码“搬”到我们的ESP32-S3项目里。资料包里已经提供了写好的驱动,我们只需要把它放到正确的位置并修改配置文件。
3.1 获取驱动文件
首先,你需要从之前提供的资料下载链接中,找到驱动文件包。根据原文指引,文件位于:资料下载中心 -> 模块移植资料下载 -> 该章节配套压缩包中。
下载后解压,你会找到一个名为LCD的文件夹。这个文件夹里就包含了驱动屏幕所需的所有源文件(.c和.h)。
3.2 将驱动文件加入工程
复制文件:打开你的ESP-IDF项目,将下载得到的整个
LCD文件夹,复制到你项目的main目录下。通常你的项目结构会像这样:你的项目/ ├── CMakeLists.txt ├── main/ │ ├── CMakeLists.txt │ ├── main.c │ └── LCD/ <-- 把文件夹复制到这里 │ ├── lcd_init.c │ ├── lcd_init.h │ ├── lcd.c │ └── ...修改编译配置:为了让编译器知道这些新文件的存在,需要修改
main目录下的CMakeLists.txt文件。 用VS Code或其他编辑器打开main/CMakeLists.txt,在idf_component_register部分添加LCD文件夹的路径。通常是在SRCS和INCLUDE_DIRS里添加。一个简单的修改示例如下:
idf_component_register(SRCS "main.c" "LCD/lcd_init.c" "LCD/lcd.c" # ... 添加其他LCD文件夹下的.c文件 INCLUDE_DIRS "." "LCD" # 添加这一行,让编译器能找到.h文件 )更规范的做法是使用
aux_source_directory命令自动添加所有.c文件,但手动列出更清晰,也不容易出错。
3.3 关键配置:根据接线修改引脚定义
驱动文件里有一个关键的头文件(通常是lcd_init.h或lcd_conf.h),里面定义了所有用到的GPIO引脚编号。你必须根据你实际的接线方式修改这里!
打开LCD/lcd_init.h文件,找到类似下面的引脚定义部分:
// 软件SPI引脚定义示例 #define LCD_SCL_PIN 2 #define LCD_SDA_PIN 3 #define LCD_RES_PIN 4 #define LCD_DC_PIN 5 #define LCD_CS_PIN 6 #define LCD_BLK_PIN 7 // 或者硬件SPI引脚定义示例 #define LCD_SPI_HOST SPI2_HOST #define LCD_SCLK_PIN 12 #define LCD_MOSI_PIN 11 #define LCD_RES_PIN 4 #define LCD_DC_PIN 5 #define LCD_CS_PIN 6 #define LCD_BLK_PIN 7请务必将这些#define后面的数字,改成你实际连接ESP32-S3的GPIO编号。如果你用的是硬件SPI,还需要确认LCD_SPI_HOST与你使用的SPI控制器一致(SPI2_HOST或SPI3_HOST)。
修改完引脚定义,驱动移植的核心工作就完成了。
4. 功能验证:编写测试程序点亮屏幕
代码集成好了,引脚也配置对了,是时候上电测试了。我们在主程序main.c里写一段简单的测试代码,来验证屏幕是否正常工作。
4.1 测试代码解析
打开你的main/main.c文件,将内容替换为以下测试代码。这段代码会初始化屏幕,先清屏为白色,然后循环显示一些文字、数字、图片和一个递增的浮点数。
#include <stdio.h> #include <inttypes.h> #include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_chip_info.h" #include "esp_flash.h" #include "esp_timer.h" // 包含我们移植的LCD驱动头文件 #include "LCD/lcd_init.h" #include "LCD/lcd.h" #include "LCD/pic.h" // 包含图片数据 void app_main(void) { float t = 0.0; // 用于演示的浮点数变量 LCD_Init(); // 第一步:初始化LCD屏幕,这是必须的! LCD_Fill(0, 0, LCD_W, LCD_H, WHITE); // 第二步:用白色填充整个屏幕 while(1) { // 以下代码在循环中执行,动态刷新显示内容 // 1. 显示中文 LCD_ShowChinese(40, 0, (uint8_t *)"中电科", RED, WHITE, 32, 0); // 2. 显示字符串和屏幕宽度 LCD_ShowString(10, 33, (uint8_t *)"LCD_W:", RED, WHITE, 32, 0); LCD_ShowIntNum(106, 33, LCD_W, 3, RED, WHITE, 32); // LCD_W是驱动里定义的屏幕宽度 // 3. 显示字符串和屏幕高度 LCD_ShowString(10, 66, (uint8_t *)"LCD_H:", RED, WHITE, 32, 0); LCD_ShowIntNum(106, 66, LCD_H, 3, RED, WHITE, 32); // LCD_H是驱动里定义的屏幕高度 // 4. 显示一个不断增加的浮点数 LCD_ShowFloatNum1(10, 99, t, 4, RED, WHITE, 32); t += 0.11; // 5. 在指定位置显示一张40x40像素的图片 // gImage_1 是 pic.h 中定义好的图片数组 LCD_ShowPicture(160, 95, 40, 40, gImage_1); // 延时1秒,让变化看得清 delay_ms(1000); // 你可以尝试取消下面几行注释,看看全屏刷色的效果 // LCD_Fill(0,0,LCD_W,LCD_H,RED); // delay_ms(500); // LCD_Fill(0,0,LCD_W,LCD_H,GREEN); // delay_ms(500); // LCD_Fill(0,0,LCD_W,LCD_H,BLUE); // delay_ms(500); // LCD_Fill(0,0,LCD_W,LCD_H,WHITE); // delay_ms(500); } }4.2 编译、烧录与上电
- 编译工程:在VS Code的ESP-IDF终端或你的项目目录下,运行
idf.py build命令编译项目。 - 连接开发板:用USB线将ESP32-S3开发板连接到电脑,确保端口被系统识别。
- 烧录程序:运行
idf.py -p PORT flash命令将程序烧录到开发板(将PORT替换为你的实际串口号,如COM3或/dev/ttyUSB0)。 - 上电观察:烧录完成后,程序会自动运行。观察你的1.9寸屏幕:
- 屏幕背光应该点亮。
- 屏幕首先会全白。
- 随后,屏幕上会显示“中电科”三个红字,以及屏幕的宽高参数(应该是170和320)。
- 一个红色的浮点数会每秒增加0.11。
- 屏幕右侧会显示一张内置的小图片。
如果一切顺利,恭喜你,驱动移植成功!如果屏幕没反应,别着急,可以按照下面的排查思路看看。
5. 常见问题与调试心得
搞嵌入式,一次成功是幸运,调试才是常态。这里分享几个我调试时遇到的问题和解决方法。
屏幕完全无显示,背光也不亮
- 检查电源:首先用万用表量一下屏幕VCC和GND引脚是不是3.3V。ESP32-S3的3.3V输出能力有限,如果接了很多外设,可能导致电压被拉低。
- 检查背光:确认BLK引脚是否接对了。如果接的是GPIO,检查程序里是否将其设置为高电平输出;如果直接接3.3V,检查连接是否牢固。
- 检查复位:测量RES引脚,正常工作时应该是高电平。可以在程序初始化前,手动给一个低电平脉冲(拉低再拉高)来复位屏幕。
屏幕背光亮,但无任何内容(白屏或花屏)
- 检查接线:这是最常见的问题!逐根线检查SCL、SDA、DC、CS是否与程序中的定义一一对应,有没有虚焊或接错。特别是DC和CS引脚,接反了肯定没显示。
- 检查SPI模式:ST7789V3通常使用SPI Mode 0或Mode 3。确保驱动代码里的SPI模式设置正确。资料包里的驱动一般是设置好的,如果你用的其他驱动库,需要留意。
- 降低SPI速度:尤其是软件SPI,如果初始化速度太快,屏幕可能反应不过来。尝试在初始化函数里,在发送初始化命令序列前,增加一个几十毫秒的延时(
vTaskDelay(pdMS_TO_TICKS(50)))。
显示内容错位、乱码或颜色不对
- 检查屏幕扫描方向:ST7789V3可以通过命令设置扫描方向(Rotation)。驱动里一般有
LCD_Display_Dir之类的函数。如果你发现文字是横着的或者镜像的,调用这个函数修改方向即可。 - 检查颜色格式:ESP32-S3和屏幕可能使用不同的颜色格式(如RGB565、RGB888)。确保驱动中颜色数据的发送格式与屏幕期望的格式一致。资料包里的驱动通常已适配好。
- 检查屏幕扫描方向:ST7789V3可以通过命令设置扫描方向(Rotation)。驱动里一般有
硬件SPI不工作,但软件SPI可以
- 确认引脚复用:确保你为硬件SPI(SCLK, MOSI)分配的GPIO,在ESP32-S3上确实具有SPI功能。参考ESP32-S3的技术手册或引脚定义图。
- 检查SPI控制器初始化:硬件SPI驱动中,除了配置引脚,还需要正确初始化SPI主机(
spi_bus_initialize)和设备(spi_device_interface_config_t)。对比资料包里的硬件SPI驱动示例,看是否有遗漏步骤。
调试时,逻辑分析仪或者示波器是神器,可以抓取SPI总线上的波形,看时钟和数据有没有正常发出。没有仪器的话,就耐心点,用“二分法”排查:先确保电源和复位,再确保SPI数据线,最后看配置命令。
好了,关于ESP32-S3驱动1.9寸ST7789V3彩屏的教程就到这里。从硬件连接到软件移植,再到调试上电,整个过程走下来,你应该对SPI屏的驱动有了更实在的理解。这套驱动代码框架比较清晰,你完全可以在此基础上,去实现更复杂的UI、动画或者图形菜单。
