3. 滑动条调节亮度
任务目标
在ESP32上使用LVGL的滑动条(Slider)控件,通过PWM信号实时调节LED亮度。旋转滑动条时,LED亮度随之连续变化,并在屏幕上显示当前亮度百分比。
所需材料与依赖
- ESP32开发板(任意型号,推荐DevKitC)
- LED(普通5mm或3mm,串联220Ω限流电阻)
- LVGL v8.x(已移植到ESP32,推荐使用lv_port_esp32或ESP-IDF组件方式)
- LEDC(ESP32硬件PWM外设)驱动
硬件连接
LED阳极经220Ω电阻接GPIO2,阴极接GND。GPIO2为ESP32默认LEDC可用通道,无需额外配置。
关键完整代码
// main.c — 滑动条调节LED亮度(LVGL v8 + ESP-IDF)
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/ledc.h"
#include "lvgl.h"
#include "lvgl_helpers.h"
#define LEDC_GPIO 2
#define LEDC_TIMER LEDC_TIMER_0
#define LEDC_CHANNEL LEDC_CHANNEL_0
#define LEDC_MODE LEDC_LOW_SPEED_MODE
#define LEDC_DUTY_RES LEDC_TIMER_13_BIT // 分辨率8192
#define LEDC_FREQ_HZ 5000
static const char *TAG = "slider_demo";
// 滑动条事件回调:实时更新PWM占空比
static void slider_event_cb(lv_event_t *e) {
lv_obj_t *slider = lv_event_get_target(e);
lv_obj_t *label = (lv_obj_t *)lv_event_get_user_data(e);
int16_t val = lv_slider_get_value(slider);
uint32_t duty = (val * 8191) / 100; // 0~100 → 0~8191
ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty);
ledc_update_duty(LEDC_MODE, LEDC_CHANNEL);
lv_label_set_text_fmt(label, "亮度: %d%%", val);
}
// 初始化LEDC PWM
static void ledc_init(void) {
ledc_timer_config_t timer_conf = {
.speed_mode = LEDC_MODE,
.timer_num = LEDC_TIMER,
.duty_resolution = LEDC_DUTY_RES,
.freq_hz = LEDC_FREQ_HZ,
.clk_cfg = LEDC_AUTO_CLK
};
ledc_timer_config(&timer_conf);
ledc_channel_config_t ch_conf = {
.gpio_num = LEDC_GPIO,
.speed_mode = LEDC_MODE,
.channel = LEDC_CHANNEL,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = LEDC_TIMER,
.duty = 0,
.hpoint = 0
};
ledc_channel_config(&ch_conf);
}
// 创建LVGL界面:滑动条 + 亮度标签
static void create_ui(void) {
lv_obj_t *scr = lv_scr_act();
lv_obj_set_style_bg_color(scr, lv_color_hex(0x1E1E2E), 0);
// 滑动条(垂直方向,便于触摸操作)
lv_obj_t *slider = lv_slider_create(scr);
lv_obj_set_size(slider, 20, 200);
lv_obj_align(slider, LV_ALIGN_CENTER, -40, 0);
lv_slider_set_range(slider, 0, 100);
lv_slider_set_value(slider, 50, LV_ANIM_OFF);
// 亮度显示标签
lv_obj_t *label = lv_label_create(scr);
lv_label_set_text(label, "亮度: 50%");
lv_obj_align_to(label, slider, LV_ALIGN_OUT_RIGHT_MID, 30, 0);
// 绑定事件(将label作为user_data传入回调)
lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, label);
// 初始设置50%亮度
uint32_t init_duty = (50 * 8191) / 100;
ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, init_duty);
ledc_update_duty(LEDC_MODE, LEDC_CHANNEL);
}
void app_main(void) {
ledc_init();
// 初始化LVGL(需根据你的移植方式调整)
lvgl_helpers_init(); // 来自lv_port_esp32或lvgl_helpers组件
create_ui();
// LVGL任务循环
while (1) {
lv_task_handler();
vTaskDelay(pdMS_TO_TICKS(5));
}
}
运行与验证
- 将代码中的
lvgl_helpers_init()替换为你实际LVGL移植环境的初始化函数(如lv_init()+ 显示/触摸驱动初始化)。 - 编译烧录:
idf.py build flash monitor - 观察屏幕:应显示垂直滑动条和“亮度: 50%”标签。
- 触摸或拖动滑动条,观察LED亮度是否连续变化,同时标签百分比实时更新。
通过判定标准
- 滑动条拖动到0%时LED完全熄灭,100%时最亮,中间值亮度均匀过渡。
- 标签数值与滑动条位置严格同步,无跳变或滞后。
- LED无闪烁(PWM频率5kHz,人眼不可见频闪)。
常见问题
- LED不亮:检查GPIO2接线和限流电阻;确认LEDC初始化成功(查看串口日志有无错误)。
- 滑动条无反应:确认触摸驱动已正确初始化,且LVGL tick和任务循环正常运行。
- 亮度范围不对:检查
LEDC_DUTY_RES为13位时,最大占空比值为8191,代码中已按此换算。