简介:本资源是一套面向嵌入式开发初学者与物联网项目实践者的ESP32-S3图形界面入门工程,聚焦于3.5英寸ST7796 IPS显示屏(320×480)与FT6336触控芯片的软硬件协同驱动,基于LVGL 8.x构建可交互GUI基础框架。资源共15个文件,涵盖4个C源文件(实现LCD初始化、触摸读取、LVGL移植与主循环)、3个头文件(含关键配置config.h及屏驱接口定义)、3个文本类文件(README说明、分区表partitions.csv、依赖锁dependencies.lock),以及CMakeLists.txt、sdkconfig、idf_component.yml等构建与配置核心文件,总大小仅44KB,轻量易导入。已有110人学习下载,适合快速验证LVGL在ESP32-S3上的最小可行显示+触控系统。读者可直接编译烧录运行,获得完整LVGL初始化、屏幕颜色校准(含IPS/non-IPS双模式切换逻辑)、多点触摸坐标映射及基础UI渲染能力,并通过清晰的模块划分(lcd_lvgl.c、backlight.c、main.c分层)理解嵌入式GUI工程组织范式。
1. 项目缘起:为什么是ESP32S3、ST7796与LVGL的组合?
最近在捣鼓一个需要本地交互界面的嵌入式小项目,核心需求很简单:一块能流畅显示图形界面、支持触摸交互的屏幕,主控芯片要足够强大且性价比高。市面上方案很多,从经典的STM32+FSMC驱动TFT,到各种国产MCU,选择让人眼花缭乱。最终,我把目光锁定在了ESP32S3、3.5寸ST7796 SPI屏和LVGL这个组合上。这并非一时兴起,而是经过一番权衡后的选择。
首先看主控。ESP32S3是乐鑫在ESP32系列中的“性能担当”,双核240MHz的Xtensa LX7处理器,性能远超常见的STM32F4系列。更重要的是,它内置了8MB的PSRAM,这对于图形界面来说是“雪中送炭”。LVGL作为一款轻量级但功能强大的图形库,其流畅度很大程度上依赖于帧缓冲(Frame Buffer)。如果没有足够的内存做双缓冲甚至三缓冲,界面刷新时的撕裂感会非常明显。ESP32S3内置的PSRAM正好解决了这个痛点,让我们可以奢侈地开辟一块320x480x2(RGB565)约300KB的显存区域,而无需外挂RAM芯片,大大简化了硬件设计和成本。
其次是屏幕。3.5寸是一个在信息量和便携性之间取得很好平衡的尺寸。ST7796是一款非常成熟的驱动IC,支持RGB565 16位色,分辨率通常是320x480。我选择的是基于SPI接口的版本,而非并口(如8080或RGB)。原因在于,对于这个分辨率和刷新率需求,高速SPI(80MHz)在ESP32S3上完全够用,而且SPI接线简单(通常只需4-6根线:SCK, MOSI, MISO, DC, CS, RST),能节省大量宝贵的GPIO,留给其他传感器或外设。虽然SPI的理论极限吞吐量低于并口,但经过优化(使用ESP32的SPI DMA、LVGL的局部刷新机制),实际观感依然可以非常流畅。
最后是LVGL。它几乎成了开源嵌入式GUI的事实标准,生态丰富,文档相对完善,有强大的模拟器和丰富的控件。选择LVGL意味着你不用从零开始造轮子,社区里大量的示例和主题能极大加速开发。将这三者结合起来,目标就是搭建一个硬件成本可控、软件开发高效、最终体验流畅的嵌入式图形交互解决方案的基础工程。这个“基础工程”就像毛坯房,水电管线(驱动、配置)都已铺好,你拿到后可以专注于内部的装修(应用逻辑和界面设计)。
2. 硬件选型与核心电路连接要点
硬件是工程的基石,连接错误会导致后续调试困难重重。这里详细拆解ESP32S3与3.5寸ST7796 SPI触摸屏的硬件连接逻辑。
2.1 ESP32S3引脚规划与SPI外设选择
ESP32S3有多个SPI外设:SPI0、SPI1、SPI2(SPI2和SPI3是同一个,通常称为SPI2/3或FSPI)。SPI0和SPI1通常用于连接外部Flash和PSRAM,这是芯片启动和运行的基础,绝对不要占用。因此,我们可用的主要是SPI2(即FSPI,或标记为HSPI的兼容模式)。
我们需要为SPI屏分配以下引脚:
- SPI CLK (SCK):时钟线。选择SPI2的默认SCK引脚(GPIO12)或任何其他可用的IO。考虑到布线,我常用GPIO12。
- SPI MOSI (SDO):主设备输出,从设备输入。用于向屏幕发送命令和数据。SPI2的默认MOSI是GPIO11。
- SPI MISO (SDI):主设备输入,从设备输出。虽然ST7796屏在纯写入模式下可能不需要MISO,但为了后续可能读取屏幕ID或状态,建议连接。使用SPI2的默认MISO引脚GPIO13。
- DC (Data/Command):这是一个GPIO,用于告诉屏幕当前发送的是命令(拉低)还是数据(拉高)。这个引脚必不可少,必须单独占用一个GPIO,例如GPIO10。
- CS (Chip Select):片选线,低电平有效。当有多个SPI设备时,用于选择当前通信的设备。即使只有一个屏幕,也建议连接并控制,以符合SPI协议规范。可以用GPIO9。
- RST (Reset):硬件复位线,低电平复位。虽然可以通过软件命令复位,但硬件复位更可靠。建议连接,例如GPIO8。
- BACKLIGHT:背光控制。通常是高电平点亮。可以用一个GPIO通过三极管或MOS管控制,以实现调光。简单应用可以直接接3.3V常亮。我用GPIO7配合一个NMOS管(如2N7002)来控制。
对于触摸芯片(通常是XPT2046、FT6236或其他),如果是SPI接口,强烈建议使用另一个SPI外设,比如用SPI2的另一个CS线,或者使用软件模拟SPI(Bit-Banging)。因为屏幕的刷新是连续、高优先级的,而触摸查询是间歇性的。混用同一个SPI硬件,在传输屏幕数据时触摸查询会被阻塞,导致触摸响应延迟。更常见的3.5寸屏集成的触摸是电阻式(XPT2046),它也是SPI接口。我的方案是:屏幕用硬件SPI2,触摸芯片用软件模拟SPI,占用另外一组GPIO(如GPIO21作CS, GPIO18作CLK, GPIO17作MOSI, GPIO16作MISO)。这样两者互不干扰。
注意:ESP32S3的许多引脚在上电启动时有特殊功能(如Strapping引脚)。务必避开GPIO0、GPIO45、GPIO46等关键引脚。我推荐的上述引脚在大多数开发板上都是安全的通用IO。
2.2 电源与信号完整性考量
3.5寸屏的功耗不可小觑,尤其是背光全亮时。ESP32S3的3.3V引脚(VDD3P3)通常只能提供数百mA电流。如果屏幕功耗较大(可能达到200-300mA),直接由开发板供电可能导致电压跌落,引起ESP32重启。
- 独立供电:最佳实践是使用一个独立的3.3V LDO稳压器为屏幕供电,输入可以是5V。ESP32S3开发板的5V引脚(来自USB)通常能提供足够的电流。
- 去耦电容:在屏幕的VCC和GND引脚附近,务必放置一个10uF的电解电容和一个0.1uF的陶瓷电容,以滤除电源噪声,这对SPI高速通信的稳定性至关重要。
- 信号线上拉:对于SPI的CS、DC等控制信号,如果线缆较长(>10cm),可以考虑在ESP32端加上一个4.7kΩ - 10kΩ的上拉电阻到3.3V,增强抗干扰能力。
一份我实际使用的连接表示例如下:
| ESP32S3 引脚 | 连接至 | 功能说明 | 备注 |
|---|---|---|---|
| GPIO12 | 屏 - SCK | SPI 时钟 | HSPI/SPI2 默认 SCK |
| GPIO11 | 屏 - MOSI (SDA) | SPI 数据输出 | HSPI/SPI2 默认 MOSI |
| GPIO13 | 屏 - MISO (SDO) | SPI 数据输入 | 可选的,用于读操作 |
| GPIO10 | 屏 - DC | 数据/命令选择 | 必须,通用IO |
| GPIO9 | 屏 - CS | 片选 | 必须,低电平有效 |
| GPIO8 | 屏 - RST | 硬件复位 | 建议连接,通用IO |
| GPIO7 | 背光控制电路 | 背光 PWM 控制 | 通过MOS管控制背光阳极 |
| GPIO21 | 触摸 - T_CS | 触摸芯片片选 | 软件SPI片选 |
| GPIO18 | 触摸 - T_CLK | 触摸 SPI 时钟 | 软件SPI时钟 |
| GPIO17 | 触摸 - T_MOSI | 触摸 SPI 输出 | 软件SPI数据输出 |
| GPIO16 | 触摸 - T_MISO | 触摸 SPI 输入 | 软件SPI数据输入,用于读取触摸坐标 |
| 3.3V | 屏 - VCC | 电源(需确认) | 建议经外部LDO供电 |
| 5V | 屏 - BL_VCC | 背光电源(需确认) | 根据屏幕规格书 |
| GND | 屏 - GND | 地 | 共地 |
务必在焊接前,用万用表确认屏幕引脚定义!不同厂家的3.5寸ST7796屏,引脚顺序可能不同,背光电压可能是3.3V或5V。
3. 软件工程搭建:从零配置LVGL与驱动程序
硬件连接无误后,我们就进入软件世界。我选择使用ESP-IDF v5.1作为开发框架,它原生支持LVGL,可以通过组件管理器(Component Manager)轻松集成,比手动移植要省心得多。
3.1 创建工程与组件管理
首先,确保你的开发环境已设置好(VSCode + ESP-IDF插件或基于终端的IDF环境)。创建一个新的项目:
idf.py create-project esp32s3_lvgl_st7796 cd esp32s3_lvgl_st7796接下来,我们需要添加必要的组件。ESP-IDF的组件管理器 (idf.py add-dependency) 让这一切变得简单。但更直接的方法是编辑项目根目录下的idf_component.yml文件。对于这个项目,核心依赖如下:
dependencies: # LVGL图形库本体 lvgl/lvgl: "^8.3.11" # LVGL在ESP32上的移植层和驱动程序框架 lvgl/lvgl_esp32_drivers: version: "^1.0.4" override_path: ./components/lvgl_esp32_drivers # 有时需要指定路径 # 用于管理SPI总线、GPIO等 idf: ">=5.0"lvgl_esp32_drivers这个组件至关重要,它包含了针对ESP32系列优化过的显示(lvgl_tft)和触摸(lvgl_touch)驱动框架,以及连接LVGL与ESP-IDF SPI、I2C等外设的桥梁。添加后,运行idf.py reconfigure来获取和编译这些组件。
3.2 显示驱动(ST7796)的深度配置
lvgl_esp32_drivers组件已经支持ST7796,但我们需要根据屏幕的具体型号和连接方式进行精确配置。配置主要通过menuconfig工具完成。
idf.py menuconfig进入Component config -> LVGL TFT Display controller:
- Display Controller:选择
ST7796。 - Interface type:选择
SPI (parallel-1线模式)。这里虽然是SPI,但驱动内部可能标记为“并行”,实际上是指令/数据通过同一条线(MOSI)传输,这是最常见的SPI屏模式。 - SPI Host:选择
SPI2_HOST。 - 引脚配置:根据之前的硬件连接表,逐一设置
PIN_NUM_MISO,PIN_NUM_MOSI,PIN_NUM_CLK,PIN_NUM_CS,PIN_NUM_DC,PIN_NUM_RST,PIN_NUM_BCKL。 - 屏幕方向(Rotation):根据屏幕的物理安装方向选择,0-3分别对应0度、90度、180度、270度旋转。如果启动后方向不对,可以在这里修改。
- 色彩格式(Color Format):选择
RGB565。这是16位色,平衡了色彩表现和内存/带宽消耗,是最常用的格式。 - 反转颜色(Invert Colors):有些屏幕可能需要反转颜色。如果显示颜色完全不对(比如白色变黑色),可以尝试切换这个选项。
- SPI时钟速度(SPI Clock Speed):这是关键性能参数。ESP32S3的SPI时钟可以很高,但受限于屏幕驱动IC和PCB布线。对于ST7796,可以尝试从40MHz开始,如果出现花屏或数据错误,再逐步降低。我测试的屏幕在80MHz下稳定运行。可以在
Display SPI clock speed (MHz)中直接输入数字。
除了menuconfig,还有一个更灵活的方式是直接修改sdkconfig.defaults文件或项目中的Kconfig.projbuild来预设这些配置,便于团队共享和版本管理。
3.3 触摸驱动(XPT2046)配置与校准
大多数3.5寸SPI屏搭载的是电阻触摸芯片XPT2046。配置路径在menuconfig的Component config -> LVGL Touch Controller中。
- Touch Controller:选择
XPT2046。 - Interface type:选择
SPI (software implementation)。这就是我之前为什么建议触摸用软件SPI的原因——在这里可以方便地配置。 - 软件SPI引脚:设置
TOUCH_SPI_MISO,TOUCH_SPI_MOSI,TOUCH_SPI_CLK,TOUCH_SPI_CS为对应的GPIO号。 - 触摸方向:需要根据屏幕的显示方向来映射触摸坐标。如果触摸方向与显示方向不匹配,会出现点击位置偏移。驱动通常提供
TOUCH_SWAP_XY,TOUCH_INVERT_X,TOUCH_INVERT_Y等选项来调整。最准确的方法是进行触摸校准。
触摸校准是必须的步骤,因为电阻屏存在固有的线性误差。LVGL提供了内置的校准程序。你可以在应用代码中,在初始化LVGL和触摸驱动后,调用lv_calibrate_indev(lv_indev_get_next(NULL));。这会在屏幕上显示几个点,要求你依次点击,从而计算出校准矩阵。校准数据可以保存到NVS(非易失性存储)中,下次启动时直接加载,无需重复校准。
我的经验是,在lv_port_init()函数(通常由lvgl_esp32_drivers组件提供)调用之后,添加如下代码:
// 尝试从NVS加载校准数据 static bool touch_calibration_load(void) { // ... 从NVS读取数据的代码 ... if (数据有效) { lv_indev_set_calibration_matrix(indev, &matrix); return true; } return false; } if (!touch_calibration_load()) { // 如果加载失败,启动校准 lv_calibrate_indev(lv_indev_get_next(NULL)); // 传入触摸输入设备指针 }3.4 LVGL自身的关键配置
LVGL有极其丰富的配置项,位于Component config -> LVGL configuration。对于ESP32S3,以下几个配置需要重点关注:
- 颜色深度 (Color depth):设置为16位(RGB565),与屏幕驱动配置保持一致。
- 堆大小 (Heap size):LVGL需要内部内存来创建对象、样式等。在
LV_MEM_SIZE中,建议设置为至少64KB (65536)。ESP32S3有PSRAM,我们可以让LVGL使用PSRAM。 - 使用PSRAM:确保
LV_MEM_ADDR指向PSRAM的地址。在ESP-IDF中,通常可以通过heap_caps_malloc(size, MALLOC_CAP_SPIRAM)来分配PSRAM内存。lvgl_esp32_drivers的显示驱动初始化部分,通常会处理帧缓冲(frame buffer)的内存分配,我们可以配置它使用PSRAM。 在menuconfig的显示驱动配置部分,寻找Allocate frame buffer in PSRAM或类似的选项,并打开它。同时,将LVGL buffer size (in pixels)设置为整个屏幕的大小(320*480=153600),这意味着我们分配了一个完整的全屏帧缓冲在PSRAM中。双缓冲则需要两倍于此的大小。 - 双缓冲 (Double buffering):这是提升流畅度的关键。在显示驱动配置中,启用双缓冲。这样LVGL在一个缓冲区(off-screen buffer)中绘制下一帧时,DMA正在将另一个缓冲区(frame buffer)的数据发送到屏幕,两者并行,避免了绘制过程中的屏幕撕裂。ESP32S3的SPI DMA功能在此发挥了巨大作用。
- 任务优先级与Tick:LVGL需要一个心跳(tick)来管理动画和超时。确保在
lv_port_init()中创建了一个高优先级的任务(如lv_timer_handler)来定期调用lv_tick_inc()和lv_timer_handler()。通常这个任务优先级要高于你的主应用任务,但低于SPI DMA中断。
4. 驱动调试与性能优化实战
配置完成后,编译并烧录。如果一切顺利,你应该能看到LVGL的默认示例界面。但现实往往是骨感的,下面是我在调试中遇到的一些典型问题及解决方案。
4.1 常见启动问题排查链
屏幕无任何显示,背光也不亮:
- 第一步:检查电源。用万用表测量屏幕VCC和GND之间是否有3.3V?背光引脚电压是否正确?ESP32的3.3V输出是否被拉低?
- 第二步:检查复位时序。在初始化代码中,驱动通常会先拉低RST引脚(>10ms),再拉高。用逻辑分析仪或示波器查看RST引脚波形,或者简单地在代码中增加
vTaskDelay(pdMS_TO_TICKS(100));在复位操作前后,确保屏幕有足够时间完成复位。 - 第三步:检查SPI信号。如果条件允许,用逻辑分析仪抓取SPI总线上初始化阶段的波形。看CS、DC信号是否正常,是否有时钟和数据输出。没有逻辑分析仪的话,可以尝试将SPI时钟速度降到1MHz以下,排除因布线问题导致的高速信号失真。
屏幕花屏、闪烁或显示错位:
- 首要嫌疑:SPI时钟速度。这是最常见的原因。过高频率会导致数据采样错误。逐步降低
SPI Clock Speed(如从80MHz降到40MHz、20MHz)测试。 - 帧缓冲内存对齐:确保为LVGL和显示驱动分配的内存地址是32位对齐的(尤其是使用PSRAM时)。不对齐的内存访问在某些架构上会导致数据错误。ESP-IDF的
heap_caps_malloc通常能保证对齐,但自定义分配时需注意。 - DMA缓冲区大小:检查SPI DMA传输的缓冲区大小设置。有时缓冲区设置过小,会导致DMA传输频繁中断,影响效率甚至出错。在驱动配置中寻找相关选项。
- 屏幕初始化序列:不同批次的ST7796屏幕,可能需要微调初始化命令序列。
lvgl_esp32_drivers组件中的st7796.c文件里包含了默认的初始化命令。如果显示异常(如颜色反转、扫描方向错误),可能需要查阅ST7796数据手册,修改这个序列。例如,添加或修改设置内存数据访问控制(MADCTL)的命令来调整BGR顺序、行列地址扫描方向等。
- 首要嫌疑:SPI时钟速度。这是最常见的原因。过高频率会导致数据采样错误。逐步降低
触摸无反应或坐标不准:
- 软件SPI时序:软件模拟SPI的时序可能不够精确,特别是时钟高低电平的保持时间。尝试在
touch_spi_xpt2046.c等驱动文件中,在__touch_spi_sw_read和__touch_spi_sw_write函数里的gpio_set_level操作后增加微秒级的延迟(ets_delay_us(1))。 - 触摸压力阈值:XPT2046通过测量压力来判断是否被按下。在驱动配置中有一个
TOUCH_THRESHOLD参数,如果值设得太大,轻微触摸可能无法触发;太小则容易误触。默认值可能不适合你的屏幕,需要调整。 - 坐标转换公式:驱动中从原始AD值转换为屏幕坐标的公式可能不准确。这需要校准来解决。确保校准程序运行正确,并且校准数据被保存和加载。
- 软件SPI时序:软件模拟SPI的时序可能不够精确,特别是时钟高低电平的保持时间。尝试在
4.2 性能压测与优化策略
当基础显示和触摸都正常后,我们就要追求流畅度了。LVGL的流畅度主要受限于两个因素:渲染计算时间和屏幕刷新时间(即SPI填充速度)。
1. 渲染性能分析:在lv_conf.h中打开LV_USE_PERF_MONITOR和LV_USE_MEM_MONITOR。这会在屏幕角落显示帧率(FPS)、渲染时间、内存使用等信息。如果帧率很低(如低于30FPS),且渲染时间很长(比如超过20ms),说明CPU渲染是瓶颈。
- 优化策略:简化界面,减少重叠的控件和复杂的阴影、渐变效果。检查是否在循环中频繁创建/删除对象,这会导致内存碎片和分配开销。使用LVGL的对象池(如果可用)或静态分配对象。
2. 刷新带宽分析:如果渲染时间很短(如<5ms),但帧率依然不高,瓶颈就在屏幕刷新上。全屏刷新一帧320x480 RGB565的数据量是 320 * 480 * 2 = 307200 字节。在80MHz SPI时钟下(实际数据传输率可能只有一半左右,约40Mbps),理论全刷时间约为 307200*8 / 40e6 ≈ 61ms,即约16FPS。这显然不够。
- 核心优化:局部刷新(Partial Update):LVGL不会每帧都刷新整个屏幕,它通过
lv_disp_flush_ready回调函数通知驱动“需要刷新的区域(dirty area)”。一个优秀的驱动应该只发送这个区域的数据。确保你的显示驱动(disp_drv.flush_cb回调函数)正确地接收并处理了lv_disp_flush_ready传递的area参数,只更新屏幕的指定矩形区域。lvgl_esp32_drivers中的SPI驱动通常已经实现了这一点。 - 启用双缓冲与DMA:这几乎是必须的。确保在
menuconfig中启用了双缓冲,并且缓冲区分配在PSRAM。DMA传输可以解放CPU,在SPI发送数据的同时,CPU可以准备下一帧的内容,实现并行。 - 提高SPI实际速率:除了提高时钟频率,还要优化SPI事务。使用ESP32的
spi_device_queue_trans和中断回调,避免轮询等待SPI传输完成。确保一次传输的数据块尽可能大,减少事务开销。
在我的实测中,经过优化(双缓冲PSRAM、局部刷新、80MHz SPI),在显示一个中等复杂度的界面(多个按钮、滑块、图表)时,LVGL的帧率可以稳定在45-60 FPS,触摸响应延迟低于50ms,达到了非常可用的水平。
5. 从基础工程到实际应用:项目框架建议
这个“基础工程”跑通后,它只是一个空壳。如何将其变成一个真正的项目?这里分享我的项目组织经验。
1. 应用与驱动分离:不要将你的业务逻辑代码直接写在main.c或与驱动混杂在一起。建议的目录结构如下:
your_project/ ├── main/ │ ├── app_main.c // 应用入口,初始化硬件、启动任务 │ └── lvgl_app/ // LVGL应用层 │ ├── ui.c // 界面创建、事件绑定函数 │ ├── ui.h │ ├── logic.c // 业务逻辑处理 │ └── logic.h ├── components/ // 自定义组件(如果需要) └── ... // IDF工程其他文件在app_main.c中,调用lv_port_init()(来自lvgl_esp32_drivers)来初始化显示和触摸。然后,创建一个任务(如lvgl_task)来定期运行lv_timer_handler()。最后,调用ui_create()函数(在ui.c中)来构建你的初始界面。
2. 使用LVGL的“屏幕(Screen)”概念:LVGL的基本容器是“屏幕”(lv_obj_t *scr)。你可以创建多个屏幕,通过lv_scr_load(scr)在它们之间切换。这非常适合实现多级菜单或不同的应用页面。例如,一个主屏幕、一个设置屏幕、一个数据图表屏幕。
3. 事件驱动编程:LVGL是事件驱动的。为按钮等控件添加事件回调lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL)。在event_handler函数中,不要执行长时间阻塞的操作(如vTaskDelay或复杂的计算),这会阻塞LVGL的主任务,导致界面卡死。正确的做法是,在事件回调中通过队列(xQueueSend)向一个独立的应用逻辑任务发送消息,由那个任务去处理耗时操作,然后通过lv_async_call或再次发送消息到LVGL任务来更新UI。
4. 管理字体与图片:中文字体文件很大。不要试图将整个中文字库(如16px的字体可能好几MB)直接编译进固件。推荐使用LVGL的“字体分割”工具,或者使用外部SPI Flash存储字体,并在运行时加载所需字符的子集(LVGL支持此功能)。对于图片,同样建议转换为C数组或二进制文件存储在外部Flash,使用LVGL的“文件系统”接口来加载。
5. 功耗考虑:如果你的设备是电池供电,需要考虑功耗。在无操作时,可以降低屏幕背光(PWM调光)甚至关闭背光。ESP32S3本身可以进入轻量睡眠或深度睡眠模式。需要设计一个唤醒机制,比如通过触摸中断唤醒系统。LVGL可以配合这些电源管理策略。
最后,这个基础工程的价值在于它验证了硬件链路和软件底层的可行性。在此基础上,你可以尽情发挥创意,去构建智能家居中控、工业仪表盘、便携式游戏机等丰富的应用。整个过程中,最花时间的往往不是写代码,而是调试硬件连接和驱动参数。耐心地使用逻辑分析仪、串口打印和LVGL的性能监控工具,大部分问题都能迎刃而解。希望这份详细的拆解能帮你少走弯路,快速搭起属于自己的嵌入式GUI平台。
本文还有配套的精品资源,点击获取