ESP32-S3开发板LVGL图形界面开发实战教程
ESP32-S3开发板LVGL图形界面开发实战教程
前言
大家好!今天我们来深入探讨如何在ESP32-S3开发板上实现LVGL图形界面开发。随着物联网设备对用户友好界面需求的增加,掌握LVGL这样的轻量级图形库变得尤为重要。本文将带你从零开始,一步步实现一个可用的LVGL应用程序。
一、LVGL简介
LVGL(Light and Versatile Graphics Library)是一个开源的图形库,专为嵌入式系统设计,具有以下特点:
- 资源占用少,适合微控制器使用
- 支持多种显示控制器和输入设备
- 丰富的UI控件和动画效果
- 支持多语言、多主题
- 完全免费且开源
二、开发环境准备
2.1 硬件准备
- ESP32-S3开发板(带LCD显示屏和触摸屏)
- USB数据线
- 电脑一台
2.2 软件准备
- ESP-IDF开发环境
- VSCode编辑器
- ESP-IDF VS Code插件
三、项目搭建
3.1 创建项目
我们以ESP-IDF中的示例项目为基础,修改为支持LVGL的项目。具体步骤如下:
- 复制一个基础项目(例如LCD显示项目)
- 重命名项目文件夹
- 使用VS Code打开项目
3.2 项目结构分析
项目目录
├── CMakeLists.txt // 项目构建文件
├── main // 主程序目录
│ ├── CMakeLists.txt // 主程序构建文件
│ ├── main.c // 主函数入口
│ ├── esp32_s3_szp.c // 开发板驱动程序
│ └── esp32_s3_szp.h // 开发板驱动头文件
├── components // 组件目录
└── managed_components // 管理的组件目录
四、液晶屏与LVGL接口实现
4.1 液晶屏初始化函数
首先,我们需要实现液晶屏初始化并添加到LVGL的函数:
static lv_disp_t *bsp_display_lcd_init(void)
{/* 初始化液晶屏 */bsp_display_new(); // 液晶屏驱动初始化app_lcd_set_color(0xffff); // 设置整屏背景白色esp_lcd_panel_disp_on_off(panel_handle, true); // 打开液晶屏显示/* 添加LCD到LVGL */ESP_LOGD(TAG, "Add LCD screen");const lvgl_port_display_cfg_t disp_cfg = {.io_handle = io_handle,.panel_handle = panel_handle,.buffer_size = BSP_LCD_H_RES * BSP_LCD_DRAW_BUF_HEIGHT, // 缓冲区大小.double_buffer = true, // 启用双缓冲提高显示速度.hres = BSP_LCD_H_RES, // 水平分辨率.vres = BSP_LCD_V_RES, // 垂直分辨率.monochrome = false, // 是否为单色屏/* 旋转设置,必须与esp_lcd初始化时一致 */.rotation = {.swap_xy = true, // 交换XY坐标.mirror_x = true, // X轴镜像.mirror_y = false, // Y轴不镜像},.flags = {.buff_dma = false, // 不使用DMA传输.buff_spiram = true, // 使用外部SPIRAM存储缓冲区}};return lvgl_port_add_disp(&disp_cfg); // 添加显示设备到LVGL并返回句柄
}
注意:缓冲区大小设置为
BSP_LCD_H_RES * BSP_LCD_DRAW_BUF_HEIGHT
,其中BSP_LCD_DRAW_BUF_HEIGHT
是一次绘制的高度。受内存限制,如果使用内部内存,这个值不能太大,建议设为20(屏幕高度的约1/10)。如果使用外部PSRAM,可以设置为整个屏幕高度。
4.2 触摸屏初始化函数
接下来实现触摸屏初始化函数:
esp_err_t bsp_touch_new(esp_lcd_touch_handle_t *ret_touch)
{/* 初始化触摸屏配置 */const esp_lcd_touch_config_t tp_cfg = {.x_max = BSP_LCD_V_RES, // 触摸屏X最大值.y_max = BSP_LCD_H_RES, // 触摸屏Y最大值.rst_gpio_num = GPIO_NUM_NC, // 复位引脚未连接.int_gpio_num = GPIO_NUM_NC, // 中断引脚未连接.levels = {.reset = 0,.interrupt = 0,},.flags = {.swap_xy = 0, // 是否交换XY.mirror_x = 1, // 是否X轴镜像.mirror_y = 0, // 是否Y轴镜像},};// 配置I2C通讯esp_lcd_panel_io_handle_t tp_io_handle = NULL;const esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_FT5x06_CONFIG();// 创建I2C通讯接口并初始化触摸控制器ESP_RETURN_ON_ERROR(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)BSP_I2C_NUM, &tp_io_config, &tp_io_handle), TAG, "");return esp_lcd_touch_new_i2c_ft5x06(tp_io_handle, &tp_cfg, ret_touch);
}
4.3 触摸输入设备添加到LVGL
将触摸屏设备添加为LVGL的输入设备:
static lv_indev_t *bsp_display_indev_init(lv_disp_t *disp)
{ESP_ERROR_CHECK(bsp_touch_new(&tp)); // 初始化触摸屏assert(tp); // 确保触摸屏初始化成功/* 添加触摸输入设备到LVGL */const lvgl_port_touch_cfg_t touch_cfg = {.disp = disp, // 关联的显示设备.handle = tp, // 触摸屏句柄};return lvgl_port_add_touch(&touch_cfg); // 添加触摸设备到LVGL并返回句柄
}
4.4 LVGL初始化与启动函数
综合上面的函数,创建一个统一的LVGL启动函数:
// 开发板显示初始化
void bsp_lvgl_start(void)
{/* 初始化LVGL */lvgl_port_cfg_t lvgl_cfg = ESP_LVGL_PORT_INIT_CONFIG();lvgl_port_init(&lvgl_cfg);/* 初始化液晶屏并添加LVGL接口 */disp = bsp_display_lcd_init();/* 初始化触摸屏并添加LVGL接口 */disp_indev = bsp_display_indev_init(disp);/* 打开液晶屏背光 */bsp_display_backlight_on();
}
4.5 全局变量定义
需要定义以下全局变量:
static esp_lcd_touch_handle_t tp; // 触摸屏句柄
static lv_disp_t *disp; // 指向液晶屏
static lv_indev_t *disp_indev = NULL; // 指向触摸屏
五、组件配置与添加
5.1 添加必要组件
在idf_component.yml
文件中添加LVGL相关组件:
## IDF Component Manager Manifest File
dependencies:# espressif/esp32-camera: "^2.0.10" # 注释掉不需要的摄像头组件lvgl/lvgl: '~8.3.0' # LVGL核心库espressif/esp_lvgl_port: '~1.4.0' # LVGL接口espressif/esp_lcd_touch_ft5x06: '~1.0.6' # 触摸屏驱动
版本号前的
~
和^
符号有不同含义:
~8.3.0
表示下载8.3.*系列的最高版本(例如8.3.11)^8.3.0
表示下载8.*.*系列的最高版本(例如8.9.7)- 如果不加符号直接写版本号,则下载指定版本
5.2 摄像头模块条件编译
为了处理不需要摄像头功能的情况,在头文件中添加条件编译:
#define CAMERA_EN 0 // 设为1开启摄像头功能,设为0关闭#if CAMERA_EN
#include "esp_camera.h"
// 摄像头相关代码...
#endif
六、主程序实现
6.1 主函数编写
#include "demos/lv_demos.h" // 包含LVGL示例头文件void app_main(void)
{bsp_i2c_init(); // I2C初始化pca9557_init(); // IO扩展芯片初始化bsp_lvgl_start(); // 初始化LVGL显示/* 下面5个demos只打开1个运行 */lv_demo_benchmark(); // 性能测试演示// lv_demo_keypad_encoder(); // 键盘编码器演示// lv_demo_music(); // 音乐播放器演示// lv_demo_stress(); // 压力测试演示// lv_demo_widgets(); // 控件演示
}
七、LVGL配置
7.1 menuconfig配置
编译前需要通过menuconfig进行LVGL配置:
- 先选择目标芯片(ESP32-S3)
- 打开menuconfig配置界面
- 进行LVGL相关配置:
7.1.1 颜色配置
在LVGL配置中启用色彩交换(Color Swap):
7.1.2 字体配置
启用12像素和16像素大小字体:
7.1.3 Demo配置
启用需要的Demo演示程序:
注意:只需勾选主选项,子选项不需要勾选。
7.2 配置保存
配置完成后,使用以下命令保存配置:
idf.py save-defconfig
这将生成sdkconfig.defaults
文件,保存了在menuconfig中的配置(不包括默认配置)。
八、编译与下载
8.1 编译项目
执行编译命令:
idf.py build
8.2 下载到开发板
选择正确的串口后下载:
idf.py -p COM口号 flash
九、运行效果分析
成功运行后,开发板会显示LVGL的演示程序。其中:
- Benchmark演示:显示LVGL各种组件的性能测试
- Widgets演示:展示LVGL所有控件
- Stress演示:进行压力测试
- Music演示:显示音乐播放器界面(注意:在320×240分辨率下显示效果不佳)
- Keypad演示:展示键盘和编码器交互
十、常见问题与解决方法
10.1 编译错误
问题:缺少组件导致的编译错误。
解决:检查idf_component.yml
文件,确保所有依赖组件正确添加。
10.2 显示异常
问题:屏幕方向或触摸坐标不正确。
解决:检查rotation
配置中的swap_xy
、mirror_x
和mirror_y
设置是否正确。
10.3 内存不足
问题:运行LVGL时内存不足。
解决:减小buffer_size
或启用外部SPIRAM存储缓冲区。
十一、总结
通过本教程,我们学习了如何在ESP32-S3开发板上集成LVGL图形库,并运行多个演示程序。从液晶屏初始化、触摸屏配置到LVGL接口实现,每一步都进行了详细讲解。这为开发自己的图形界面应用打下了坚实基础。
希望本文对你有所帮助!如有任何问题,欢迎在评论区留言交流。
参考资料
- LVGL官方文档
- ESP-IDF编程指南
- ESP-BSP开发文档