3. PWM呼吸灯
任务目标
使用ESP32的LEDC外设产生PWM信号,驱动LED实现从暗到亮再变暗的呼吸效果。通过本案例理解PWM的占空比、频率概念,以及LEDC通道的配置方法。
所需硬件与接线
- ESP32开发板
- LED一个(建议串联220Ω限流电阻)
- 杜邦线
将LED阳极(长脚)经限流电阻连接到GPIO2,阴极(短脚)接GND。
核心原理
LEDC(LED Control)是ESP32内置的PWM外设,通过设置频率和占空比控制输出。呼吸灯的关键在于动态改变占空比:占空比从0逐步增大到最大值(LED渐亮),再逐步减小到0(LED渐暗),循环往复。本案例使用8位分辨率(0~255),频率设为5kHz(高于人眼闪烁感知阈值)。
完整代码
#include <stdio.h>
#include "driver/ledc.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define LED_GPIO 2
#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_8_BIT // 8位分辨率,占空比0~255
#define LEDC_FREQ_HZ 5000 // 5kHz PWM频率
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));
// 3. 呼吸循环:渐亮→渐暗
while (1) {
// 渐亮:占空比从0增加到255
for (int duty = 0; duty <= 255; duty++) {
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty));
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
vTaskDelay(pdMS_TO_TICKS(5)); // 每步延时5ms,约1.3s完成渐亮
}
// 渐暗:占空比从255减小到0
for (int duty = 255; duty >= 0; duty--) {
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty));
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
vTaskDelay(pdMS_TO_TICKS(5));
}
}
}
编译与烧录
- 在ESP-IDF环境中创建项目,将上述代码保存为
main.c(替换模板中的同名文件)。 - 在项目根目录执行
idf.py set-target esp32设置目标芯片。 - 执行
idf.py build编译。 - 连接开发板,执行
idf.py -p /dev/ttyUSB0 flash monitor烧录并打开串口监视器(Windows端口号请按实际修改)。
验证方法
烧录成功后,观察GPIO2所接LED是否呈现周期性呼吸效果:亮度从完全熄灭平滑增强到最亮,再平滑减弱至熄灭,循环周期约2.6秒。若LED不亮,检查接线和GPIO2是否被其他外设占用;若亮度跳变不连续,检查延时是否过短导致人眼无法分辨中间亮度等级。
关键参数调整
- 呼吸速度:修改
vTaskDelay的延时值(当前5ms),增大则变慢,减小则变快。 - 亮度范围:修改for循环的上下限(当前0~255),可限制最大亮度。
- PWM频率:修改
LEDC_FREQ_HZ,频率过低会导致LED闪烁,过高可能超出LEDC支持范围。