2. 创建第一个LVGL界面

任务目标

在ESP32上运行LVGL,创建一个包含标签和按钮的界面。点击按钮时,标签文本在“Hello LVGL”和“Button Pressed!”之间切换。

环境依赖

本案例基于ESP-IDF v5.x + LVGL v8.3,使用lvgl和esp_lcd组件。在idf.py menuconfig中确认LCD屏驱动(如ILI9341)和触摸(如XPT2046)已正确配置。若使用模拟器,可跳过硬件配置,直接编译运行。

关键完整代码

// main.c
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"

static const char *TAG = "lvgl_demo";

static lv_obj_t *label;
static lv_obj_t *btn;
static bool is_pressed = false;

static void btn_event_cb(lv_event_t *e) {
    (void)e;
    is_pressed = !is_pressed;
    if (is_pressed) {
        lv_label_set_text(label, "Button Pressed!");
    } else {
        lv_label_set_text(label, "Hello LVGL");
    }
}

static void create_ui(void) {
    // 创建标签
    label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Hello LVGL");
    lv_obj_align(label, LV_ALIGN_CENTER, 0, -40);

    // 创建按钮
    btn = lv_btn_create(lv_scr_act());
    lv_obj_set_size(btn, 120, 50);
    lv_obj_align(btn, LV_ALIGN_CENTER, 0, 40);
    lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_CLICKED, NULL);

    // 按钮上的标签
    lv_obj_t *btn_label = lv_label_create(btn);
    lv_label_set_text(btn_label, "Click Me");
    lv_obj_center(btn_label);
}

void app_main(void) {
    ESP_LOGI(TAG, "Starting LVGL demo");

    // 初始化显示和输入设备(由lv_port提供)
    lv_port_disp_init();
    lv_port_indev_init();

    // 创建UI
    create_ui();

    // LVGL主循环
    while (1) {
        lv_timer_handler();
        vTaskDelay(pdMS_TO_TICKS(5));
    }
}

运行与验证

  1. 编译烧录:在项目目录执行idf.py build flash monitor。
  2. 操作:屏幕中央显示“Hello LVGL”文本,下方为“Click Me”按钮。点击按钮后,上方文本切换为“Button Pressed!”,再次点击恢复为“Hello LVGL”。
  3. 通过条件:每次点击按钮,标签文本在两种状态间正确切换,无卡死或乱码,即判定通过。

常见问题

  • 屏幕无显示:检查lv_port_disp_init()中的LCD引脚配置和SPI时钟频率是否与硬件匹配。
  • 点击无响应:确认触摸驱动已初始化,且lv_port_indev_init()正确注册了输入设备。
  • 编译报错:确保LVGL版本为v8.3,且lv_conf.h中启用了LV_COLOR_DEPTH和所需字体。