1. 为什么GUI-Guider生成的代码在ESP32上跑不起来
1.1 先搞清楚GUI-Guider到底生成了什么
很多人第一次用GUI-Guider,看到界面上拖拖拽拽就能出效果,点一下“导出”就以为大功告成。结果把生成的文件夹往ESP32工程里一塞,编译直接爆红,几十条报错刷屏,瞬间懵了。
我刚开始接触这套组合的时候也踩过这个坑。GUI-Guider本质上是一个界面代码生成器,它根据你在画布上的布局,生成两类东西:一类是纯C代码的界面构建逻辑(比如gui_guider.c、setup_scr_screen.c),另一类是资源文件(图片、字体、样式)。它默认的目标平台是模拟器环境,也就是在PC上跑的那个SDL窗口版本。所以它生成的代码里会引用大量模拟器专有的头文件、宏定义和初始化流程。
换句话说,GUI-Guider生成的代码是“半成品”,它假设你已经有一个能跑LVGL的宿主环境,并且这个环境跟它的预期一致。ESP32上的LVGL移植跟PC模拟器完全是两码事,这就是所有问题的根源。
你需要先理解一个核心事实:GUI-Guider不负责LVGL本身的移植。它只负责生成界面层的代码。LVGL在ESP32上的显示驱动、触摸驱动、tick时钟、内存分配,这些都得你自己搞定。很多人把顺序搞反了,先导入GUI-Guider代码,再去调LVGL移植,结果两边的问题混在一起,根本分不清是哪个环节出了错。
1.2 编译错误的三大来源分类
我把实际项目中遇到的编译错误归成三类,方便你快速定位:
| 错误类型 | 典型表现 | 根本原因 |
|---|---|---|
| 头文件缺失 | fatal error: lv_conf.h: No such file | 路径配置不对或文件没放对位置 |
| 符号未定义 | undefined reference to 'lv_...' | LVGL源文件没加入编译或版本不匹配 |
| 类型冲突 | conflicting types for 'xxx' | GUI-Guider版本与LVGL版本不兼容 |
这三类错误的排查思路完全不同。头文件问题靠检查路径和宏定义,符号问题靠检查编译文件列表,类型冲突靠对齐版本号。下面我会逐一拆开讲。
1.3 版本匹配是第一条铁律
GUI-Guider每个版本绑定的LVGL版本是固定的。比如GUI-Guider 1.4.x对应LVGL 8.2,1.5.x对应LVGL 8.3,1.6.x之后开始支持LVGL 9。你如果拿GUI-Guider 1.5生成的代码去配LVGL 7.11的库,那编译不过太正常了。
我见过有人用LVGL 7.11的教程去配GUI-Guider 1.6的代码,然后花了两天时间改各种API,最后发现根本改不完。正确的做法是:先确定你用的GUI-Guider版本,然后去查它官方文档里写的LVGL版本,严格按那个版本来。不要想着“我用最新版LVGL肯定更好”,版本不匹配带来的工作量远超你的想象。
提示:GUI-Guider安装目录下通常有一个
lvgl文件夹,里面就是它配套的LVGL源码。直接用那份源码,不要自己去GitHub下别的版本。
2. 环境搭建阶段的五个致命坑
2.1 lv_conf.h的位置和宏开关
lv_conf.h是LVGL的核心配置文件,它决定了哪些功能被启用、内存池多大、颜色深度多少。这个文件放错位置,后面所有事情都白搭。
在ESP32的ESP-IDF环境下,lv_conf.h必须放在能被编译器搜索到的路径里。常见做法是放在项目根目录的components文件夹下,或者放在main文件夹同级。然后在编译选项里加上-DLV_CONF_INCLUDE_SIMPLE,这样LVGL就会用#include "lv_conf.h"的方式去找。
但这里有个隐藏坑:如果你用的是PlatformIO或者Arduino IDE,路径规则又不一样。Arduino IDE下通常要把lv_conf.h放在库文件夹的同级目录,并且确保lvgl库的lv_conf_internal.h能找到它。
我建议的做法是:在lv_conf.h第一行加一个#error "lv_conf.h loaded",编译一次看报不报这个错。如果没报,说明文件根本没被加载,你后面改什么配置都没用。这个技巧帮我省过无数次排查时间。
2.2 颜色深度和屏幕驱动不匹配
lv_conf.h里有个LV_COLOR_DEPTH宏,可选1、8、16、32。ESP32上绝大多数SPI屏和并口屏用16位色(RGB565),所以这里要设成16。如果你设成32,LVGL会按每像素4字节来分配缓冲区和计算,而你的屏幕驱动按2字节发送,结果就是花屏或者只显示一半。
更隐蔽的问题是字节序。RGB565有大端小端之分,ST7789、ILI9341这些驱动芯片对字节序的敏感度不同。你如果发现颜色不对(比如红色变蓝色),先检查LV_COLOR_16_SWAP这个宏。在LVGL 8.x里它叫LV_COLOR_16_SWAP,在LVGL 9里改成了LV_COLOR_DEPTH配合lv_draw_sw_rgb565_swap函数。
实测下来,大部分ESP32+ST7789的组合需要开启字节交换。但ILI9341有时候不需要。这个没有统一答案,只能试。我的经验是:先关掉交换,显示一张纯色图,看颜色对不对;不对再打开,基本就能确定。
2.3 内存分配:LVGL的堆和ESP32的堆是两回事
LVGL有自己的内存管理机制,通过LV_MEM_SIZE宏定义内存池大小。这个内存池是LVGL内部用来分配对象、样式、动画数据的,跟ESP32的FreeRTOS堆是独立的。
很多人编译通过了,运行起来却崩溃,报malloc failed或者直接重启。原因就是LV_MEM_SIZE设太小了。GUI-Guider生成的界面如果控件多、图片多,默认的48KB根本不够。我一般建议至少设到64KB,复杂界面直接上128KB。
但也不能无限大,因为ESP32的RAM总共就那么多。ESP32-WROOM-32有520KB SRAM,其中一部分被WiFi协议栈和FreeRTOS占用,实际可用的大概300KB左右。你给LVGL分128KB,剩下的还要给任务栈、DMA缓冲区、其他组件用,得算着来。
注意:如果你用的是ESP32-S3,它有额外的8MB PSRAM(如果模组带的话),可以把LVGL的内存池放到PSRAM里,这样就能设得很大。但需要配置
LV_MEM_CUSTOM为1,然后自己实现lv_malloc和lv_free指向PSRAM的分配函数。
2.4 tick时钟源的选择
LVGL需要一个毫秒级的tick来驱动动画、定时器和任务调度。在PC模拟器上这个tick是SDL提供的,在ESP32上你得自己给。
常见做法有两种:一种是用FreeRTOS的xTaskGetTickCount(),另一种是用ESP32的硬件定时器。xTaskGetTickCount()的精度取决于configTICK_RATE_HZ,默认是100Hz,也就是10ms一个tick。这对LVGL来说太粗了,动画会卡顿。你可以把configTICK_RATE_HZ改成1000,但这样会增加系统调度开销。
更稳的做法是用一个硬件定时器,每1ms触发一次中断,在中断里调用lv_tick_inc(1)。ESP32有四个通用定时器,随便拿一个出来就行。配置成1MHz的计数频率,每1000个计数触发一次中断,正好1ms。
这里有个坑:不要在中断里调用LVGL的其它函数,只调lv_tick_inc。LVGL的任务处理(lv_task_handler)必须放在主循环或者一个独立的任务里,不能放在中断里。
2.5 显示缓冲区的尺寸和数量
LVGL的显示缓冲区大小直接决定了刷新效率和内存占用。lv_conf.h里不配置这个,而是在初始化显示驱动时通过lv_disp_draw_buf_init来指定。
缓冲区可以是一个全屏大小的,也可以是屏幕的1/10。全屏缓冲区刷新最快,但占用内存大。320x240的屏幕,16位色,全屏就是150KB,ESP32扛不住。通常用屏幕的1/10,也就是32x240,约15KB,分两个缓冲区做双缓冲,总共30KB。
但缓冲区太小会导致刷新时出现撕裂感,尤其是滚动列表的时候。我的经验是:如果界面以静态为主,1/10够了;如果有大量滚动或者动画,至少1/4屏。ESP32-S3带PSRAM的话,直接上全屏双缓冲,体验最好。
3. GUI-Guider代码导入后的编译错误逐个击破
3.1 头文件路径问题的系统化解决
GUI-Guider导出的文件夹结构通常是这样的:
gui_guider/ generated/ gui_guider.c gui_guider.h setup_scr_screen.c widgets_init.c custom/ custom.c custom.h events/ events_init.c events_init.h这些文件之间互相引用,用的都是相对路径。你如果直接把这个文件夹拷到ESP32工程里,编译器找不到头文件是必然的。
解决方案有两种:一种是在CMakeLists.txt里用include_directories把所有子文件夹都加进去;另一种是修改源文件里的include路径,改成相对于项目根目录的路径。
我推荐第一种,因为改include路径的话,下次GUI-Guider重新导出又得改一遍。在ESP-IDF的CMakeLists.txt里这样写:
idf_component_register( SRCS "gui_guider/generated/gui_guider.c" "gui_guider/generated/setup_scr_screen.c" "gui_guider/generated/widgets_init.c" "gui_guider/custom/custom.c" "gui_guider/events/events_init.c" INCLUDE_DIRS "gui_guider/generated" "gui_guider/custom" "gui_guider/events" )这样编译器就能找到所有头文件了。但还有一个坑:GUI-Guider生成的代码里会#include "lvgl.h",而你的LVGL库可能不在默认搜索路径里。需要确保LVGL的lvgl.h所在目录也被加到了INCLUDE_DIRS。
3.2 符号未定义错误的排查流程
编译时看到一堆undefined reference to 'lv_obj_create'之类的错误,说明LVGL的源文件没有被编译进去。在ESP-IDF里,LVGL通常作为一个组件放在components/lvgl目录下,需要有对应的CMakeLists.txt来注册源文件。
LVGL 8.x的源文件很多,手动一个个列不现实。通常的做法是用通配符:
file(GLOB_RECURSE LVGL_SRCS "src/*.c") idf_component_register(SRCS ${LVGL_SRCS} INCLUDE_DIRS ".")但file(GLOB_RECURSE)在CMake里有个问题:它只在配置阶段执行一次,如果你新增了源文件,需要重新运行cmake才能生效。不过对于LVGL这种稳定的库来说,这不是大问题。
另一个常见原因是条件编译。LVGL的很多功能是通过lv_conf.h里的宏来开关的。如果你在代码里用了某个控件(比如lv_chart),但lv_conf.h里LV_USE_CHART设成了0,那这个控件的源文件就不会被编译,链接时自然找不到符号。
排查方法:在编译输出里搜索第一个undefined reference的符号名,然后去LVGL源码里找它在哪个文件定义,再看那个文件是否在编译列表里。如果文件在,那就是条件编译的问题,去lv_conf.h里把对应的LV_USE_xxx打开。
3.3 类型冲突和API变更的应对
GUI-Guider版本和LVGL版本不匹配时,最常见的错误就是类型冲突。比如LVGL 8里lv_obj_t是个结构体指针,LVGL 9里改成了不透明指针,两者的用法有细微差别。GUI-Guider生成的代码如果按8的写法来,配9的库就会报错。
还有一种情况是函数签名变了。比如lv_label_set_text在8和9里参数类型没变,但lv_img_set_src在9里对图片来源的处理方式变了,传入lv_img_dsc_t指针的方式有调整。
遇到这类错误,我的建议是不要硬改。先确认GUI-Guider和LVGL的版本对应关系,如果确实不匹配,要么换GUI-Guider版本,要么换LVGL版本。硬改的话,改完一处还有十处等着,而且改完可能引入新的bug。
如果实在没法换版本,那就只能逐个函数对照LVGL的迁移指南来改。LVGL官方有一份从8到9的迁移文档,列出了所有API变更。但这个过程很耗时,一个中等复杂度的界面可能要改一两天。
3.4 中文字体导致的编译问题
GUI-Guider里如果用了中文字体,导出时会生成一个字体文件(通常是.c格式的数组)。这个文件可能非常大,几万个汉字的点阵数据,编译时占用大量内存,甚至导致编译器崩溃。
更麻烦的是,GUI-Guider默认生成的中文字体可能包含全字库,一个文件好几MB。ESP32的Flash通常只有4MB,放不下。
解决方案是按需生成字体。在GUI-Guider的字体设置里,选择“指定字符”模式,只把你界面上用到的汉字输进去。比如界面上只有“温度”、“湿度”、“设置”这几个词,那就只生成这几个字。这样字体文件可能只有几KB。
如果GUI-Guider的字体生成功能不够灵活,可以用LVGL官方的字体转换工具,在PC上生成指定字符集的字体C文件,然后替换掉GUI-Guider生成的。
提示:LVGL 8.x支持外部字体文件(通过文件系统加载),但ESP32上需要挂载SPIFFS或LittleFS。这种方式更灵活,但增加了文件系统的复杂度。新手建议先用内置字体数组的方式。
4. 显示异常问题的诊断与修复
4.1 花屏、白屏、黑屏的区分处理
屏幕不亮分三种情况,处理方式完全不同:
白屏:背光亮了,但没有任何内容。这通常是初始化序列没发对,或者复位时序有问题。检查你的屏幕驱动初始化代码,确认复位引脚拉低至少10ms,然后拉高等待120ms再发初始化命令。有些屏幕还需要在初始化前先发一个软件复位命令。
黑屏:背光都没亮。先检查背光引脚有没有给高电平,有些屏幕背光是低电平点亮。如果背光电路是PWM控制的,确认PWM输出正常。用万用表量一下背光引脚电压,这是最快的判断方法。
花屏:有内容但颜色错乱、位置偏移。这通常是颜色深度、字节序或者分辨率设置不对。先确认LV_COLOR_DEPTH和屏幕实际色深一致,再检查LV_COLOR_16_SWAP。如果花屏是规律性的条纹,那可能是SPI时钟太快,数据没来得及建立,降低SPI频率试试。
我遇到过一次特别诡异的花屏:屏幕上半部分正常,下半部分错位。查了半天发现是显示缓冲区的尺寸设成了屏幕宽度的一半,但LVGL按全宽来刷新,导致数据错位。所以缓冲区的宽度必须和屏幕宽度一致,高度可以任意。
4.2 触摸坐标偏移的校准方法
触摸屏和显示屏是两个独立的坐标系,如果不对齐,就会出现“点这里那里响应”的情况。校准的本质是找到两个坐标系之间的映射关系。
最简单的校准方法是两点校准:在屏幕左上角和右下角各画一个十字,让用户依次点击,记录触摸控制器返回的原始坐标,然后计算缩放因子和偏移量。
但ESP32上很多触摸驱动(比如XPT2046)返回的原始值范围跟屏幕分辨率不成比例。比如屏幕是320x240,触摸原始值可能是200到3800。你需要做线性映射:
screen_x = (touch_raw_x - touch_min_x) * screen_width / (touch_max_x - touch_min_x) screen_y = (touch_raw_y - touch_min_y) * screen_height / (touch_max_y - touch_min_y)touch_min_x和touch_max_x需要实测。我的做法是在屏幕上画四个角的目标,依次点击,记录原始值,然后取平均值。
还有一个坑:触摸方向可能跟显示方向不一致。比如显示是横屏,触摸驱动默认是竖屏,那x和y就要交换。这个在初始化触摸驱动时通过配置寄存器来设置,不同芯片的寄存器不一样,得查数据手册。
4.3 刷新率低和撕裂感的优化
ESP32上跑LVGL,如果刷新率低于30fps,操作就会感觉卡顿。影响刷新率的因素有好几个:
SPI时钟频率是最直接的。ST7789支持最高62.5MHz,但实际能跑多快取决于你的布线和ESP32的SPI控制器。我一般从40MHz开始试,稳定的话往上加。如果出现花屏就降回来。
DMA传输能大幅降低CPU占用。ESP32的SPI支持DMA,配置好之后,LVGL的flush_cb里调用spi_device_transmit时用DMA通道,CPU就可以去处理其他任务了。但DMA缓冲区必须放在DMA-capable的内存里,ESP32上只有内部SRAM支持DMA,PSRAM不行。
双缓冲能减少撕裂。原理是LVGL在往缓冲区A写数据的时候,DMA在发送缓冲区B的数据。写完了交换。这样就不会出现“上半屏是新画面,下半屏是旧画面”的情况。
如果以上都做了还是卡,那可能是界面本身太复杂。GUI-Guider生成的界面如果控件层次太深,LVGL渲染一帧需要遍历很多对象。优化方法是减少不必要的容器嵌套,把静态的控件合并成图片。
4.4 图片显示异常的几种情况
GUI-Guider里插入的图片,导出时会被转换成C数组。如果图片是RGB888格式的,而你的屏幕是RGB565,LVGL需要做转换,这会增加CPU负担。建议在GUI-Guider里就把图片转成RGB565格式。
图片显示位置不对,通常是lv_img_set_offset_x/y没设对,或者图片的对齐方式跟预期不一致。LVGL的图片默认以中心为原点,如果你按左上角来算坐标,就会偏。
图片显示成乱码或者颜色错乱,检查图片的字节序。GUI-Guider生成的图片数组可能是按大端排列的,而LVGL按小端读取。这个可以在lv_conf.h里通过LV_COLOR_16_SWAP来调整,但注意这个宏同时影响屏幕输出和图片解析,调的时候要一起看。
5. 实战:从零搭建一个可运行的ESP32+LVGL+GUI-Guider工程
5.1 工程目录结构规划
一个清晰的结构能省掉后面很多麻烦。我推荐的目录结构是这样的:
project/ components/ lvgl/ # LVGL库源码 lvgl_esp32_drivers/ # 显示和触摸驱动 main/ main.c # 主程序入口 gui_guider/ # GUI-Guider生成的代码 generated/ custom/ events/ display_config.c # 显示驱动初始化 touch_config.c # 触摸驱动初始化 CMakeLists.txt sdkconfigLVGL和驱动作为组件放在components下,GUI-Guider代码放在main下。这样编译时,main组件会自动依赖lvgl组件,不需要额外配置。
5.2 显示驱动初始化的关键代码
以ST7789为例,初始化流程分三步:SPI总线初始化、屏幕控制器初始化、LVGL显示驱动注册。
SPI总线初始化:
spi_bus_config_t bus_cfg = { .mosi_io_num = PIN_MOSI, .miso_io_num = -1, .sclk_io_num = PIN_CLK, .quadwp_io_num = -1, .quadhd_io_num = -1, .max_transfer_sz = SCREEN_WIDTH * 40 * 2, }; spi_bus_initialize(SPI2_HOST, &bus_cfg, SPI_DMA_CH_AUTO);max_transfer_sz要设得比一次传输的最大数据量大。LVGL一次刷新一行或几行,所以设成屏幕宽度 * 行数 * 2。设太小会导致传输被截断。
屏幕控制器初始化就是发一堆命令,设置分辨率、颜色格式、刷新方向等。这部分代码通常驱动库会提供,直接调用即可。
LVGL显示驱动注册:
lv_disp_draw_buf_t draw_buf; lv_color_t *buf1 = heap_caps_malloc(BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA); lv_color_t *buf2 = heap_caps_malloc(BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA); lv_disp_draw_buf_init(&draw_buf, buf1, buf2, BUF_SIZE); static lv_disp_drv_t disp_drv; lv_disp_drv_init(&disp_drv); disp_drv.hor_res = SCREEN_WIDTH; disp_drv.ver_res = SCREEN_HEIGHT; disp_drv.flush_cb = my_flush_cb; disp_drv.draw_buf = &draw_buf; lv_disp_drv_register(&disp_drv);注意heap_caps_malloc用了MALLOC_CAP_DMA标志,确保分配的内存支持DMA。如果用普通的malloc,DMA传输会失败。
5.3 GUI-Guider代码的集成步骤
把GUI-Guider导出的gui_guider文件夹拷到main目录下,然后在main.c里调用初始化函数:
#include "gui_guider.h" #include "events_init.h" lv_ui guider_ui; void app_main(void) { // 先初始化显示和触摸 display_init(); touch_init(); lv_init(); lv_port_disp_init(); lv_port_indev_init(); // 再初始化GUI-Guider界面 setup_ui(&guider_ui); events_init(&guider_ui); // 主循环 while (1) { lv_task_handler(); vTaskDelay(pdMS_TO_TICKS(5)); } }setup_ui和events_init是GUI-Guider生成的函数名,具体名字可能因版本而异,看gui_guider.h里的声明。
这里有个顺序问题:必须先初始化LVGL和显示驱动,再调用setup_ui。因为setup_ui里会创建LVGL对象,如果LVGL还没初始化,会直接崩溃。
5.4 编译参数和分区表的调整
ESP32默认的分区表给应用程序的空间是1MB,如果LVGL和GUI-Guider代码加起来超过1MB,编译会报“app partition too small”。需要修改分区表,把app分区调大。
在menuconfig里,Partition Table选项选Custom partition table CSV,然后编辑partitions.csv:
nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, factory, app, factory, 0x10000, 0x300000,0x300000就是3MB,足够放LVGL和界面代码了。但注意Flash总大小要匹配,4MB的Flash最多给app分3MB左右,剩下的给文件系统和其他数据。
编译优化等级也影响很大。-Og调试友好但代码大,-Os体积小但可能影响性能。如果Flash紧张就用-Os,否则-Og方便调试。
6. 常见问题速查与避坑经验
6.1 编译错误速查表
| 错误信息 | 可能原因 | 解决方法 |
|---|---|---|
lv_conf.h: No such file | 路径未包含或文件位置不对 | 检查INCLUDE_DIRS,确认文件存在 |
undefined reference to 'lv_xxx' | 源文件未编译或条件编译关闭 | 检查CMakeLists和lv_conf.h宏 |
conflicting types for 'lv_xxx' | 版本不匹配 | 对齐GUI-Guider和LVGL版本 |
region 'iram0_0_seg' overflowed | 代码太大放不下IRAM | 把不要求速度的函数放到Flash |
app partition too small | 分区表app分区太小 | 修改partitions.csv |
6.2 运行崩溃的排查思路
ESP32上跑LVGL崩溃,最常见的原因是内存不足和栈溢出。
内存不足的表现是malloc failed或者Guru Meditation Error。排查方法是打印esp_get_free_heap_size(),看剩余堆内存。如果低于20KB,就很危险了。优化方法是减小LVGL内存池、减小显示缓冲区、把大数组放到PSRAM。
栈溢出的表现是任务运行一段时间后崩溃,或者调用某个函数时崩溃。FreeRTOS的任务栈默认是4KB,如果LVGL的lv_task_handler在任务里调用,4KB可能不够。可以加到8KB试试。在xTaskCreate的第三个参数里指定栈大小。
还有一个隐蔽的崩溃原因是中断优先级冲突。LVGL的tick定时器中断如果优先级设得太高,会打断WiFi或蓝牙的中断,导致系统不稳定。ESP32的中断优先级数值越小优先级越高,LVGL的tick中断建议设成3或4,不要设成1。
6.3 界面卡顿的优化清单
按优先级排序:
- 提高SPI时钟频率(40MHz起步,逐步加到稳定上限)
- 启用DMA传输
- 使用双缓冲区
- 减小显示缓冲区到屏幕的1/10
- 把LVGL内存池放到PSRAM(如果有)
- 减少界面控件数量,合并静态元素为图片
- 降低LVGL刷新周期(
lv_task_handler的调用间隔从5ms改成10ms)
实测下来,前三条做完,320x240的屏幕刷新率能从15fps提到45fps左右。后面几条是锦上添花。
6.4 我踩过的三个印象最深的坑
第一个坑:lv_conf.h里LV_MEM_SIZE设了32KB,界面简单的时候没问题。后来加了一个带图标的列表,运行几分钟就崩溃。查了一晚上才发现是内存池耗尽。改成64KB后稳定运行。教训是:内存池要留足余量,别按刚好够用来设。
第二个坑:SPI时钟设了80MHz,编译下载都正常,但屏幕偶尔闪一下白线。以为是接触不良,换了排线还是这样。后来用示波器看SPI波形,发现时钟上升沿有振铃,数据建立时间不够。降到60MHz后完全正常。教训是:SPI频率不是越高越好,要看实际信号质量。
第三个坑:GUI-Guider里用了一个自定义字体,导出后编译报错说字体数组太大。查了发现字体文件包含了整个GB2312字库,2万多个汉字。改成只生成界面上用到的十几个字后,文件从3MB降到8KB。教训是:字体一定要按需生成,别用全字库。
6.5 给新手的三个实用建议
第一,先跑通LVGL官方示例再导入GUI-Guider代码。LVGL的examples文件夹里有各种基础示例,先确保这些能正常显示,说明你的显示驱动和LVGL移植没问题。然后再导入GUI-Guider代码,这样出问题就只可能是GUI-Guider代码本身的问题,排查范围小很多。
第二,用串口打印关键信息。在flush_cb里打印刷新区域坐标,在lv_tick_inc里打印tick计数,在内存分配失败时打印剩余堆大小。这些信息在排查问题时非常有用。ESP32的串口输出很方便,ESP_LOGI宏直接就能用。
第三,保留一个能跑的最小工程。每次改配置之前,先备份一份能正常运行的工程。改出问题了,对比一下改了什么,或者直接回退。我见过太多人改着改着把能跑的工程改坏了,又回不去,只能从头再来。
界面开发这件事,工具能帮你省掉画控件的力气,但底层的移植和调试功夫省不掉。GUI-Guider生成的代码只是一个起点,真正让它跑起来、跑得稳,还是得靠对LVGL和ESP32的理解。我自己的经验是,第一个界面移植花了三天,第二个界面只花了半天,因为坑都踩过了。希望这篇内容能帮你少走一些弯路。