/** * @file buzzer.c * @brief 无源蜂鸣器控制实现 (LEDC PWM) * * 无源蜂鸣器需要外部提供音频频率的方波才能发声, 不能像有源蜂鸣器那样 * 直接给高电平。这里用 LEDC 在独立定时器上产生可变频率的 50% 占空比方波。 * * 资源分配 (与 servo 错开): * servo : LEDC_TIMER_0 / LEDC_CHANNEL_0 (50Hz 固定) * buzzer : LEDC_TIMER_1 / LEDC_CHANNEL_2 (音频频率, 可动态改频) */ #include "buzzer.h" #include "driver/ledc.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #define BUZZER_TIMER LEDC_TIMER_1 #define BUZZER_MODE LEDC_LOW_SPEED_MODE #define BUZZER_CHANNEL LEDC_CHANNEL_2 #define BUZZER_DUTY_RES LEDC_TIMER_10_BIT /* 0~1023, 允许更高频率 */ #define BUZZER_MAX_DUTY 1023 #define BUZZER_DEFAULT_FREQ_HZ 4000 static const char *TAG = "BUZZER"; static bool s_initialized = false; static uint32_t s_freq_hz = 0; void buzzer_init(int gpio) { ledc_timer_config_t timer_cfg = { .speed_mode = BUZZER_MODE, .duty_resolution = BUZZER_DUTY_RES, .timer_num = BUZZER_TIMER, .freq_hz = BUZZER_DEFAULT_FREQ_HZ, .clk_cfg = LEDC_AUTO_CLK, }; ESP_ERROR_CHECK(ledc_timer_config(&timer_cfg)); ledc_channel_config_t chan_cfg = { .gpio_num = gpio, .speed_mode = BUZZER_MODE, .channel = BUZZER_CHANNEL, .intr_type = LEDC_INTR_DISABLE, .timer_sel = BUZZER_TIMER, .duty = 0, /* 默认静音 */ .hpoint = 0, .flags.output_invert = 0, }; ESP_ERROR_CHECK(ledc_channel_config(&chan_cfg)); s_initialized = true; s_freq_hz = BUZZER_DEFAULT_FREQ_HZ; ESP_LOGI(TAG, "初始化完成 (GPIO%d, 通道%d)", gpio, BUZZER_CHANNEL); } void buzzer_set_freq(uint32_t freq_hz) { if (!s_initialized || freq_hz == 0) return; if (freq_hz == s_freq_hz) return; ESP_ERROR_CHECK(ledc_set_freq(BUZZER_MODE, BUZZER_TIMER, freq_hz)); s_freq_hz = freq_hz; ESP_LOGD(TAG, "频率: %lu Hz", (unsigned long)freq_hz); } void buzzer_on(uint32_t freq_hz) { if (!s_initialized) return; buzzer_set_freq(freq_hz); ESP_ERROR_CHECK(ledc_set_duty(BUZZER_MODE, BUZZER_CHANNEL, BUZZER_MAX_DUTY / 2)); ESP_ERROR_CHECK(ledc_update_duty(BUZZER_MODE, BUZZER_CHANNEL)); } void buzzer_off(void) { if (!s_initialized) return; ESP_ERROR_CHECK(ledc_set_duty(BUZZER_MODE, BUZZER_CHANNEL, 0)); ESP_ERROR_CHECK(ledc_update_duty(BUZZER_MODE, BUZZER_CHANNEL)); } void buzzer_beep(uint32_t freq_hz, uint32_t duration_ms) { buzzer_on(freq_hz); vTaskDelay(pdMS_TO_TICKS(duration_ms)); buzzer_off(); } void buzzer_beep_twice(uint32_t freq_hz, uint32_t duration_ms) { buzzer_beep(freq_hz, duration_ms); vTaskDelay(pdMS_TO_TICKS(120)); buzzer_beep(freq_hz, duration_ms); } void buzzer_beep_triple(uint32_t freq_hz, uint32_t duration_ms) { buzzer_beep(freq_hz, duration_ms); vTaskDelay(pdMS_TO_TICKS(120)); buzzer_beep(freq_hz, duration_ms); vTaskDelay(pdMS_TO_TICKS(120)); buzzer_beep(freq_hz, duration_ms); }