机器人设计与应用综合实训技术分享

ESP32-LVGL 安装移植应用实训记录表

适配开发环境:ESP-IDF、LVGL 9.4.0

前置基础:ESP32-LCD 汉字 / 时钟 / 动图基础开发文档性质:技术博客模板 | 实训报告辅助 | 工程实操复盘表

一、LVGL 环境配置与问题解决表

配置步骤  具体操作内容 预期结果  实测结果  问题现象  解决方法  经验总结

1. 组件版本配置 在 main/idf_component.yml 中添加依赖:

lvgl/lvgl: ^9.4.0

espressif/esp_lvgl_port: ^2.6.3

espressif/esp_lcd_touch_ft5x06: ^1.0.6 保存后 ESP-IDF 自动拉取对应版本组件      

2.SDK 配置开启 LVGL 执行 idf.py menuconfig → Component config → LVGL,开启 Enable LVGL LVGL 核心功能开启,支持调用相关 API       

3. 加载 LVGL 内置 Demo 在 menuconfig-LVGL 中勾选 LVGL Demos,选择需要的测试 Demo 工程自动关联 Demo 源码,可直接调用      

4. 路径问题处理 检查工程保存路径,确认无中文 / 特殊字符 / 空格 工程路径可被 ESP-IDF 正常识别,组件编译无路径报错  工程保存至 QQ 中文路径,组件安装失败、编译报错 1. 将工程迁移至纯英文 / 数字无空格路径;

2. 执行 idf.py reconfigure 重新加载配置;

3. 执行 idf.py build 验证 ESP-IDF 对中文 / 特殊字符路径兼容性差,所有工程需放在纯英文路径

二、代码修改记录表(LCD.c + LCD.h)

2.1 LCD.c 文件修改

表格

修改位置  新增 / 修改代码内容  代码功能说明 调用 / 生效方式

全局变量区域 // 引入 LVGL 相关头文件

#include "lvgl.h"

#include "esp_lvgl_port.h"

#include "esp_lcd_touch_ft5x06.h"

// LVGL 核心句柄定义

static esp_lcd_touch_handle_t tp;

static lv_disp_t *disp;

static lv_indev_t *disp_indev = NULL;  引入 LVGL 和触摸屏驱动头文件,定义液晶屏、触摸屏句柄 全局生效,仅在 LCD.c 内部调用

自定义函数区域 void lvgl_lcd_init(void){

lv_init();

esp_lvgl_port_init();

disp = esp_lvgl_port_add_disp(NULL);

disp_indev = esp_lvgl_port_add_indev(tp, disp);

lv_indev_set_type(disp_indev, LV_INDEV_TYPE_POINTER);

} LVGL 内核、ESP32 适配层初始化,绑定液晶屏与触摸屏 供 app_main.c 调用,工程启动时初始化

事件回调区域 static void btn_click_event(lv_event_t *e){

lv_obj_t *label = lv_event_get_user_data(e);

lv_label_set_text(label, "Touched!");

lv_obj_center(label);

} 触摸屏点击事件回调,实现按钮点击文本切换 绑定到触摸按钮,点击时触发

原有代码区域 保留原有 LCD 驱动、绘图、汉字显示等代码 延续基础 LCD 硬件驱动和功能 与 LVGL 代码无冲突,硬件复用

2.2 LCD.h 文件修改

表格

修改位置  新增 / 修改代码内容  代码功能说明 注意事项

头文件引入区域 // 新增 LVGL 核心头文件

#include "lvgl.h"

#include "esp_lvgl_port.h" 声明 LVGL 相关头文件,供外部调用  保留原有 LCD 驱动头文件,避免冲突

函数声明区域 // 新增 LVGL 初始化函数声明

void lvgl_lcd_init(void); 声明 LVGL 初始化函数,开放给 app_main.c 调用 保证头文件 #ifndef/define/endif 保护,避免重复包含

原有函数区域 保留 void bsp_lcd_init (void);

