1. 创建第一个LVGL项目
任务目标
在ESP32-S3开发板上搭建LVGL图形库开发环境,初始化显示屏驱动,最终在屏幕上居中显示“Hello World”文本。本案例使用ESP-IDF v5.x + LVGL v8.3作为软件栈,显示屏采用ILI9341(SPI接口,分辨率240x320)。
环境准备
- 硬件:ESP32-S3-DevKitC-1开发板、ILI9341 SPI显示屏模块、杜邦线若干
- 软件:ESP-IDF v5.1及以上版本(安装方法见官方文档)、Python 3.8+
- 接线:ILI9341的SCLK→GPIO12、MOSI→GPIO11、CS→GPIO10、DC→GPIO9、RST→GPIO8、BL→GPIO7(背光控制,可接3.3V常亮)
工程创建与依赖配置
使用IDF组件管理器添加LVGL和显示屏驱动依赖。在项目根目录执行以下命令创建基础工程:
idf.py create-project hello_lvgl
cd hello_lvgl
idf.py add-dependency "lvgl/lvgl@^8.3.11"
idf.py add-dependency "esp_lcd_ili9341"
在main/CMakeLists.txt中确认自动生成的依赖引用已包含上述两个组件。若使用自定义板级配置,需在sdkconfig.defaults中设置SPI引脚和屏幕参数:
CONFIG_LV_COLOR_DEPTH_16=y
CONFIG_LV_MEM_CUSTOM=1
CONFIG_LV_MEM_SIZE=65536
关键完整代码
在main/main.c中写入以下完整实现。代码包含SPI总线初始化、ILI9341显示驱动注册、LVGL显示缓冲区配置以及“Hello World”标签绘制:
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "driver/spi_master.h"
#include "esp_log.h"
#include "lvgl.h"
#define LCD_H_RES 240
#define LCD_V_RES 320
#define LCD_PIXEL_CLOCK_HZ (20 * 1000 * 1000)
#define LCD_SPI_NUM SPI2_HOST
#define LCD_GPIO_SCLK 12
#define LCD_GPIO_MOSI 11
#define LCD_GPIO_CS 10
#define LCD_GPIO_DC 9
#define LCD_GPIO_RST 8
static const char *TAG = "hello_lvgl";
static void lvgl_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p) {
esp_lcd_panel_handle_t panel = (esp_lcd_panel_handle_t)drv->user_data;
esp_lcd_panel_draw_bitmap(panel, area->x1, area->y1, area->x2 + 1, area->y2 + 1, color_p);
lv_disp_flush_ready(drv);
}
void app_main(void) {
// SPI总线配置
spi_bus_config_t bus_cfg = {
.sclk_io_num = LCD_GPIO_SCLK,
.mosi_io_num = LCD_GPIO_MOSI,
.miso_io_num = -1,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = LCD_H_RES * LCD_V_RES * 2
};
spi_bus_initialize(LCD_SPI_NUM, &bus_cfg, SPI_DMA_CH_AUTO);
// LCD IO配置
esp_lcd_panel_io_handle_t io_handle;
esp_lcd_panel_io_spi_config_t io_config = {
.dc_gpio_num = LCD_GPIO_DC,
.cs_gpio_num = LCD_GPIO_CS,
.pclk_hz = LCD_PIXEL_CLOCK_HZ,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
.spi_mode = 0,
.trans_queue_depth = 10
};
esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_SPI_NUM, &io_config, &io_handle);
// 初始化ILI9341
esp_lcd_panel_handle_t panel = NULL;
esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = LCD_GPIO_RST,
.color_space = ESP_LCD_COLOR_SPACE_RGB,
.bits_per_pixel = 16
};
esp_lcd_new_panel_ili9341(io_handle, &panel_config, &panel);
esp_lcd_panel_reset(panel);
esp_lcd_panel_init(panel);
esp_lcd_panel_invert_color(panel, true);
esp_lcd_panel_disp_on_off(panel, true);
// LVGL初始化
lv_init();
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf1[LCD_H_RES * 40];
lv_disp_draw_buf_init(&draw_buf, buf1, NULL, LCD_H_RES * 40);
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = LCD_H_RES;
disp_drv.ver_res = LCD_V_RES;
disp_drv.flush_cb = lvgl_flush_cb;
disp_drv.draw_buf = &draw_buf;
disp_drv.user_data = panel;
lv_disp_drv_register(&disp_drv);
// 创建并显示Hello World标签
lv_obj_t *label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Hello World");
lv_obj_center(label);
// LVGL定时刷新任务
while (1) {
lv_timer_handler();
vTaskDelay(pdMS_TO_TICKS(5));
}
}
编译与烧录
idf.py set-target esp32s3
idf.py build
idf.py -p /dev/ttyUSB0 flash monitor
将/dev/ttyUSB0替换为实际串口设备名。首次烧录后按复位键,屏幕应显示白色背景和黑色“Hello World”文本。
验证方法与通过条件
- 编译通过:执行
idf.py build无报错,生成hello_lvgl.bin固件文件。 - 屏幕点亮:烧录后ILI9341背光亮起,屏幕呈现白色背景(若显示为蓝色,说明颜色反转设置不正确,需调整
esp_lcd_panel_invert_color参数)。 - 文本显示:屏幕中央出现清晰可辨的黑色“Hello World”字样,字体无乱码或花屏。
- 系统稳定:持续运行5分钟无重启、无显示撕裂或闪烁现象。
常见问题排查
- 白屏无内容:检查SPI接线是否松动,确认
esp_lcd_panel_init返回ESP_OK。 - 显示颜色异常:ILI9341模块存在兼容性差异,尝试将
esp_lcd_panel_invert_color参数改为false。 - 编译报错找不到lvgl头文件:在项目根目录执行
idf.py reconfigure重新生成依赖。