前阵子帮朋友调一块测温仪的面板,对方指定要用 ST7789 这颗屏幕,主控选的是 ESP32,环境直接上 ESP-IDF。本来想着这颗屏网上资料已经烂大街了,拿到手能很快点亮,结果从 SPI 配置到动态内容刷新折腾了两天才完全跑通,尤其是 CLion 2023 里始终找不到官方 ESP-IDF 插件这件事,实在让人窝火。今天把整个过程和踩坑点一起整理出来,给正准备用 ESP-IDF 驱动 ST7789 的朋友当个参考。
这篇文章不是简单贴一段初始化代码完事,我会把 SPI 总线参数怎么定、初始化序列为什么是那几条命令、动态内容显示时怎么处理缓冲区和刷新方式都拆开讲,最后再把常见的坑列一遍。适合已经在使用 ESP-IDF 但对 LCD 驱动不太熟的人,也适合那些想从 Arduino 迁移到 ESP-IDF、希望用更稳定高效的方式驱动屏幕的开发者。如果你只是想要一个能跑的 Demo,那也能直接复制代码,但建议尽量把原理部分过一遍,否则后续换屏幕、加动画还是会卡住。
1. 项目概述与方案选型
1.1 为什么选 ESP-IDF 而不是 Arduino
很多人拿到 ST7789 的第一反应是 Arduino 加 Adafruit 的库,插上就能跑,确实省事。但我这次选择 ESP-IDF 是有明确原因的:项目的显示内容需要定时刷新多个动态数据,包括温度曲线、数字变化和简单动画,Arduino 自带的库在帧率控制和 DMA 支持方面都比较薄弱。ESP-IDF 内部基于 FreeRTOS,可以创建独立任务来刷新屏幕,主循环不用被显示逻辑拖住,这对交互设备和仪表类项目来说是刚需。
还有一个实际原因:ESP-IDF 的 SPI 驱动原生支持 DMA 传输,ST7789 这种 SPI 屏幕只要把像素数据送到总线就行,CPU 不用逐字节干预。Arduino 上要想跑到同样的速度和稳定性,需要自己翻寄存器,实际上很多人直接放弃了。ESP-IDF 把这些底层做好了,我们只负责配置参数和调用 API。
1.2 ST7789 屏幕的核心特征
ST7789 是一颗常见的单芯片 LCD 驱动器,支持最大 240x320 分辨率,实际模组上常见 240x240、240x280 等几种规格。它内部带一块显存 RAM,尺寸和分辨率匹配,MCU 通过 SPI 或者并口往这块 RAM 写数据就能控制屏幕上每个像素。对于嵌入式项目来说,这意味着我们不需要外部显存,也不需要复杂的时序操作,只要严格按照芯片手册通过 SPI 发送命令和数据即可。
这颗驱动 IC 支持标准 SPI、Dual SPI 和 Quad SPI,不过大多数模块只引出标准 SPI 引脚,也就是 SCK、MOSI(SDA)、CS、DC(D/C)、RST、BL(背光)。部分模块还支持 MISO,但 ST7789 基本不需要回读,所以 MISO 可以不用接。我们做滚动显示和局部刷新时,需要理解 ST7789 内部 RAM 的访问方式,尤其是窗口设置命令,这个后面详细讲。
1.3 为什么用 SPI 而不是并行接口
ST7789 模组有的版本是 8-bit 并口,数据线一大把,接线麻烦,引脚占用多,还得考虑时序和板子走线。对于 ESP32 这种引脚不算特别富余的芯片来说,SPI 显然更合适,四条线就能搞定通信(SCLK、MOSI、CS、DC),加上复位和背光总共六条。SPI 的时钟速率在 ESP-IDF 下可以轻松上到 40MHz,甚至 60MHz,已经足够流畅显示动画,所以并不需要并口那种高带宽。
另外,ESP32 有多个 SPI 外设,包括 SPI2(HSPI)和 SPI3(VSPI),我们可以专门拿出一个 SPI 总线给屏幕,另一个留给 SD 卡或传感器,互不干扰。多设备共享 SPI 总线时还可以用不同 CS 片选,这在以后扩展功能时很方便。
2. 环境准备与工具链搭建
2.1 安装 ESP-IDF 的实际操作方法
ESP-IDF 目前支持 Linux、macOS 和 Windows,官方推荐的安装方式是通过 espressif/esp-idf 仓库拉取代码,再运行环境安装脚本。我这次使用的是 release/v5.1 分支,相对新且比较稳定。Windows 下建议直接使用官方的一键安装器,它会自动把必要的工具链和 Python 环境装好,省去很多烦心事。Linux 下可以用install.sh脚本,但注意提前装好python3、git和编译工具包。
mkdir -p ~/esp cd ~/esp git clone -b v5.1 --recursive https://github.com/espressif/esp-idf.git cd esp-idf ./install.sh esp32 source ./export.sh这一步没什么坑,唯一需要注意的是国内网络访问 GitHub 可能很慢,建议先想办法把仓库快速 clone 下来(比如使用镜像),否则后面编译时会反复卡在依赖下载上。另外,不同芯片型号在安装时是共用的,只要把相应芯片支持包加上就行,ESP32 和 ESP32-S3、ESP32-C3 的编译器略有差异。
2.2 在 CLion 2023 里找不到 ESP-IDF 插件的坑
很多人习惯用 CLion 写嵌入式代码,2023 版也很流行,但如果在 Marketplace 里直接搜“ESP-IDF”或者“Espressif”,你会发现结果为空,这跟我最初遇到的情况一模一样。原因并非插件不存在,而是官方 Espressif IDF 插件目前没有上架 JetBrains Marketplace,它只能通过 IDE 设置里的“Install Plugin from Disk”安装本地包,或者在 JetBrains 官方网站之外单独下载 zip 后导入。
正确的做法是到 Espressif 官方 GitHub 仓库(espressif/idf-eclipse-plugin)下载最新版本的插件包。包里面同时包含用于“Eclipse”和“CLion”的构建产物,注意看清楚文件名。下载完成后,在 CLion 的 Settings -> Plugins 中点击齿轮图标,选择 “Install PLugin from Disk”,然后选择下载的 zip 文件,重启 IDE 就能在工具栏看到 ESP-IDF 入口了。之后还需要在 CMake 工具链和 SDK 路径中进行配置,指向你本地的 esp-idf 目录。
2.3 创建工程与芯片目标的设置
用命令行创建工程比在 IDE 里新建模板更直接。官方提供了一个简单的 start 工程模板,也可以通过idf.py create-project来生成基础工程。这个命令在 v5.1 版本以后比较完善,会自动生成 CMakeLists.txt、main 目录等。
idf.py create-project st7789_demo cd st7789_demo idf.py set-target esp32设置目标后,编译、烧录命令都是一样的idf.py build和idf.py flash monitor。在 CMakeLists.txt 里可以添加需要的组件依赖,比如我会添加driver和esp_lcd,后者在高版本 ESP-IDF 中对屏幕做了抽象,能省不少事。不过本文的驱动方式会同时使用硬件驱动层和软件初始化命令,保证兼容大多数现成代码。
3. SPI 总线配置与 ST7789 初始化
3.1 SPI 参数的精细化设置
ESP-IDF 的 SPI 驱动通过两套结构体来配置:一套是总线,一套是设备。先把总线配置好,再把屏幕作为一个挂在总线上的设备做参数设定。
总线配置用的是spi_bus_config_t,需要指定 SCLK、MOSI、MISO 和几个关键标志位。ST7789 并不需要 MISO,可以不接或用一个空闲 GPIO,但如果不接就得保证代码里没有回读操作。另外需要设置max_transfer_sz,这个值决定了一次 DMA 最多能传多少字节。我的屏幕分辨率是 240x240,颜色格式 RGB565,一帧数据约 115200 字节,所以把 max_transfer_sz 至少设成 128KB,这样可以直接整帧传输。
设备配置用spi_device_interface_config_t,这里核心是时钟频率和 SPI 模式。ST7789 手册支持的最高时钟通常在 62.5MHz 左右,实际使用中 40MHz 是兼顾稳定性和速度的常见选择。clock_speed_hz就设 4010001000,mode设 0,因为在标准 SPI mode 0(CPOL=0,CPAH=0)下 ST7789 工作正常。spics_io_num设成实际连接的 CS 引脚,queue_size设成 1 或 2 都可以,后续在动态刷新时才需要调整。
spi_bus_config_t bus_cfg = { .sclk_io_num = GPIO_SCLK, .mosi_io_num = GPIO_MOSI, .miso_io_num = -1, .quadwp_io_num = -1, .quadhd_io_num = -1, .max_transfer_sz = 128 * 1024, }; spi_bus_initialize(SPI2_HOST, &bus_cfg, SPI_DMA_CH_AUTO); spi_device_interface_config_t dev_cfg = { .clock_speed_hz = 40 * 1000 * 1000, .mode = 0, .spics_io_num = GPIO_CS, .queue_size = 2, .flags = SPI_DEVICE_HALFDUPLEX, }; spi_bus_add_device(SPI2_HOST, &dev_cfg, &spi_dev);SPI_DEVICE_HALFDUPLEX这个标志非常重要,ST7789 基本上只做单向写,不需要全双工操作。加上这个标志后,驱动会采用更高效的传输方式,避免不必要的读数据流程。
3.2 接线与 GPIO 规划
我实际使用的接线方案如下,供参考。注意这不是唯一解法,但按这种方式跑起来基本不会出问题。
| 信号 | GPIO (ESP32) | 说明 |
|---|---|---|
| SCLK | GPIO 18 | SPI 时钟 |
| MOSI | GPIO 23 | SPI 数据 |
| CS | GPIO 5 | 片选,低电平有效 |
| DC | GPIO 4 | 数据/命令选择,高电平数据,低电平命令 |
| RST | GPIO 2 | 复位,低电平有效 |
| BL | GPIO 22 | 背光控制,PWM 可调亮度 |
这里必须强调 DC 引脚的作用。ST7789 的 SPI 协议本质上是把“Data/Command”信号当作额外一位地址线来用:当 DC 为低电平时,当前传输的字节被解释为命令;当 DC 为高电平时,被解释为显存数据。因此在整个驱动流程里,每次传输前都要根据是写命令还是写数据来切换 DC 的电平,这是一个容易忽略的细节。
3.3 ST7789 初始化序列的原理解读
屏幕初始化看起来就是一堆 GPIO 高低电平操作和 SPI 写字节,但背后其实有逻辑顺序。先要硬件复位,也就是把 RST 拉低一段很短时间再拉高,让 IC 内部状态回到默认。软件复位则通过发送命令0x01完成,之后还需要等待足够的延时让自己的电路稳定。
接着要设置屏幕参数。常见命令包括:
0x36设置内存数据访问控制,也就是旋转方向和 RGB/BGR 顺序。我需要横屏显示,所以对应的参数是0xA0或0x60,具体取决于是否镜像,这需要在真机上验证。0x3A设置像素格式,常用0x05表示 16-bit 每像素(RGB565)。如果用 18-bit(0x06)也可,但会增加传输数据量,一般不建议。0xB2设置 porch 控制,调节行前肩和行后肩,对于消除屏幕上下边缘的偏移有直接影响。很多初始化代码直接用默认值,但实际上不同模组推出来的屏参数会有差异,如果遇到画面上下偏移,就要调这里。0xB7设置 Gate Control,用来控制扫描方向。0xBB设置 VCOM 值,这会影响到对比度,太暗或太亮都可能需要调这个命令。0xC0、0xC1设置 LCM 控制,也就是电源电压和软启动相关参数。0xD0设置电源控制。
这些参数很多直接翻 ST7789V 数据手册就能看到推荐值。但一个比较务实的做法:先找到这个屏出厂自带的初始化代码(通常模组厂商会提供),对照运行效果再微调。如果看到的画面颜色偏色,多半是0x36命令的控制位没调好,RGB 还是 BGR 反了,把该位翻转即可。
初始化序列最后一步是0x29打开显示器,然后再打开背光。如果不发送这个命令,好几屏看起来像白屏或黑屏,其实只是显示器还在休眠。
static void lcd_cmd(const uint8_t cmd) { spi_transaction_t t = {0}; t.length = 8; t.tx_buffer = &cmd; gpio_set_level(GPIO_DC, 0); spi_device_polling_transmit(spi_dev, &t); } static void lcd_data(const uint8_t *data, size_t len) { spi_transaction_t t = {0}; t.length = len * 8; t.tx_buffer = data; gpio_set_level(GPIO_DC, 1); spi_device_polling_transmit(spi_dev, &t); }需要说明的是,spi_device_polling_transmit会阻塞等待传输完成,对初始化这种低频操作很合适,但动态刷新阶段最好换成spi_device_queue_trans加 DMA 方式,避免 CPU 空转。
3.4 坐标窗口与内容写入
显示动态内容之前,必须先理解 ST7789 的窗口机制。屏幕内部有一个显存坐标系,MCU 只能通过地址窗口来访问这部分 RAM。用0x2A设置列地址,0x2B设置行地址,两者共同圈出一个矩形区域,之后写入的像素数据会按顺序填充这个区域。
这个机制的价值在于:动态内容往往只是局部变化,比如一个数字跳变、一个进度条伸缩,只有那一小块区域需要更新。如果没有窗口机制,每次刷新只能整帧推数据,效率和流畅度都会大打折扣。ESP-IDF 的动态显示需要和这个窗口机制配合,绘制前先设置窗口,再灌入对应行列的像素数据。
void lcd_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { uint8_t data[4]; data[0] = x0 >> 8; data[1] = x0 & 0xFF; data[2] = x1 >> 8; data[3] = x1 & 0xFF; lcd_cmd(0x2A); lcd_data(data, 4); data[0] = y0 >> 8; data[1] = y0 & 0xFF; data[2] = y1 >> 8; data[3] = y1 & 0xFF; lcd_cmd(0x2B); lcd_data(data, 4); lcd_cmd(0x2C); // 开始写 RAM }写完这些命令后,后面对 SPI 连续发送的字节就会被当作像素数据传输。这里有个小细节:像素数据是按 RGB565 还是 RGB666 解析,取决于之前设置的0x3A值,而 ESP-IDF 的显示缓冲区如果直接填充 RGB565,则数据顺序是低字节在前还是高字节在前需要结合屏幕配置测试,通常可以用颜色反转来快速判断。
4. 动态内容显示:绘制文字、图形与帧率优化
4.1 显存缓冲区的设计
为了显示动态内容,通常至少需要一个帧缓冲(Frame Buffer)。ST7789 自带显存,但 MCU 侧依然需要一块内存来准备像素内容,然后整体拷贝到屏幕的内部 RAM 中。如果内存充足,可以直接为整块屏幕创建 240x240 的 RGB565 缓冲区,大概 115200 字节,ESP32 上勉强能放。如果还要跑 TCP/IP、传感器处理等任务,内存会比较紧张,这时最好采用部分缓冲。
一种常见做法是只在 MCU 侧开一个小一点的缓冲区,比如 240x16 大小,然后按条带刷新。这是嵌入式 GUI 常用的方法,LVGL 也支持这种部分刷新模式。当你只需要显示局部变化时,可以只准备与变化区域等大的缓冲区。关键在于要设计一个统一的绘制接口,让上层代码能往缓冲区里画像素,然后再刷到屏幕。我们可以把显示逻辑拆成两层:底层是 SPI 驱动和窗口操作,上层是绘制引擎(如简单的点、线、矩形和字体渲染)。绘制引擎先将结果写入缓冲区,再由刷新函数把缓冲区数据块传给 ST7789。
4.2 用 DMA 加速动态内容刷新
ESP-IDF SPI 驱动最核心的优势就是 DMA。初始化时spi_bus_initialize的 DMA 参数选择SPI_DMA_CH_AUTO,它会自动申请一个 DMA 通道。之后传输大量数据时,CPU 只需要把缓冲区地址和长度交给 DMA 控制器,传输完成后触发中断或回调。这样 CPU 可以去干别的事情,或者准备下一帧数据。
动态内容刷新通常是在一个循环里反复执行:清空缓冲区,绘制新状态,然后把整块或部分区域发送到屏幕。如果是每秒 50 帧的滚动数字,每帧 20KB 左右数据,普通轮询方式也能接受,但一旦分辨率变大,比如同时绘制一个曲线图和几个滑块,用 DMA 输出明显更流畅。我实际测试中发现,同步轮询在 40MHz SPI 时钟下传输一帧 240x240 数据需要大约 20 多毫秒,DMA 方式虽然传输时间没变,但 CPU 占用的时间少了大概一半,多任务处理起来更顺手。
可以在发送一帧数据时,在 DMA 传输期间同时准备下一帧内容,形成双缓冲流水线。最简单的做法是准备两个缓冲区 A 和 B,显示逻辑画 A,同时 SPI DMA 传输 B,画完后交换角色。
spi_transaction_t trans = { .length = height * width * 2 * 8, .tx_buffer = draw_buffer, }; trans.user = (void*)frame_done_flag; spi_device_queue_trans(spi_dev, &trans, portMAX_DELAY);用spi_device_queue_trans提交传输任务,再在传输完成回调里递增一个事件标志即可。注意不要重复使用正在 DMA 传输的缓冲区,否则会出现分屏和花屏问题。
4.3 简单图形与文字绘制
动态内容显示的核心不只是刷色块,还要能绘制文字、数字、进度条等。ST7789 本身没有内置字库,需要我们自己维护字体点阵数据。一个最常用的方式是准备一个 8x8 的 ASCII 字模数组(比如取模软件生成),然后在缓冲区里逐字节填充对应像素点。
void draw_char(uint8_t ascii, uint16_t x, uint16_t y, uint16_t color, uint16_t bg_color) { const uint8_t* glyph = font8x8[ascii - 32]; for (int i = 0; i < 8; i++) { uint8_t line = glyph[i]; for (int j = 0; j < 8; j++) { if (line & (0x80 >> j)) { draw_pixel(x + j, y + i, color); } else { draw_pixel(x + j, y + i, bg_color); } } } }这只是基本思路,实际项目里可能要用更紧凑的字模排列以及支持不同字号。如果不需要自己造轮子,可以直接移植 LVGL,然后使用 LVGL 自带的字体和控件库来做复杂界面。但是,如果仅仅是显示几个数字和字符,自己写一个 8x8 字体反而更轻量,内存占用小,也不存在版本兼容问题。
4.4 帧率优化与内容更新节奏
动态内容并不是越快越好。ST7789 的最大帧率受限于 SPI 时钟、传输数据量和屏幕内部刷新率。对于 240x240 分辨率 RGB565 来说,40MHz 时钟下理论最大刷新率大概 43Hz,扣掉开销实际跑 30Hz 左右是可行的。如果显示的是温度计或电池电量这类低频变化数据,完全没必要全屏刷新,一个局部窗口的 20x40 像素区域可能只需要不到 1ms,刷新起来毫无压力。
为了达到既好看又不卡的效果,可以设定一个固定的显示刷新周期,比如 100ms 刷一次局部区域,1 秒刷一次大区域。这种节奏控制可以用 FreeRTOS 的任务延时实现,也算对“动态内容显示”的一种合理调度。我这次做的面板里,数字区域 250ms 刷新一次,曲线区域 500ms 刷新一次,整体 CPU 占用很低,屏幕也没有明显闪烁。
5. 常见问题与排查技巧实录
5.1 CLion 插件无法安装的处理思路
前文已经提到在 Marketplace 里找不到插件,这里再补充一个容易踩的坑:有的朋友下载了最新的 ESP-IDF 插件包,导入 CLion 后工具栏确实出现了 ESP-IDF 入口,但在配置工程时仍提示找不到 CMake 编译器或 Ninja。原因是插件默认使用 Espressif 自带工具链,需要在 SDK 管理器里设置 ESP-IDF 路径,并且导出的环境变量要正确。如果你是 Windows,安装完 ESP-IDF 后还要确认IDF_PATH、IDF_TOOLS_PATH已经设置好。CLion 里最好在Toolchains页面直接指定idf.py所在目录下的clang或gcc编译器,不要让它自动查找,否则很容易误匹配系统自带的其他编译器。
其实最简单的做法就是:先把idf.py build跑通,再回头折腾 CLion 配置。因为很多问题的根源在环境变量上。
5.2 SPI 通信失败排查
如果屏幕完全没反应,首先要检查 GPIO 是否正确。STM32 上常用的 PA5/PA7 和 ESP32 的引脚完全不一样别照搬。如果你的 SCLK 和 MOSI 接错,SPI 总线自然不会工作。另外,部分开发板上的 PMU 引脚(比如 ESP32 DevKit 的 GPIO0)默认状态下会有下拉电阻,会影响上电瞬间的启动模式,用它做 CS 或 DC 会导致不稳定。
用逻辑分析仪查看 SPI 信号也是一种很直接的排查手段。SCK 上应该看到连续的时钟脉冲,MOSI 上应该有数据,CS 在每次传输时拉低。如果没有时钟脉冲,问题多半在spi_bus_initialize的配置上,尤其要检查spics_io_num是否设成了 -1(表示不用片选),这在多设备环境下会引发误触。
5.3 初始化后屏幕仍然全黑或全白
屏幕全黑且背光正常,一般说明显存传输有问题。先确认是否执行了0x29命令,没有它屏幕处于关闭状态。打开之后如果整个屏幕是白色,通常是因为没有正确设置窗口,或者像素数据格式与0x3A命令不匹配。比如你设置为 RGB565,但代码里发的是 RGB888 数据,就会出现颜色错乱,看起来像白屏。还有可能是0x36控制位中的地址增量方向不对,导致写入数据被放到了错误的内存位置。
还有一种情况是 RST 脚没接好。有些模组将 RST 接到了片选或其它引脚上,需要确认复位信号确实翻转过。如果是在初始化之前复位,要确保复位后等待至少 120ms,让内部稳压电路稳定。如果复位后立刻开始发命令,会导致后续命令被丢弃,表现出来就是屏幕状态乱七八糟。
5.4 刷新时撕裂或闪烁
动态刷新时出现闪烁或撕裂,一般有两种原因:一是缓冲区复用错误,在上一帧 DMA 还没结束时就开始往同一个缓冲区里写数据,导致数据被覆盖;二是刷新区域没有对齐,或者 SPI 传输被打断。解决杯子闪烁的根源是使用双缓冲,或者在刷新新一帧数据前,等上一帧传输完成的事件。典型写法是利用spi_transaction_t的回调函数,或者用一个二值信号量来同步。
撕裂通常在于屏幕内部 RAM 的读写出错,不一定能完全消除,但可以通过降低传输数据量来减轻。还可以尝试把 SPI 时钟降到 20MHz,虽然慢了一些,但信号质量更好,特别是在杜邦线连接、线路较长的场景下,这往往比任何代码优化都有效。
5.5 实测中的小技巧:颜色和方向的快速验证
用 ST7789 调试时,最常见的需求是快速验证颜色设置是否正确。可以在初始化完成后直接填满红色、绿色、蓝色三个色块,分别看是否正常显示。如果红和蓝互换,那就把0x36命令里的 BGR 位取反;如果整个画面像倒过来了,就把列地址扫描顺序和行地址扫描顺序互换。
这些操作在代码里其实就是修改一个字节的事,但每次修改都要重新编译烧录。为了加快调试,可以把这个参数通过串口命令来动态修改,跑在 esp_console 里,不用重新烧录就能马上看到效果。我在实际开发中用这个方法把调屏时间压缩了至少一半。
6. 扩展思路:把驱动封装成可复用的模块
在线调试通过之后,我不建议把这一堆代码全部堆在main.c里。比较好的做法是把 SPI 初始化和 ST7789 的操作封装成独立的模块:比如st7789.h和st7789.c,只对外提供st7789_init、st7789_fill_screen、st7789_draw_bitmap、st7789_set_window这样的函数。接下来如果换成 ILI9341 或者 GC9A01,只需要换一套初始化函数,上层绘制代码完全可以复用,因为大家都遵循类似的窗口写入机制。
如果你的项目比这种裸操作更复杂一点,可以直接移植 LVGL,然后把 ST7789 作为 LVGL 的底层驱动。LVGL 自带了一套显示驱动接口,要求实现flush_cb回调,传入一个待刷新的矩形区域和像素缓冲区。你可以把前面讲到的st7789_set_window和 SPI 传输代码接进这个回调里,这样你就能使用 LVGL 的默认控件库和字体库来快速搭建界面。这个扩展方案对动态仪表盘、菜单系统特别有效,而且经过我实测,运行得很稳定。不过要注意 LVGL 版本和 ESP-IDF 版本的匹配关系,不同小版本间的接口有差异,卡住了就先查日志。
另外,有条件的话,尽量把时钟频率、DMA 通道、引脚定义这些编译期常量统一放在一个配置头文件里。这样后续换板子、换引脚,只需要修改这一个文件,再重新编译,就能快速适配新硬件。这个习惯在我手上救过我好几次,特别是当你同时维护好几块不同屏幕的开发板时,优势尤其明显。别嫌麻烦,前期花十分钟把配置抽出来,后期省下的时间绝对不止十分钟。