保留 void lcd_draw_pictrue (uint16_t x, uint16_t y, const unsigned char *pic); 延续原有 LCD 基础驱动功能 与 LVGL 功能复用硬件,无需修改原有代码

三、主函数(app_main.c)功能调用表

表格

调用顺序  函数名称  函数功能  调用目的  实测运行状态 备注

1 bsp_i2c_init(); 初始化 I2C 通信接口  为 LCD、触摸屏提供通信基础   原有基础代码,直接复用

2 pca9557_init(); 初始化外设 IO 扩展 驱动 LCD 相关外设   原有基础代码,直接复用

3 bsp_lcd_init(); 初始化 LCD 硬件驱动  完成液晶屏底层硬件配置   原有基础代码,直接复用

4 lvgl_lcd_init();  初始化 LVGL 与硬件适配 绑定 LVGL 到 LCD 和触摸屏   本次新增核心函数

5 lv_demo_widgets(); 启动 LVGL 官方控件 Demo 测试 LCD 显示和触摸屏交互   可替换为 lv_demo_music/lv_demo_benchmark

6 lv_timer_handler(); LVGL 定时器核心处理  处理触摸事件和界面刷新   必须在主循环中持续调用

7 vTaskDelay(pdMS_TO_TICKS(5));  短暂延时  降低 CPU 占用,避免阻塞   替换原有 delay (),适配 FreeRTOS

四、LVGL 功能测试表

表格

测试项目  测试操作  预期效果  实测结果  异常排查步骤 测试结论(正常 / 异常)

LVGL 基础显示 烧录程序后启动开发板,等待界面加载 LCD 屏幕正常显示 LVGL 官方 Demo 界面(按钮、滑块、文本等控件)    1. 检查 LCD 硬件接线;

2. 验证 bsp_lcd_init () 是否执行;

3. 确认 lvgl_lcd_init () 中 disp 句柄绑定成功 

触摸屏基础触摸 用手指点击 Demo 中的按钮、拖动滑块控件 点击按钮触发对应事件,拖动滑块实现参数调节,界面实时响应   1. 检查触摸屏接线;

2. 验证 FT5x06 驱动初始化;

3. 确认 disp_indev 句柄与 disp 绑定;

4. 调用坐标校准函数 esp_lcd_touch_calibrate ()

自定义触摸控件 点击自定义创建的 “Touch Me!” 按钮 按钮文本切换为 “Touched!”,文本保持居中显示   1. 检查按钮创建与坐标设置;

2. 验证事件回调函数是否绑定;

3. 确认 lv_timer_handler () 持续调用

多任务调度兼容性  同时运行 LVGL 界面和原有 LCD 动图 / 时钟功能  LVGL 界面无卡顿,触摸响应灵敏,原有 LCD 功能正常运行  1. 提高 LVGL 任务优先级;

2. 优化延时逻辑,使用 vTaskDelay ();

3. 降低 LCD 刷新帧率

LVGL 函数调用测试 从 LVGL 百问网调用字符、颜色设置函数,写入 LCD  屏幕正常显示自定义字符 / 颜色,参数修改实时生效  1. 确认函数头文件正确引入;

2. 检查函数参数与屏幕分辨率匹配;

3. 验证 LVGL 内核初始化完成

五、实训收获与问题复盘表

5.1 技术收获

表格

收获类别  具体内容

LVGL 基础操作 1. 掌握 LVGL 9.4.0 组件的配置与安装方法;

2. 理解 idf_component.yml 文件的组件依赖配置规则;

3. 学会通过 menuconfig 开启 LVGL 功能并加载官方 Demo

代码开发能力 1. 掌握在原有 LCD 驱动代码中添加 LVGL 适配代码的方法,实现代码兼容;

2. 理解 LVGL 核心句柄(disp/indev/tp)的作用与硬件绑定逻辑;

3. 学会编写 LVGL 自定义触摸控件和事件回调函数,实现基础交互

硬件软件适配 1. 掌握 ESP32 与 LVGL、FT5x06 触摸屏的多层适配逻辑;

