4. PWM调光LED

任务目标

使用ESP32-S3的LEDC模块生成PWM信号驱动LED,实现亮度从暗到亮再回到暗的平滑呼吸灯效果。通过本案例掌握LEDC通道配置、PWM频率与占空比调节方法。

硬件准备

  • ESP32-S3开发板
  • LED(建议串联220Ω限流电阻)
  • 连接线:LED正极接GPIO48,负极经电阻接GND

核心代码

#include <stdio.h>
#include "driver/ledc.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define LED_GPIO        48
#define LEDC_TIMER      LEDC_TIMER_0
#define LEDC_MODE       LEDC_LOW_SPEED_MODE
#define LEDC_CHANNEL    LEDC_CHANNEL_0
#define LEDC_DUTY_RES   LEDC_TIMER_13_BIT   // 分辨率:13位,占空比0~8191
#define LEDC_FREQ_HZ    5000                // PWM频率5kHz

static const char *TAG = "pwm_led";

void app_main(void)
{
    // 1. 配置LEDC定时器
    ledc_timer_config_t timer_conf = {
        .speed_mode      = LEDC_MODE,
        .duty_resolution = LEDC_DUTY_RES,
        .timer_num       = LEDC_TIMER,
        .freq_hz         = LEDC_FREQ_HZ,
        .clk_cfg         = LEDC_AUTO_CLK
    };
    ESP_ERROR_CHECK(ledc_timer_config(&timer_conf));

    // 2. 配置LEDC通道
    ledc_channel_config_t channel_conf = {
        .gpio_num   = LED_GPIO,
        .speed_mode = LEDC_MODE,
        .channel    = LEDC_CHANNEL,
        .intr_type  = LEDC_INTR_DISABLE,
        .timer_sel  = LEDC_TIMER,
        .duty       = 0,
        .hpoint     = 0
    };
    ESP_ERROR_CHECK(ledc_channel_config(&channel_conf));

    ESP_LOGI(TAG, "PWM呼吸灯启动,GPIO%d,频率%dHz", LED_GPIO, LEDC_FREQ_HZ);

    uint32_t max_duty = (1 << 13) - 1;  // 8191
    uint32_t duty = 0;
    int8_t step = 8;  // 每次调整的占空比步长

    while (1) {
        // 3. 设置占空比并输出
        ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty));
        ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));

        duty += step;
        if (duty >= max_duty) {
            duty = max_duty;
            step = -step;   // 到达最亮,开始变暗
        } else if (duty == 0) {
            step = -step;   // 到达最暗,开始变亮
        }

        vTaskDelay(pdMS_TO_TICKS(10));  // 每10ms调整一次,完成一个周期约2秒
    }
}

编译与烧录

  1. 在ESP-IDF环境中创建项目,将上述代码保存为 main/pwm_led.c,并确保 main/CMakeLists.txt 中已注册该源文件。
  2. 在项目根目录执行 idf.py set-target esp32s3 设置目标芯片。
  3. 执行 idf.py build 编译固件。
  4. 连接开发板,执行 idf.py -p /dev/ttyUSB0 flash monitor 烧录并打开串口监视器(端口号按实际修改)。

验证方法

  • 观察LED是否呈现周期性由暗到亮、再由亮到暗的呼吸效果,周期约2秒。
  • 串口监视器应输出日志 PWM呼吸灯启动,GPIO48,频率5000Hz,无错误信息。
  • 用示波器或逻辑分析仪测量GPIO48,可见频率约5kHz、占空比在0%~100%之间周期性变化的方波信号。

关键说明

  • LEDC的13位分辨率对应占空比范围0~8191,ledc_set_duty 设置目标占空比后必须调用 ledc_update_duty 使配置生效。
  • 步长8和延时10ms共同决定呼吸速度,调整这两个参数可改变渐变快慢。
  • 若LED亮度变化不明显,可检查GPIO48是否支持LEDC输出(ESP32-S3大部分GPIO均可),并确认限流电阻连接正确。