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));
    }
}

运行与验证

  1. 将代码中的lvgl_helpers_init()替换为你实际LVGL移植环境的初始化函数(如lv_init() + 显示/触摸驱动初始化)。
  2. 编译烧录:idf.py build flash monitor
  3. 观察屏幕:应显示垂直滑动条和“亮度: 50%”标签。
  4. 触摸或拖动滑动条,观察LED亮度是否连续变化,同时标签百分比实时更新。

通过判定标准

  • 滑动条拖动到0%时LED完全熄灭,100%时最亮,中间值亮度均匀过渡。
  • 标签数值与滑动条位置严格同步,无跳变或滞后。
  • LED无闪烁(PWM频率5kHz,人眼不可见频闪)。

常见问题

  • LED不亮:检查GPIO2接线和限流电阻;确认LEDC初始化成功(查看串口日志有无错误)。
  • 滑动条无反应:确认触摸驱动已正确初始化,且LVGL tick和任务循环正常运行。
  • 亮度范围不对:检查LEDC_DUTY_RES为13位时,最大占空比值为8191,代码中已按此换算。
滑动条调节LED亮度 — 信号流 滑动条 0~100 value slider_event_cb duty = val×8191/100 更新标签文本 duty LEDC PWM 5kHz GPIO2 LED 标签同步显示