2. 复用原有 LCD 硬件引脚和通信接口,实现基础功能与 LVGL 功能的硬件兼容;

3. 理解 FreeRTOS 与 LVGL 的任务调度适配要点

问题解决能力 1. 解决中文路径导致的 ESP-IDF 组件安装失败问题,掌握环境配置排错思路;

2. 掌握 LVGL 无显示、触摸屏无响应的基础排查流程(硬件→初始化→句柄绑定→逻辑);

3. 学会 LVGL 界面卡顿的优化方法,适配嵌入式系统资源限制

5.2 典型问题复盘

表格

问题编号  问题现象  涉及模块  根因分析  解决方法  复盘总结

1 工程保存至 QQ 中文路径,LVGL 组件拉取失败、编译报路径错误 开发环境 ESP-IDF 对中文 / 特殊字符 / 空格路径兼容性差,无法识别路径中的中文编码 1. 将工程迁移至纯英文 / 数字无空格路径;

2. 执行 idf.py reconfigure 重新加载工程配置;

3. 执行 idf.py build 重新编译验证 开发工程需提前规划路径,统一使用纯英文命名,规避环境配置底层问题

2 LVGL Demo 正常显示,触摸屏点击无任何响应 触摸屏驱动 + LVGL 适配 触摸屏句柄 disp_indev 未与液晶屏句柄 disp 绑定,输入事件无法传递到显示层 1. 在 lvgl_lcd_init () 中确认 disp_indev = esp_lvgl_port_add_indev (tp, disp);

2. 添加 lv_indev_set_type (disp_indev, LV_INDEV_TYPE_POINTER) 设置触摸类型;

3. 检查触摸屏驱动初始化是否在 LVGL 初始化前执行 硬件句柄需严格一一绑定,输入设备必须关联到对应显示设备,初始化有先后顺序

3 LVGL 界面刷新卡顿,触摸响应存在明显延迟 任务调度 + LVGL 配置 主循环延时过长,LVGL 定时器处理不及时,CPU 被过度占用,界面刷新帧率低 1. 将主循环延时从 pdMS_TO_TICKS (100) 改为 pdMS_TO_TICKS (5);

2. 在 menuconfig 中关闭 LVGL 不必要的动画、反走样效果;

3. 提高 LVGL 任务优先级,避免被其他任务阻塞 LVGL 开发需使用非阻塞式延时,适配 FreeRTOS 任务调度,根据硬件资源精简 LVGL 配置

4 自定义按钮创建后,LCD 屏幕无任何显示,无报错信息 LVGL 控件开发  按钮创建未关联到屏幕根对象,或按钮坐标 / 大小超出 LCD 屏幕分辨率 1. 确认按钮创建代码为 lv_btn_create (lv_scr_act ()),绑定到根对象;

2. 根据 LCD 实际分辨率设置合理的按钮坐标(x/y)和大小(宽 / 高);

3. 添加屏幕背景色设置,确认屏幕初始化正常 控件创建需先绑定显示根对象,所有坐标 / 尺寸参数必须匹配硬件屏幕实际参数

5 调用 LVGL 百问网函数时,编译报 “函数未定义” 错误  头文件与代码引用  未引入函数对应的头文件,或函数名 / 参数与 LVGL 版本不匹配  1. 从 LVGL 9.4.0 官方文档 / 百问网确认函数对应的头文件并引入;

2. 检查函数名、参数类型是否与 LVGL 9.x 版本兼容(避免使用 8.x 废弃函数);

3. 确认 LVGL 组件已正常拉取,头文件路径无误 不同 LVGL 版本函数存在兼容性差异,调用前需匹配版本,确保头文件完整引入

5.3 教学建议

表格

建议类别  具体建议内容

课程内容设计 1. 增加 LVGL 9.x 版本的专属案例教学,重点讲解组件配置、硬件适配和句柄绑定;

2. 补充 FT5x06 等主流触摸屏的驱动、校准实操内容,结合硬件讲解;

3. 结合 FreeRTOS 讲解 LVGL 任务调度,重点讲解非阻塞式延时和任务优先级设置;

