十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ESP32S3驱动ST7796屏移植LVGL:从硬件选型到UI实战

ESP32S3驱动ST7796屏移植LVGL:从硬件选型到UI实战 简介本资源是一套基于ESP32-S3开发板驱动3.5英寸ST7796 IPS显示屏320×480并集成FT6336触控芯片的LVGL图形界面基础工程面向嵌入式开发者、物联网项目实践者及LVGL初学者解决硬件适配、触摸校准与GUI快速启动等典型开发痛点。压缩包共15个文件含4个C源文件实现LCD初始化、触摸读取与LVGL渲染、3个头文件含关键配置宏如DISPLAY_INVERT_COLOR、3个文本类文件README说明、分区表partitions.csv、依赖锁dependencies.lock以及sdkconfig、idf_component.yml等构建必需项整体仅44KB轻量易导入。已有110人学习下载资源结构清晰main/目录封装核心逻辑config.h支持IPS/non-IPS屏一键切换backlight.h/c提供亮度控制lcd_lvgl.c完成LVGL端口对接开箱即可编译运行基础UI示例大幅降低LVGL在ESP32-S3ST7796平台的入门门槛。1. 项目概述为什么是ESP32S3、ST7796与LVGL的组合最近在捣鼓一个需要显示复杂UI的嵌入式小项目选型时在ESP32家族里纠结了很久最终敲定了ESP32S3。原因很简单它内置的PSRAM对于图形界面来说简直是“救命稻草”。LVGL这个轻量级图形库功能强大但吃内存也是出了名的尤其是当你想要流畅的动画和多个控件时。ESP32S3提供高达8MB的片上PSRAM这让我在分配帧缓冲区和图形对象时从容了不少不必再像以前用STM32那样每个像素都要精打细算。显示部分我选择了一块3.5寸的ST7796驱动的IPS触摸屏。这个尺寸在嵌入式设备里算是个“甜点”尺寸足够显示丰富的信息又不会大到让整个设备显得笨重。ST7796这款驱动芯片支持SPI接口虽然速度上比并口慢但它极大地节省了MCU的引脚对于ESP32S3这种引脚虽然多但可能被各种功能占用的芯片来说SPI接口的简洁性非常有吸引力。更重要的是市面上很多3.5寸屏都采用了这款驱动资源丰富调试时能找到的参考也多。所以这个“基础工程”的目标就很明确了搭建一个最简可行、稳定可靠的软硬件框架让ESP32S3能够通过SPI驱动ST7796显示屏并成功运行LVGL库创建出第一个可交互的界面。这就像盖房子先打地基这个基础打好了后续往上添加各种复杂的UI功能、连接网络、处理数据都会顺畅很多。无论你是想做一个智能家居的中控面板、一个便携式仪器仪表还是一个带界面的小玩具这个工程都是你的起点。2. 硬件选型与核心电路设计解析硬件是这一切的基础选择不当会让软件调试变得异常痛苦。这里我详细拆解一下各个部分的选择理由和连接要点。2.1 主控芯片ESP32S3的关键优势为什么不是ESP32或ESP32-C3ESP32S3在图形应用上的优势是决定性的。双核Xtensa® LX7处理器主频高达240MHz为LVGL的渲染、用户输入处理和你的业务逻辑提供了充沛的计算能力。你可以将LVGL的定时器任务和渲染任务放在一个核心网络或传感器处理放在另一个核心有效避免界面卡顿。大容量片上PSRAM这是最核心的一点。我使用的型号搭载了8MB的PSRAM。LVGL推荐使用双缓冲两个完整的屏幕帧缓冲区来获得最流畅的体验。对于320x480的16位色RGB565屏幕一帧图像需要320 * 480 * 2 bytes 307,200 bytes即约300KB。双缓冲就需要600KB。这还没算LVGL内部的对象、样式等内存开销。如果没有这片PSRAM仅靠芯片内部的SRAM通常几百KB会非常拮据甚至无法实现。丰富的SPI外设ESP32S3有多个SPI控制器SPI2 SPI3。我们可以分配一个专用的SPI总线如SPI2给屏幕另一个如SPI3给触摸芯片或者共用总线但使用不同的CS引脚。硬件SPI的效率远高于软件模拟是流畅刷新的保证。足够的GPIO驱动屏幕和触摸需要一组SPI引脚外加背光控制、复位等引脚。ESP32S3的GPIO数量足以应对并且很多引脚功能可以复用布局灵活。2.2 显示屏模块ST7796 SPI接口屏详解市面上3.5寸屏规格繁多选购和连接时要认准以下几点接口确认是SPI接口而非并口如8080或RGB。SPI屏的引脚通常包括SCK时钟、MOSI主机输出从机输入即数据线、DC数据/命令选择、CS片选、RST复位可选、BL背光控制可选。分辨率常见的是320x480。购买时务必确认这直接影响驱动配置和内存计算。驱动芯片必须是ST7796。不同驱动芯片的初始化命令序列Register完全不同。触摸芯片通常集成在屏的FPC上最常见的是XPT2046。它是一个通过SPI通信的电阻式触摸控制器。需要另一组SPI引脚或与显示驱动共用SPI总线连接T_CS触摸片选、T_CLK、T_DIN、T_DOUT、T_IRQ中断引脚强烈建议使用。我的连接方案以ESP32S3-DevKitC-1为例屏幕引脚ESP32S3 GPIO功能说明VCC3.3V电源务必接3.3V接5V会烧毁GNDGND地SCL/SCKGPIO 12SPI时钟线SDA/MOSIGPIO 11SPI数据输出线RES/RSTGPIO 10复位低电平有效DC/A0GPIO 9数据/命令选择高数据低命令CSGPIO 8显示屏片选低电平有效BLGPIO 38背光控制高电平点亮有些屏是低电平有效需注意T_CLKGPIO 7触摸SPI时钟可与显示SCK共用但独立更清晰T_CSGPIO 6触摸片选T_DINGPIO 5触摸SPI数据输入主机输出T_DOUTGPIO 4触摸SPI数据输出主机输入T_IRQGPIO 3触摸中断低电平表示有触摸事件注意1电源滤波。屏幕在刷新瞬间电流较大建议在屏幕的VCC和GND引脚附近并联一个100μF的电解电容和一个0.1μF的瓷片电容以稳定电源防止屏幕花屏或复位。注意2电平匹配。ESP32S3是3.3V逻辑电平确保你购买的屏幕模块也是3.3V兼容的。大部分SPI屏都是3.3V但购买前仍需确认。注意3GPIO分配。上述GPIO编号并非固定你可以根据开发板布局和布线方便性更改但要避免使用一些特殊启动引脚如GPIO0 GPIO45等。务必在代码中同步修改。2.3 开发环境搭建从VSCode到PlatformIO我强烈推荐使用VSCode PlatformIO的组合而不是传统的Arduino IDE。PlatformIO对ESP32的支持更专业库管理、项目配置、调试都更强大特别适合管理LVGL这样的多文件项目。安装VSCode从官网下载安装。安装PlatformIO插件在VSCode扩展商店搜索“PlatformIO IDE”并安装。创建新项目打开PIO主页点击“New Project”。项目名称输入esp32s3_st7796_lvgl。Board选择 “Espressif ESP32-S3-DevKitC-1”根据你的具体开发板型号选择。Framework选择 “Arduino” 或 “ESP-IDF”。对于快速上手Arduino框架更简单如果需要更底层的控制和性能优化可以选择ESP-IDF。本文以Arduino框架为例。选择项目路径后点击“Finish”。项目创建好后你会在左侧看到项目结构。我们主要编辑src目录下的main.cpp以及配置platformio.ini文件。3. 软件架构与库依赖配置一个清晰的软件架构能让你后续的开发和维护事半功倍。这个基础工程主要包含三层硬件驱动层、LVGL库适配层、以及应用层。3.1 库依赖管理platformio.ini 的配置艺术platformio.ini是项目的核心配置文件它定义了芯片型号、框架、库依赖、编译参数等。一个配置得当的ini文件能解决大部分编译和链接问题。[env:esp32-s3-devkitc-1] platform espressif32 board esp32-s3-devkitc-1 framework arduino monitor_speed 115200 ; 启用PSRAM支持至关重要 board_build.arduino.memory_type qio_opi board_build.flash_mode qio board_build.partitions huge_app.csv ; 库依赖 lib_deps ; 1. TFT_eSPI强大的显示屏驱动库支持ST7796 bodmer/TFT_eSPI^2.5.0 ; 2. LVGL核心图形库 lvgl/lvgl^8.3.11 ; 3. XPT2046_Touchscreen触摸驱动库 PaulStoffregen/XPT2046_Touchscreen^1.4 ; 编译优化提升性能 build_flags -O2 -D LV_CONF_INCLUDE_SIMPLE1 ; 允许使用PSRAM -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ; 启用LVGL的Arduino框架支持 build_unflags -stdgnu11 lib_ldf_mode deep关键点解析board_build.arduino.memory_type qio_opi和board_build.partitions huge_app.csv这两个配置对于启用和访问ESP32S3的PSRAM至关重要。huge_app分区表为应用程序和PSRAM使用提供了更大空间。lib_depsPlatformIO会自动从库仓库下载并管理这些库。TFT_eSPI是我们驱动屏幕的桥梁lvgl是本体XPT2046_Touchscreen负责读取触摸坐标。build_flags中的-DBOARD_HAS_PSRAM和-mfix-esp32-psram-cache-issue告诉编译器我们拥有PSRAM并应用一个针对ESP32 PSRAM缓存问题的修复补丁这对稳定性很重要。lib_ldf_mode deep确保链接器能够找到所有必要的库文件特别是LVGL这种结构稍复杂的库。3.2 驱动层配置TFT_eSPI库的User_Setup.hTFT_eSPI库非常强大但需要通过编辑其用户配置文件来适配具体屏幕。这个文件通常位于项目目录/.pio/libdeps/你的环境名/TFT_eSPI/User_Setup.h。你也可以在项目根目录下创建一个User_Setup.h文件然后通过build_flags指定路径这样更利于版本管理。以下是针对ST7796 3.5寸 SPI屏的核心配置// User_Setup.h #define USER_SETUP_INFO ESP32S3_ST7796_3.5_SPI // 1. 选择驱动芯片 #define ST7796_DRIVER // 2. 定义屏幕尺寸 #define TFT_WIDTH 320 #define TFT_HEIGHT 480 // 3. 定义ESP32S3的引脚必须与硬件连接一致 #define TFT_CS PIN_D8 // 对应GPIO 8 #define TFT_DC PIN_D9 // 对应GPIO 9 #define TFT_RST PIN_D10 // 对应GPIO 10 #define TFT_BL PIN_D38 // 对应GPIO 38 // 4. 定义SPI总线 #define SPI_FREQUENCY 40000000 // 最大SPI时钟频率ST7796支持40MHz #define SPI_READ_FREQUENCY 20000000 // 读频率可以低一些 #define SPI_TOUCH_FREQUENCY 2500000 // 触摸芯片XPT2046工作在2.5MHz左右即可 // 5. 使用硬件SPI #define USE_HSPI_PORT // 对于ESP32S3HSPI (SPI2) 的默认引脚是 // SCK 12, MISO 13, MOSI 11 // 如果你的连接与此不同需要在这里重定义 #define TFT_SCLK PIN_D12 // GPIO12 #define TFT_MOSI PIN_D11 // GPIO11 // MISO引脚对于纯写的屏幕驱动可以不用接但建议接上以备诊断 // 6. 颜色格式和方向 #define TFT_RGB_ORDER TFT_RGB // ST7796是RGB顺序 #define TFT_INVERSION_ON #define TFT_ROTATION 0 // 00度190度2180度3270度 // 7. 字体和功能支持为LVGL准备 #define LOAD_GLCD // 默认字体 #define LOAD_FONT2 // 小号字体 #define LOAD_FONT4 // 中号字体 #define SMOOTH_FONT // 抗锯齿字体 #define SPI_32BIT_WRITE // 启用32位写操作提升SPI效率实操心得修改User_Setup.h后PlatformIO可能不会自动重新编译依赖库。最稳妥的方法是运行pio run -t clean清理编译缓存然后再重新编译上传。或者直接删除.pio/build目录。3.3 LVGL移植与初始化连接硬件与图形库LVGL本身是硬件无关的我们需要实现几个关键函数将LVGL的“画点”、“刷屏”、“输入读取”等抽象操作映射到我们的具体硬件TFT_eSPI和XPT2046上。首先在main.cpp中包含必要的头文件并定义全局对象#include Arduino.h #include TFT_eSPI.h #include lvgl.h #include XPT2046_Touchscreen.h // 硬件对象声明 TFT_eSPI tft TFT_eSPI(); XPT2046_Touchscreen ts(T_CS, T_IRQ); // 使用触摸片选和中断引脚 // LVGL显示缓冲区使用PSRAM #define LVGL_BUFFER_SIZE (TFT_WIDTH * 20) // 缓存20行像素 static lv_disp_draw_buf_t draw_buf; static lv_color_t *buf1; // 我们将把这个缓冲区分配到PSRAM接下来是核心的初始化函数setup()void setup() { Serial.begin(115200); Serial.println(ESP32S3 LVGL Demo Start); // 1. 初始化屏幕硬件 tft.init(); tft.setRotation(0); // 旋转方向需与User_Setup.h中一致 pinMode(TFT_BL, OUTPUT); digitalWrite(TFT_BL, HIGH); // 打开背光 // 2. 初始化触摸芯片 ts.begin(); ts.setRotation(0); // 触摸旋转校准可能需要根据实际调整 // 3. 初始化LVGL库 lv_init(); // 4. 在PSRAM中为LVGL分配显示缓冲区 // 这是流畅运行的关键 buf1 (lv_color_t*)ps_malloc(LVGL_BUFFER_SIZE * sizeof(lv_color_t)); if (buf1 NULL) { Serial.println(PSRAM allocation failed! LVGL will use internal SRAM (may be slow).); buf1 (lv_color_t*)malloc(LVGL_BUFFER_SIZE * sizeof(lv_color_t)); } else { Serial.println(PSRAM buffer allocated successfully.); } // 使用单缓冲区模式也可以配置双缓冲需要两倍内存 lv_disp_draw_buf_init(draw_buf, buf1, NULL, LVGL_BUFFER_SIZE); // 5. 注册显示驱动 static lv_disp_drv_t disp_drv; lv_disp_drv_init(disp_drv); disp_drv.hor_res TFT_WIDTH; disp_drv.ver_res TFT_HEIGHT; disp_drv.flush_cb my_disp_flush; // 实现刷屏回调函数 disp_drv.draw_buf draw_buf; lv_disp_drv_register(disp_drv); // 6. 注册输入设备驱动触摸屏 static lv_indev_drv_t indev_drv; lv_indev_drv_init(indev_drv); indev_drv.type LV_INDEV_TYPE_POINTER; indev_drv.read_cb my_touchpad_read; // 实现触摸读取回调函数 lv_indev_drv_register(indev_drv); // 7. 创建你的第一个UI create_ui(); Serial.println(Setup complete.); }4. 核心驱动回调函数实现这是连接LVGL抽象世界和硬件物理世界的桥梁。两个回调函数的实现至关重要。4.1 显示刷新回调my_disp_flush这个函数由LVGL在需要更新屏幕某块区域时调用。它的任务是将LVGL绘制好的内存缓冲区color_map的内容搬运到屏幕的指定区域area。void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) { uint32_t w (area-x2 - area-x1 1); uint32_t h (area-y2 - area-y1 1); // 启动TFT_eSPI的“窗口”写操作告诉屏幕我们要更新的区域 tft.startWrite(); tft.setAddrWindow(area-x1, area-y1, w, h); // 将LVGL的像素缓冲区推送到屏幕 // pushPixels函数能高效地通过SPI发送一批像素数据 tft.pushPixels((uint16_t*)color_p, w * h); tft.endWrite(); // 必须调用此函数告知LVGL刷新已完成 lv_disp_flush_ready(disp); }性能优化点pushPixels是TFT_eSPI库的优化函数它使用SPI的DMA如果支持或更高效的数据块传输方式比逐个像素调用drawPixel快几个数量级。startWrite()和endWrite()包裹了SPI事务的开始和结束确保数据传输的原子性避免被其他中断打断导致屏幕乱码。4.2 触摸输入回调my_touchpad_read这个函数由LVGL定期轮询或在中断模式下由事件触发以获取触摸状态和坐标。void my_touchpad_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data) { // 检查触摸芯片是否有触摸事件发生 if (ts.touched()) { // 获取原始坐标 TS_Point p ts.getPoint(); // XPT2046返回的坐标原点可能在屏幕角落且轴方向可能与显示屏不一致。 // 需要进行坐标转换和校准。 // 以下是一个常见的转换公式但强烈建议进行校准 int16_t x map(p.x, RAW_X_MIN, RAW_X_MAX, 0, TFT_WIDTH); int16_t y map(p.y, RAW_Y_MIN, RAW_Y_MAX, 0, TFT_HEIGHT); // 有时需要交换X/Y或取反取决于屏幕和触摸板的安装方向 // 例如 int16_t temp x; x y; y temp; // 或者 x TFT_WIDTH - x; y TFT_HEIGHT - y; >lv_obj_t *label_count; int count 0; void create_ui() { // 获取当前活跃的屏幕对象 lv_obj_t *scr lv_scr_act(); // 1. 创建一个按钮 lv_obj_t *btn lv_btn_create(scr); lv_obj_set_size(btn, 120, 50); // 设置大小 lv_obj_align(btn, LV_ALIGN_CENTER, 0, -40); // 居中并向上偏移40像素 lv_obj_add_event_cb(btn, btn_event_handler, LV_EVENT_ALL, NULL); // 添加事件回调 // 按钮上的标签 lv_obj_t *btn_label lv_label_create(btn); lv_label_set_text(btn_label, Click Me!); lv_obj_center(btn_label); // 2. 创建一个标签用于显示计数 label_count lv_label_create(scr); lv_label_set_text_fmt(label_count, Count: %d, count); // 格式化文本 lv_obj_align_to(label_count, btn, LV_ALIGN_OUT_BOTTOM_MID, 0, 20); // 对齐到按钮下方 // 3. 创建一个样式并应用到按钮可选 static lv_style_t style_btn; lv_style_init(style_btn); lv_style_set_bg_color(style_btn, lv_palette_main(LV_PALETTE_BLUE)); lv_style_set_bg_opa(style_btn, LV_OPA_COVER); lv_style_set_radius(style_style_btn, 10); lv_obj_add_style(btn, style_btn, 0); }5.2 事件处理函数btn_event_handler当按钮被点击、按下、释放时都会触发事件。我们在这里处理点击事件来增加计数。static void btn_event_handler(lv_event_t *e) { lv_event_code_t code lv_event_get_code(e); // 获取事件类型 if (code LV_EVENT_CLICKED) { count; // 更新标签文本 lv_label_set_text_fmt(label_count, Count: %d, count); Serial.printf(Button clicked! Count %d\n, count); } }5.3 LVGL任务处理器与内存管理LVGL本身不是多线程的它需要一个周期性的“心跳”来执行内部的任务比如动画处理、对象状态更新、输入设备读取等。这需要在loop()函数中调用lv_timer_handler()。void loop() { lv_timer_handler(); // 让LVGL运行其任务延迟约5ms delay(5); // 适当的延迟避免过度占用CPU }关于内存优化这是LVGL项目的重中之重缓冲区大小我们在初始化时设置了LVGL_BUFFER_SIZE为TFT_WIDTH * 20。这意味着LVGL一次渲染20行像素。这个值越大一次能渲染的区域就越大刷新复杂页面时需要的“刷新调用”次数就越少理论上更流畅。但会消耗更多内存。对于320x480的屏幕20行缓冲区占用约320*20*2 12.8KB。你可以根据可用PSRAM大小调整比如设置为30或40。切勿设置为整个屏幕大小300KB除非你的应用非常简单且内存极其充裕因为LVGL内部还有其他开销。对象和样式数量每个LVGL对象按钮、标签等和样式都会占用内存。避免创建大量永不隐藏或删除的对象。动态创建的对象在使用完后要用lv_obj_del(obj)及时删除。字体中文字体文件巨大。不要将整个字库加载到内存。使用LVGL的“字体分区加载”功能或者使用外部存储器如SD卡、SPIFFS存储字体并按需加载字形。监控内存可以使用ESP.getFreePsram()和ESP.getFreeHeap()在串口监视器中查看内存使用情况帮助你判断优化效果。6. 项目构建、调试与常见问题排查6.1 编译与上传在VSCode中点击PlatformIO工具栏底部的“→”箭头Upload按钮。PlatformIO会自动完成编译和上传。第一次编译会花费较长时间因为它需要下载所有依赖库。上传失败常见原因端口被占用关闭其他串口监视软件。开发板未进入下载模式ESP32S3需要手动进入下载模式。通常方法是按住开发板上的“BOOT”按钮再按一下“RST”按钮然后释放“BOOT”。有些开发板如DevKitC-1会自动检测下载信号。驱动问题确保电脑已安装ESP32S3的USB转串口驱动通常是CP210x或CH340。6.2 串口调试与信息输出打开PlatformIO的串口监视器Serial Monitor你将看到初始化信息。这是排查问题的第一现场。6.3 常见问题与解决方案速查表现象可能原因排查步骤与解决方案屏幕白屏或花屏1. 电源不稳定。2. SPI时钟频率过高。3. 引脚连接错误。4. 复位时序问题。1. 检查电源并靠近屏幕VCC加滤波电容。2. 在User_Setup.h中降低SPI_FREQUENCY如改为20000000。3. 用万用表逐一核对屏幕与ESP32的连线。4. 在setup()中tft.init()前手动控制RST引脚digitalWrite(TFT_RST, LOW); delay(50); digitalWrite(TFT_RST, HIGH); delay(120);触摸坐标完全不对1. 坐标转换公式错误。2. 触摸芯片旋转设置不对。3. X/Y轴需要交换或取反。1. 在my_touchpad_read中打印原始坐标p.x, p.y点击屏幕四角和中心记录数值重新计算map函数的参数。2. 调整ts.setRotation()的值0,1,2,3。3. 尝试在代码中交换>LVGL界面刷新极慢、卡顿1. 显示缓冲区太小。2. SPI频率太低。3. 未使用PSRAM内部SRAM不足。4.lv_timer_handler()调用间隔太长。1. 适当增大LVGL_BUFFER_SIZE。2. 在稳定前提下提高SPI_FREQUENCY。3. 确认buf1已成功从PSRAM分配看串口打印。4. 减少loop()中的delay或使用lv_tick_inc(5)配合非阻塞延时。编译错误未定义LVGL函数1. LVGL库版本不匹配。2.lv_conf.h配置问题。1. 在platformio.ini中固定LVGL版本为较新的稳定版如lvgl/lvgl^8.3.11。2. 确保lv_conf.h被正确包含。在platformio.ini中使用build_flags -D LV_CONF_INCLUDE_SIMPLE1让LVGL使用其自带的简化配置。也可以复制lvgl/lv_conf_template.h到项目目录并重命名为lv_conf.h进行详细配置。触摸无反应1. 触摸SPI引脚错误。2. 触摸芯片片选T_CS未正确拉低。3. 中断模式配置错误。1. 核对触摸SPI四根线CLK, DIN, DOUT, CS的连接。2. 检查XPT2046_Touchscreen ts(T_CS, T_IRQ);初始化是否正确。3. 如果使用中断确保T_IRQ引脚模式为上拉输入pinMode(T_IRQ, INPUT_PULLUP);并且中断服务程序正确设置标志位。先尝试轮询模式排除硬件问题。6.4 性能优化进阶技巧使用双缓冲区如果PSRAM足够可以分配两个缓冲区buf1和buf2并在lv_disp_draw_buf_init中同时传入。LVGL会在一个缓冲区渲染时另一个缓冲区用于发送到屏幕实现真正的并行最大限度提升流畅度。这需要你的my_disp_flush函数支持异步DMA传输并在传输完成后通过回调通知LVGL。TFT_eSPI库的pushPixelsDMA函数可以配合实现。优化LVGL的刷新区域确保你的my_disp_flush函数只更新area指定的区域而不是整个屏幕。我们的实现已经通过setAddrWindow做到了这一点。减少全局重绘在UI事件处理中只更新需要变化的部件而不是调用lv_obj_invalidate(scr)让整个屏幕重绘。谨慎使用透明度和阴影这些效果需要大量的混合计算会显著降低渲染速度。在性能敏感的界面中尽量避免。这个基础工程就像一把钥匙为你打开了用ESP32S3构建富交互式嵌入式图形应用的大门。代码框架是稳定的但触摸校准和性能调优需要你根据具体的硬件和项目需求进行细致的打磨。当你看到屏幕上第一个按钮随着你的点击而响应计数器数字跳动时后续所有复杂的UI设计都将基于这个稳固的基石展开。本文还有配套的精品资源点击获取
返回列表