107 lines
3.1 KiB
C
107 lines
3.1 KiB
C
/**
|
|
* @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);
|
|
}
|