4. 增加 LVGL 百问网常用函数的实操讲解,指导学生快速查询和调用

实操指导优化 1. 实训前提前强调 ESP-IDF 工程的纯英文路径要求,规避环境配置基础坑;

2. 提供 LVGL 与原有 LCD 代码的整合模板,标注新增代码和修改位置,降低开发难度;

3. 制作 LVGL 常见问题排查流程图(硬件→初始化→句柄→逻辑),方便学生自主排错;

4. 提供 LVGL 9.4.0 官方 Demo 和自定义控件的完整代码,供学生参考调试

硬件支持配套 1. 提供配套的 LVGL 兼容触摸屏,统一 FT5x06 硬件型号,减少驱动适配问题;

2. 标注 LCD 与触摸屏的接线对应关系,制作硬件接线图,减少接线错误;

3. 提供屏幕分辨率、引脚定义等硬件参数表,方便学生匹配代码参数

实训安排调整 1. 将 LVGL 学习分为 “配置安装→基础显示→触摸交互→综合应用” 四个阶段,循序渐进;

2. 增加小组实操答疑环节,针对环境配置、硬件接线等共性问题集中讲解;

3. 设置综合实训任务,要求基于 LVGL 实现 “触摸控制 + 显示 + 原有 LCD 功能” 的整合应用

 

六.部分代码:

static void event_handler(lv_event_t * e)

{

}

void lv_example_demo(void)

{

    lv_obj_t * label;

    lv_obj_t * btn1 = lv_button_create(lv_screen_active());

    lv_obj_add_event_cb(btn1, event_handler, LV_EVENT_ALL, NULL);

    // lv_obj_align(btn1, LV_ALIGN_CENTER, 0, -40);

    lv_obj_remove_flag(btn1, LV_OBJ_FLAG_PRESS_LOCK);

    lv_obj_set_width(btn1, 240);

    lv_obj_set_height(btn1, 24);

    lv_obj_set_x(btn1, 0);

    lv_obj_set_y(btn1, 0);

    label = lv_label_create(btn1);

    lv_label_set_text(label, "login");

    lv_obj_center(label);

    lv_obj_t * btn2 = lv_button_create(lv_screen_active());

    lv_obj_add_event_cb(btn2, event_handler, LV_EVENT_ALL, NULL);

    lv_obj_align(btn2, LV_ALIGN_CENTER, 0, 40);

    lv_obj_add_flag(btn2, LV_OBJ_FLAG_CHECKABLE);

    lv_obj_set_height(btn2, LV_SIZE_CONTENT);

    label = lv_label_create(btn2);

    lv_label_set_text(label, "Toggle");

    lv_obj_center(label);

   

    lv_obj_set_flex_flow(lv_screen_active(), LV_FLEX_FLOW_COLUMN);

    lv_obj_set_flex_align(lv_screen_active(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER);

    lv_obj_t * cb;

    cb = lv_checkbox_create(lv_screen_active());

    lv_checkbox_set_text(cb, "Apple");

    lv_obj_add_event_cb(cb, event_handler, LV_EVENT_ALL, NULL);

    cb = lv_checkbox_create(lv_screen_active());

    lv_checkbox_set_text(cb, "Banana");

    lv_obj_add_state(cb, LV_STATE_CHECKED);

    lv_obj_add_event_cb(cb, event_handler, LV_EVENT_ALL, NULL);

    lv_obj_update_layout(cb); 

    // 创建文本输入区域

    lv_obj_t *textarea = lv_textarea_create(lv_scr_act());

    lv_textarea_set_placeholder_text(textarea, "please input...");

    lv_textarea_set_one_line(textarea, true);  // 单行模式

    lv_obj_set_size(textarea, 300, 40);

}

void app_main(void)

{

    // 初始化硬件

    bsp_i2c_init();

    pca9557_init();

    bsp_lcd_init();

    bsp_lvgl_start();

    lv_example_demo();

    while (1){

        vTaskDelay(10);  // 延时1秒

    }

}

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