第 2 章:无源蜂鸣器(LEDC PWM 音调控制)
📂 示例代码:02_buzzer
2.1 知识要点
- LEDC(LED Control)外设的定时器与通道配置
- 通过动态修改 PWM 频率实现音调变化
- 占空比与音量的关系(50% 占空比驱动无源蜂鸣器)
- 音符频率表与旋律播放逻辑
2.2 课程内容
无源蜂鸣器需要外部提供特定频率的方波才能发声,频率决定音调。ESP32-S3 的 LEDC 外设可以灵活配置 PWM 频率,非常适合驱动蜂鸣器播放旋律。本章实现 C 大调音阶的上行与下行演奏。
2.3 基础学习
LEDC 外设结构
LEDC 包含 4 个定时器和 8 个通道(低速模式):
- 定时器:配置时钟源、分辨率(bit 数)、频率
- 通道:绑定到定时器,配置 GPIO 和占空比
蜂鸣器使用 LEDC_TIMER_1,10-bit 分辨率(1024 步),占空比 512(50%)时输出对称方波。
改变音调只需调用 ledc_set_freq(),无需重新初始化通道。静音时将占空比置 0。
音符频率(Hz)
C4=262 D4=294 E4=330 F4=349
G4=392 A4=440 B4=494 C5=5232.4 程序学习
初始化定时器与通道:
c
ledc_timer_config_t timer = {
.speed_mode = LEDC_LOW_SPEED_MODE,
.duty_resolution = LEDC_TIMER_10_BIT,
.timer_num = LEDC_TIMER_1,
.freq_hz = 1000,
.clk_cfg = LEDC_AUTO_CLK,
};
ledc_timer_config(&timer);
ledc_channel_config_t ch = {
.gpio_num = 42,
.speed_mode = LEDC_LOW_SPEED_MODE,
.channel = LEDC_CHANNEL_2,
.timer_sel = LEDC_TIMER_1,
.duty = 0,
};
ledc_channel_config(&ch);播放单个音符(非阻塞,esp_timer 异步关闭):
c
static esp_timer_handle_t s_buzzer_timer = NULL;
static void buzzer_set_off(void)
{
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, 0);
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2);
}
static void buzzer_timer_cb(void *arg) { buzzer_set_off(); }
static void buzzer_tone(uint32_t freq_hz, uint32_t duration_ms)
{
if (freq_hz == 0 || duration_ms == 0) { buzzer_set_off(); return; }
if (s_buzzer_timer == NULL) {
esp_timer_create_args_t args = { .callback = buzzer_timer_cb, .name = "buzzer" };
esp_timer_create(&args, &s_buzzer_timer);
}
esp_timer_stop(s_buzzer_timer);
ledc_set_freq(LEDC_LOW_SPEED_MODE, LEDC_TIMER_1, freq_hz);
ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2, 512); /* 50% duty */
ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_2);
/* 到期后由定时器回调异步关闭,不阻塞调用任务 */
esp_timer_start_once(s_buzzer_timer, (uint64_t)duration_ms * 1000);
}关键点:旧版用 vTaskDelay 阻塞等待音符结束,新版改用 esp_timer_start_once 启动一次性定时器,到期后回调自动将占空比置 0。调用方在 buzzer_tone 返回后可以立即执行其他逻辑,音符播放完全异步。
2.5 课程总结
本章学会了使用 LEDC 外设驱动无源蜂鸣器,掌握了通过动态修改频率实现音调控制的方法。LEDC 是 ESP32-S3 上最通用的 PWM 外设,后续章节的 ESC 和舵机控制也将使用它。