ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

ESP32-S3驱动1.69寸电容触摸屏:LVGL显示与触摸坐标对齐实战

ESP32-S3驱动1.69寸电容触摸屏:LVGL显示与触摸坐标对齐实战 简介面向嵌入式与物联网开发者的 ESP32S3LVGL 触摸屏驱动资源围绕 1.69 英寸电容触摸屏提供完整图形界面实现方案。显示侧采用 ST7789 控制器通过 SPI 接口传输图像数据触摸侧采用 CST816 芯片支持多点触控并通过 I2C/SPI 与主控通信。内容重点解决两块控制器的初始化与驱动适配包括屏幕初始化时序、SPI 时钟配置、触摸中断处理、坐标上报格式等关键细节同时将 CST816 的触摸数据接入 LVGL 触摸输入层注册回调函数完成点击、滑动等用户交互涵盖 LVGL 8 的配置方式和移植要点适合正在做小型彩屏人机界面或物联网可视化项目的中级嵌入式开发者参考也可作为快速搭建触摸界面的起步模板。压缩包共 971 个文件约 17.39MB以 C/H 源码、Python 脚本、Markdown/RST 文档、PNG/GIF 图片、FNT 字体及 JSON 配置为主既有源码示例也有说明文档与构建配置便于对照实验和二次开发。目前已有 6160 人学习使用结合实际硬件调整参数后即可在此基础上扩展页面控件、动画效果与业务逻辑。1. ESP32-S3 LVGL 驱动 1.69 寸电容触摸屏先打通显示和触摸两条链路「ESP32-S3 驱动 1.69 寸电容触摸屏跑 LVGL」听起来是件很常规的事真正动手时却最容易在两个地方翻车屏能点亮但触摸没反应或者触摸能用但坐标和显示完全对不上。我见过不少人被「只需四根线」的说法误导结果卡在 SPI 和 I2C 两套驱动上一卡就是两三天。本文就是顺着这条落地路径走一遍先分立验证显示和触摸再交给 LVGL 统一调度最后处理坐标对齐和性能。适合手里已经有一块 1.69 寸电容触摸屏想用 ESP32-S3 做出可交互界面的开发者已经用过 LVGL 的人可以直接跳到坐标对齐那一章。这块屏虽然小但当显示刷新、触摸采样和 LVGL 的刷新机制对齐后跑一个三五百行的 UI 完全够用。2. 屏和触摸是两条独立链路读懂 1.69 寸电容触摸屏的硬件组成2.1 常见驱动组合与引脚识别ST7789V CST816S1.69 寸电容触摸屏是一个「显示 触摸」的合屏模组。显示这边绝大多数用的是 ST7789V 这类 SPI 接口的彩色驱动 IC触摸这边常见的是 CST816S走 I2C 接口。这个组合的好处是 ESP32-S3 只需要一组 SPI 加一组 I2C总共七八个引脚就能同时覆盖显示和触摸如果换成了电阻触摸屏还要额外占用两个 ADC 通道反而更麻烦。我一般在拿到模块后先不看丝印直接把排针标号抄下来分成两组一组是 SPI 信号分别是 CLK、MOSI、CS、DC、RST再带上 BL 背光另一组是触摸信号常见的是 T_SDA、T_SCL、T_INT有的板子还会给 T_RST。这组信号中T_RST 不是必须的因为很多触摸控制器的复位可以和显示复位共用或者模块内部已经做了 RC 复位电路。不过我会建议你单独引一根出来排错的时候很有用后面第 5 章的避坑记录里会看到原因。下面这个表是我常用的接线约定具体 GPIO 号根据开发板的引出情况自行调整信号建议 GPIO说明LCD_SCLKGPIO12SPI 时钟LCD_MOSIGPIO11主机输出屏端输入LCD_CSGPIO10片选低有效LCD_DCGPIO9数据/命令选择LCD_RSTGPIO8复位低有效LCD_BLGPIO7背光高电平点亮TOUCH_SDAGPIO4I2C 数据TOUCH_SCLGPIO5I2C 时钟TOUCH_INTGPIO6触摸中断可不上拉有两点要提前确认第一1.69 寸这类小屏的背光电流通常不大直接由 GPIO 驱动没问题但如果你遇到背光闪烁就在 BL 到 GND 之间加一个 100nF 电容或者用三极管驱动第二I2C 的 SDA/SCL 必须在模块端有 4.7kΩ 左右的上拉电阻。很多触摸模块出厂时把这组电阻也焊上了但有些廉价款会省略这时候需要在外部再加两个上拉电阻否则触摸会时好时坏。先把这个硬件前提理清楚后面所有软件问题都不会指向接线错误。提示在跑任何软件之前用万用表量一次 VCC 对 GND 的阻值以及 RST 引脚对上电瞬间的复位波形。这样能省下一整天排查玄学问题的时间。2.2 点亮 LCDSPI 初始化、复位时序和最小命令序列我常用的方式是基于 ESP-IDF 的 SPI 主机接口先把总线初始化出来再注册一个设备给屏幕。下面是最小代码关键参数都写了注释#include driver/spi_master.h #define PIN_LCD_SCLK GPIO_NUM_12 #define PIN_LCD_MOSI GPIO_NUM_11 #define PIN_LCD_CS GPIO_NUM_10 #define PIN_LCD_DC GPIO_NUM_9 #define PIN_LCD_RST GPIO_NUM_8 #define PIN_LCD_BL GPIO_NUM_7 #define LCD_H_RES 240 #define LCD_V_RES 280 spi_device_handle_t spi_lcd; static void lcd_spi_init(void) { spi_bus_config_t bus_cfg { .sclk_io_num PIN_LCD_SCLK, .mosi_io_num PIN_LCD_MOSI, .miso_io_num -1, // 写屏为主不读数据就用不到 MISO .quadwp_io_num -1, .quadhd_io_num -1, .max_transfer_sz LCD_H_RES * LCD_V_RES * 2, }; esp_err_t ret spi_bus_initialize(SPI2_HOST, bus_cfg, SPI_DMA_CH_AUTO); ESP_ERROR_CHECK(ret); spi_device_interface_config_t dev_cfg { .clock_speed_hz 40 * 1000 * 1000, // 小屏跑 40MHz 很稳 .mode 0, // ST7789V 用 mode 0 或 mode 3 .spics_io_num PIN_LCD_CS, .queue_size 7, }; ret spi_bus_add_device(SPI2_HOST, dev_cfg, spi_lcd); ESP_ERROR_CHECK(ret); }这里有两处要说明。一是max_transfer_sz我直接给了整帧的字节数240*280*2这样后续一帧一次性 DMA 发送也不会被限制如果你内存紧张可以改成240*280*2/8甚至更小但每次 flush 的数据块就不能超过这个值。二是mode 0ST7789V 支持 mode 0 和 mode 3都表现为能点亮但在高速 SPI 下 mode 0 更常见如果你发现画面有规律错位可以试 mode 3这属于换着试的范畴。点亮屏幕还需要一套初始化命令。我不建议把某家供应商的几十条初始化序列原封不动贴进来最关键是以下几条static void lcd_write_cmd(uint8_t cmd) { gpio_set_level(PIN_LCD_DC, 0); spi_transaction_t t { .length 8, .tx_buffer cmd }; spi_device_polling_transmit(spi_lcd, t); } static void lcd_write_data(const uint8_t *data, size_t len) { gpio_set_level(PIN_LCD_DC, 1); spi_transaction_t t { .length len * 8, .tx_buffer data }; spi_device_polling_transmit(spi_lcd, t); } static void lcd_init_sequence(void) { gpio_set_level(PIN_LCD_RST, 0); vTaskDelay(pdMS_TO_TICKS(20)); // 复位低电平保持时间 gpio_set_level(PIN_LCD_RST, 1); vTaskDelay(pdMS_TO_TICKS(120)); // 退出复位要等稳定 lcd_write_cmd(0x11); // Sleep Out vTaskDelay(pdMS_TO_TICKS(120)); uint8_t madctl 0x00; // 默认扫描方向先让画面正常 lcd_write_cmd(0x36); lcd_write_data(madctl, 1); uint8_t pixfmt 0x55; // RGB56516位色 lcd_write_cmd(0x3A); lcd_write_data(pixfmt, 1); lcd_write_cmd(0x29); // Display ON vTaskDelay(pdMS_TO_TICKS(20)); gpio_set_level(PIN_LCD_BL, 1); }在初始化里0x36是内存访问控制它会同时影响 RGB 顺序、行/列扫描方向和显示刷新方向这个寄存器是你后面做坐标对齐的老朋友0x3A设置像素格式为0x55意思是 16 位 RGB565。0x11退出睡眠后必须等待 120ms 左右否则后续命令可能被忽略表现就是背光亮但屏幕一直是白屏。这一整套跑完后如果屏有背光但没有任何颜色变化试着在0x29后面加读返回状态大多数时候是 SPI 引脚映射写错或者 DC 高低电平反了。2.3 让触摸独立工作I2C 读 CST816S 坐标并打印验证触摸这边不需要任何初始化序列上电后用 I2C 扫描到0x15这个地址就算基本通了。CST816S 的触摸坐标寄存器在不同批次上存在差异所以我习惯一次性读 6 个字节打印出来看#include driver/i2c.h #define TOUCH_ADDR 0x15 void touch_i2c_init(void) { i2c_config_t conf { .mode I2C_MODE_MASTER, .sda_io_num GPIO_NUM_4, .scl_io_num GPIO_NUM_5, .sda_pullup_en GPIO_PULLUP_ENABLE, .scl_pullup_en GPIO_PULLUP_ENABLE, .master.clk_speed 400000, // 触摸 IC 允许 400KHz }; i2c_param_config(I2C_NUM_0, conf); i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0); } bool touch_read_raw(uint8_t raw[6]) { i2c_cmd_handle_t cmd i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (TOUCH_ADDR 1) | I2C_MASTER_WRITE, true); i2c_master_write_byte(cmd, 0x00, true); // 从寄存器 0x00 开始连续读 i2c_master_start(cmd); i2c_master_write_byte(cmd, (TOUCH_ADDR 1) | I2C_MASTER_READ, true); i2c_master_read(cmd, raw, 6, I2C_MASTER_LAST_NACK); i2c_master_stop(cmd); esp_err_t ret i2c_master_cmd_begin(I2C_NUM_0, cmd, 100 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); return ret ESP_OK; }读到raw[0]到raw[5]后先不要急着解析。在开发板下载口接一组串口日志手指按住触摸屏的不同位置把 6 个字节全部打印出来。按下与抬起之间至少会有一个字节出现连续变化常见布局是raw[1]的 bit0 表示触摸状态raw[2]是高 4 位坐标raw[3]是低 8 位raw[4]和raw[5]同理。有的模块会把坐标整体右移一位这就是为什么直接抄网上的寄存器表不一定好使。打印两三次后你就知道自己的板子用哪种映射。我一般会在这一步先验证一下坐标范围。用指尖从左上角滑到右下角记录数值如果最大值在 240 和 280 附近说明坐标是屏幕物理分辨率如果跑满 4095说明它工作在低分辨率模式需要检查触摸 IC 上电后的输出配置。CST816S 的坐标位数可以通过寄存器配置但绝大多数模块出厂已经设好不用额外写。I2C 连不上时优先检查触摸 IC 的复位引脚很多模块的触摸复位会被显示复位一起拉低导致上电后触摸 IC 还没从复位中释放I2C 扫描就会失败。这一步独立跑通后再进 LVGL你会少掉一半的排错烦恼。接下来我们把这两条链路交给 LVGL 来调度。3. LVGL 移植显示 driver 和触摸 driver 的接入方式决定一切3.1 lv_conf.h 里的关键开关LV_COLOR_DEPTH、字体和 tick 设置LVGL 本身不是驱动库它只是定义了一套显示驱动接口和刷新流程。所以第一步不是写代码而是把lv_conf.h里几个关键开关打开。这里我默认用 LVGL v8.3.x接口稳定网上资料也多如果你用的是 v9接口名会变我将在 3.4 里给出区别表底层思路完全一致。我常用的一组最小配置如下#define LV_COLOR_DEPTH 16 // 匹配 ST7789V 的 RGB565 #define LV_USE_LOG 1 #define LV_LOG_PRINTF 1 #define LV_TICK_CUSTOM 0 // 使用外部 tick 源 #define LV_USE_ASSERT_NULL 1 #define LV_FONT_MONTSERRAT_16 1 #define LV_FONT_MONTSERRAT_24 1 #define LV_USE_PERF_MONITOR 1LV_COLOR_DEPTH必须和屏幕像素格式一致这一项设错会直接导致颜色错乱。LV_USE_PERF_MONITOR是我强烈建议打开的它会在屏幕上画出帧率统计后期定位性能问题非常有用量产前再关掉。LV_FONT_MONTSERRAT_24对应 1.69 寸屏上的可读字号如果没有启用你调用lv_label_set_text时界面会只显示空白。LV_TICK_CUSTOM的原则是如果系统里已经有 1ms 的定时器就通过lv_tick_inc(1)喂给 LVGL如果没有才打开LV_TICK_CUSTOM。ESP-IDF 环境下我推荐用esp_timer创建一个 1ms 周期回调实际过程是这样的static void lv_tick_cb(void *arg) { lv_tick_inc(1); } void lvgl_tick_init(void) { esp_timer_handle_t tick_timer; esp_timer_create_args_t tick_args { .callback lv_tick_cb, .arg NULL, .name lv_tick, }; esp_timer_create(tick_args, tick_timer); esp_timer_start_periodic(tick_timer, 1000); // 每 1ms 触发一次 }注意 1ms 的周期是 LVGL 动画和输入事件的基础心跳如果周期偏大动画卡顿、触摸响应延迟会一并出现。esp_timer 的回调上下文不能做耗时操作这里只是累加一个计数完全没问题。3.2 注册显示设备flush_cb 要遵守的规则LVGL 把屏幕抽象成一个lv_disp_drv_t。注册显示设备时只需要告诉它屏幕的逻辑分辨率、绘制缓冲区和刷新回调。下面是 v8 的注册方式static lv_disp_draw_buf_t draw_buf; static lv_color_t buf[240 * 280 / 10]; // 1/10 屏的绘制缓冲区 void lvgl_display_init(void) { lv_disp_draw_buf_init(draw_buf, buf, NULL, 240 * 280 / 10); lv_disp_drv_t disp_drv; lv_disp_drv_init(disp_drv); disp_drv.hor_res 240; disp_drv.ver_res 280; disp_drv.flush_cb st7789_flush; disp_drv.draw_buf draw_buf; disp_drv.full_refresh false; // 允许局部刷新 lv_disp_drv_register(disp_drv); }缓冲区大小是个权衡。1/10 屏大概是 240*28 个像素在内存占用和刷新速度之间比较均衡。如果你的 UI 里有大面积动态图像可以改成 1/4 屏甚至使用双缓冲lv_disp_draw_buf_init(draw_buf, buf1, buf2, SIZE)但 ESP32-S3 整体 RAM 有限整屏双缓冲会吃 134KB 内存除非你外挂 PSRAM否则我不建议。full_refreshfalse让 LVGL 只更新脏区域这对小屏相当重要能减少无谓的 SPI 传输。st7789_flush是真正的关键时刻。LVGL 会调用这个回调告诉你要更新的矩形区域area和缓冲区color_p你需要把这片区域的像素搬到屏幕上并在完成后通知 LVGL。示例代码static void st7789_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p) { uint32_t w lv_area_get_width(area); uint32_t h lv_area_get_height(area); st7789_set_window(area-x1, area-y1, area-x2, area-y2); st7789_push_pixels((uint8_t *)color_p, w * h * 2); lv_disp_flush_ready(drv); }st7789_set_window向屏幕写入列地址0x2A和行地址0x2B然后写 RAM0x2C。st7789_push_pixels可以直接复用前面 SPI 设备的spi_device_polling_transmit把color_p的原始内存作为tx_buffer发出去。这里需要注意的是color_p的字节序问题。LVGL 内部根据LV_COLOR_DEPTH16来存储颜色在 ESP32-S3 上就是一个 16 位小端整数而 ST7789V 的 RGB565 也希望收到先低位后高位的字节流。大多数情况下这两个字节序天然一致直接发即可如果出现红色和蓝色互换不要急着改像素格式而是先去排查初始化里的0x36RGB 位。不能忘记的是lv_disp_flush_ready(drv)。LVGL 依靠这个函数确认缓冲区已被释放。如果你用了 DMA 异步发送必须在发送完成中断或回调里调用如果漏掉它绘制流程会卡死表现为画面只有第一帧或持续卡顿。3.3 注册输入设备read_cb 的写法与调用频率触摸屏在 LVGL 里注册成LV_INDEV_TYPE_POINTER输入设备。LVGL 会周期性调用read_cb因此在回调里尽量只做缓存读和状态转换不要把耗时的 I2C 多次读取放在这里。示例static void touchpad_read(lv_indev_drv_t *drv, lv_indev_data_t *data) { static uint16_t last_x 0, last_y 0; static bool last_pressed false; uint16_t x, y; bool pressed; if (touch_read_point(x, y, pressed)) { last_x x; last_y y; last_pressed pressed; // 在这里可以加入旋转映射函数 map_touch_coords(...) } >#define TOUCH_MAX_X 240 #define TOUCH_MAX_Y 280 void map_touch_coords(uint16_t tx, uint16_t ty, uint16_t *dx, uint16_t *dy, uint8_t rot) { switch (rot) { case 0: // 0 度原样 *dx tx; *dy ty; break; case 1: // 90 度交换 X/Y修正新 X *dx ty; *dy TOUCH_MAX_X - 1 - tx; break; case 2: // 180 度 *dx TOUCH_MAX_X - 1 - tx; *dy TOUCH_MAX_Y - 1 - ty; break; case 3: // 270 度 *dx TOUCH_MAX_Y - 1 - ty; *dy tx; break; default: break; } }这个映射的正确性依赖于TOUCH_MAX_X和TOUCH_MAX_Y的原始值。比如 1.69 寸屏物理分辨率是 240宽x 280高如果触摸 IC 输出的 X 范围是 240Y 范围是 280那上面公式成立但如果你之前为了不裁剪画面把 LVGL 设置成了 280x240 横屏这里的TOUCH_MAX_X和TOUCH_MAX_Y还是横屏时用的 240 和 280映射就会出错。所以第一步还是在 2.3 里的打印结果里确认触摸最大坐标。把rot从 0 到 3 依次试一遍总有一个方向是对的这不是土办法而是因为触摸 IC 和 LCD 之间的装配误差本来就是批次性的先枚举再固化是更可靠的落地路径。4.3 三招验证触摸映射打印坐标、十字线和四角标定试映射前不要直接跑业务界面先用三个手段确认。第一在 LVGL 里放一个标签实时显示触摸坐标同时用串口打印原始坐标和映射后的坐标手指从左上角划到右下角观察两个坐标的关系。第二画一个全屏十字线横竖各一条点击交叉点附近看点击高亮是否跟随手指。第三四角标定依次点击屏幕四个角对比坐标是否分别接近(0,0)、(W-1,0)、(0,H-1)、(W-1,H-1)。如果四个角的误差不大但整体有偏移可能不是方向问题而是屏幕区域有边框。很多 1.69 寸模组本身带有一个约 2~3 像素的触摸边距触摸原点并不在 LCD 显示区域的真正角落。此时可以在映射函数里加上偏移量#define TOUCH_OFFSET_X 2 #define TOUCH_OFFSET_Y 2 // 在每路选择映射前先做裁剪 if (tx TOUCH_OFFSET_X) tx 0; else tx - TOUCH_OFFSET_X; if (ty TOUCH_OFFSET_Y) ty 0; else ty - TOUCH_OFFSET_Y;这一步做完后再进 LVGL demo。如果只是方向不平上面rot试一次就搞定如果需要修正偏移那这已经是可用性达标的状态。至于更严格的九点校准在小尺寸电容屏上没必要因为线性度通常很好反而是校准表会占用大量内存。四角验证足够。5. 避坑清单ESP32-S3 接 1.69 寸电容触摸屏的五个高频排错点5.1 屏亮但画面花屏或白屏现象背光正常但整屏显示乱码或者一直白屏没有任何内容。 原因最常见有三类SPI 的 mode 设错导致采样沿不对max_transfer_sz太小一次传输被截断初始化命令没有按顺序执行尤其0x11后的延时不够。 解决先把 SPI 速度降到 26MHzmode 固定 0 和 3 各试一次max_transfer_sz给到一帧大小如果内存不够就给到 1/4 帧并确认 flush 的传输长度不超过它把0x11后的延时加到 150ms。白屏还有个容易被忽略的地方就是 DC 引脚接错命令和数据全被当成命令处理表现是屏幕一直显示一块固定颜色但没图形。5.2 I2C 扫描不到触摸地址现象用 I2C scanner 扫描一路都扫不到0x15触摸完全无响应。 原因排线接线错位、I2C 上拉电阻缺失、触摸 IC 的复位没有释放或者触摸 IC 被拉进了睡眠模式。 解决先用万用表量 T_SDA/T_SCL 到 VCC 的电压正常应接近 3.3V 高电平再确认模块的触摸复位引脚 T_RST 没有被误拉低可以在初始化时把 T_RST 拉高并保持。某些模块的触摸复位和 LCD 复位共用引脚如果 LCD 初始化最后把复位引脚一直拉低触摸 IC 就永远处于复位态这在排针编号不清晰时非常隐蔽。解决方法是初始化结束后把 RST 全部拉高再扫描 I2C。5.3 触摸能读但坐标完全反了现象手指点在左上角光标出现在右下角或者左右镜像、上下颠倒。 原因触摸 IC 和 LCD 被屏幕接线方向定义成了不同的原点LVGL 侧又开启了不同角度的旋转。 解决先固定一个显示扫描方向比如通过0x36让画面在正向安装时正常然后在read_cb里用 4.2 的map_touch_coords枚举四种rot。不要同时改0x36和映射函数两处一起改会很难判断到底差在哪。确认方案后把映射固化再裁剪TOUCH_MAX_X/Y到屏幕实际范围。5.4 颜色不对红色和蓝色互换现象显示烧录图片时肤色全偏成绿色或者条形图里红蓝对调。 原因SPI 发送的是 LVGL 生成的小端 16 位颜色而屏端按大端 RGB565 处理或者0x36里的 BGR 位被设成了相反值。 解决优先改0x36的 RGB 顺序位而不是去改lv_color_t的存储方式。记住LV_COLOR_DEPTH16只是确定每个像素两个字节没有规定这两个字节的发送顺序。如果你用 DMA 发送时发现每次总是低字节先出去而屏希望高字节先到就需要在st7789_push_pixels里做一次字节交换或者设置MADCTL的 BGR 位。对 ST7789V 来说正确设置0x36后就不需要额外交换。5.5 LVGL 偶尔卡死或复位现象UI 运行几分钟后ESP_ERROR_CHECK报 SPI timeout或者看门狗复位debug 里看到 LVGL 断言在 flush 回调。 原因flush 回调里使用的是阻塞spi_device_polling_transmit当 LVGL 刷新频率高时 SPI 传输容易排队超时也可能绘制缓冲区太大超过了默认任务栈。 解决第一把 flush 里的 SPI 发送改成spi_device_transmit它使用中断不会占用调用线程第二确认任务栈至少给到4096字节把 LVGL 的绘制和刷新放在独立任务里不要让它在低栈空间里跑第三如果还卡把绘制缓冲区从 1/4 屏降到 1/10 屏降低每帧传输量。这几个参数互相影响改一个不够就三个一起调。6. 进阶验证刷新帧率、减小 LVGL 内存占用与后续优化到这一步屏幕已经能正常显示、触摸也能点准了但这个项目还不算真正立住了。我通常会在交付前做两件事先用性能数据验证整体流畅度再根据数据决定要不要继续压缩内存。LVGL v8 自带的LV_USE_PERF_MONITOR会在屏幕右上角显示一个刷新率数值这是最直接的办法。如果你的 UI 只有几个页面切换数值一般能达到 30 FPS 左右如果低于 15 FPS就要考虑绘制缓冲区大小或 SPI 频率了。如果你想自己统计也可以开一个定时器统计每秒调用lv_task_handler的次数static uint32_t task_cnt 0; static void count_task(void *arg) { task_cnt; } static void fps_timer_cb(lv_timer_t *t) { static uint32_t last_cnt 0; uint32_t now_cnt task_cnt; ESP_LOGI(perf, fps: % PRIu32, now_cnt - last_cnt); last_cnt now_cnt; }这只是个统计手段重点是后续优化方向。如果 CPU 占用率不高但帧率低问题多半在 SPI 传输和 LVGL 的单缓冲等待如果 CPU 占用率接近 100%问题在绘制开销。对 1.69 寸屏我常用的三个优化手段依次是绘制缓冲区改为双缓冲约 1/4 屏让 LVGL 在绘制下一帧时上一帧还能并行传输SPI 开启 40MHz 以上并启用 DMA如果 UI 全都是扁平色块和文字把LV_COLOR_DEPTH从 16 降为 8 位调色板能显著减内存但代价是不能显示透图和色彩丰富的图片。图形库里还要记得关掉阴影、透明度和动画特效这些在 1.69 寸小屏上效果有限却会直接拖慢刷新。我自己的习惯是把这套显示驱动封装成独立模块st7789_init、touch_init、lvgl_init三个函数彼此解耦这样换另一块 1.69 寸屏时只需要改驱动参数。前期这些驱动层面被验证好了后面所有 LVGL 界面开发才不会反复迁就硬件层的意外。希望这套来自采坑经验的接法能帮到你。本文还有配套的精品资源点击获取
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表