2. 按钮控制LED
任务目标
在ESP32上使用LVGL创建一个按钮控件,每次点击按钮时切换板载LED(GPIO2)的开关状态,并在按钮上实时显示当前LED状态(“LED: ON” / “LED: OFF”)。
环境与依赖
- 硬件:ESP32开发板(板载LED接GPIO2)
- 框架:ESP-IDF v5.x + LVGL v8.3(已配置好显示驱动与触摸/编码器输入)
- LVGL配置:确保
CONFIG_LVGL_USE_SYSMON未开启,lv_tick_inc()已在定时器中调用
核心实现
本案例通过LVGL按钮的事件回调函数,在每次点击时翻转LED电平,并同步更新按钮上的文本标签。代码采用最小实现,不涉及额外UI元素。
// main.c 核心代码(仅展示LVGL相关部分)
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "lvgl.h"
#define LED_GPIO 2
static lv_obj_t *btn;
static lv_obj_t *btn_label;
static bool led_state = false;
// 按钮点击事件回调
static void btn_event_cb(lv_event_t *e) {
// 翻转LED状态
led_state = !led_state;
gpio_set_level(LED_GPIO, led_state ? 1 : 0);
// 更新按钮文本
lv_label_set_text(btn_label, led_state ? "LED: ON" : "LED: OFF");
}
// 创建UI(在lvgl初始化完成后调用)
static void ui_create(void) {
// 创建按钮
btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 160, 60);
lv_obj_center(btn);
// 添加标签
btn_label = lv_label_create(btn);
lv_label_set_text(btn_label, "LED: OFF");
lv_obj_center(btn_label);
// 绑定点击事件
lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_CLICKED, NULL);
}
// 主任务(在app_main中创建)
void lvgl_demo_task(void *arg) {
// 初始化GPIO
gpio_reset_pin(LED_GPIO);
gpio_set_direction(LED_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(LED_GPIO, 0);
// 创建UI
ui_create();
// LVGL主循环
while (1) {
lv_task_handler();
vTaskDelay(pdMS_TO_TICKS(10));
}
}
void app_main(void) {
// 假设lvgl_init()已完成显示驱动、输入驱动和lv_init()的初始化
xTaskCreate(lvgl_demo_task, "lvgl_demo", 4096, NULL, 5, NULL);
}
运行与验证
- 将上述代码合并到你的ESP-IDF工程中,确保LVGL已正确初始化(包括显示驱动和输入设备驱动)。
- 编译并烧录:
idf.py build flash monitor - 观察屏幕:应显示一个居中按钮,初始文本为“LED: OFF”。
- 点击按钮(通过触摸屏或编码器按键),观察板载LED是否亮起,按钮文本变为“LED: ON”。
- 再次点击,LED熄灭,文本恢复为“LED: OFF”。
通过条件:每次点击按钮,LED状态和按钮文本同步切换,无卡顿或误触发。
关键说明
- 事件使用
LV_EVENT_CLICKED,仅在按钮释放且仍在按钮区域内时触发,避免长按误操作。 - GPIO2在部分开发板上可能连接板载LED(低电平点亮),若你的硬件极性相反,将
gpio_set_level中的逻辑反转即可。 - 若使用编码器按键作为输入,需确保LVGL的输入设备已正确注册,否则按钮无法获得焦点和点击事件。