无源蜂鸣器驱动代码例程

知识库
知识库文档
/firmware/被动元件/无源蜂鸣器/无源蜂鸣器驱动代码例程.md

文档

无源蜂鸣器驱动代码例程

硬件连接

MCU引脚 连接
GPIO PA0 (TIM2_CH1) → 1kΩ电阻 → S8050基极
S8050集电极 → 蜂鸣器(-)
蜂鸣器(+) → VCC (3.3V/5V)
S8050发射极 → GND

例程一:Arduino 环境

/*
 * 无源蜂鸣器 Arduino 驱动示例
 * 硬件:GPIO 9 → 1kΩ → S8050基极 → 蜂鸣器
 */

#define BUZZER_PIN  9

// 音符频率定义 (Hz)
#define NOTE_C4  262
#define NOTE_D4  294
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_G4  392
#define NOTE_A4  440
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_0   0   // 休止符

// 小星星旋律
int melody[] = {
    NOTE_C4, NOTE_C4, NOTE_G4, NOTE_G4,
    NOTE_A4, NOTE_A4, NOTE_G4,
    NOTE_F4, NOTE_F4, NOTE_E4, NOTE_E4,
    NOTE_D4, NOTE_D4, NOTE_C4,
    NOTE_G4, NOTE_G4, NOTE_F4, NOTE_F4,
    NOTE_E4, NOTE_E4, NOTE_D4,
    NOTE_G4, NOTE_G4, NOTE_F4, NOTE_F4,
    NOTE_E4, NOTE_E4, NOTE_D4,
    NOTE_C4, NOTE_C4, NOTE_G4, NOTE_G4,
    NOTE_A4, NOTE_A4, NOTE_G4,
    NOTE_F4, NOTE_F4, NOTE_E4, NOTE_E4,
    NOTE_D4, NOTE_D4, NOTE_C4
};

int noteDurations[] = {
    4, 4, 4, 4, 4, 4, 2,
    4, 4, 4, 4, 4, 4, 2,
    4, 4, 4, 4, 4, 4, 2,
    4, 4, 4, 4, 4, 4, 2,
    4, 4, 4, 4, 4, 4, 2,
    4, 4, 4, 4, 4, 4, 2
};

void setup() {
    pinMode(BUZZER_PIN, OUTPUT);
    Serial.begin(9600);
    Serial.println("无源蜂鸣器测试开始");
}

void loop() {
    // 播放小星星
    for (int i = 0; i < sizeof(melody) / sizeof(melody[0]); i++) {
        int noteDuration = 1000 / noteDurations[i];
        if (melody[i] != NOTE_0) {
            tone(BUZZER_PIN, melody[i], noteDuration);
        }
        delay(noteDuration * 1.3);  // 音符间加间隔
        noTone(BUZZER_PIN);
    }
    delay(2000);  // 循环间隔
}

// ====== 驱动函数封装 ======

/**
 * @brief 蜂鸣器发声
 * @param frequency 频率(Hz),范围 31 ~ 65535
 * @param duration_ms 持续时间(ms),0表示持续发声直到调用stopBuzzer()
 */
void buzzerBeep(uint16_t frequency, uint32_t duration_ms) {
    if (frequency > 0) {
        tone(BUZZER_PIN, frequency, duration_ms);
    }
}

/**
 * @brief 停止蜂鸣器
 */
void buzzerStop(void) {
    noTone(BUZZER_PIN);
}

/**
 * @brief 短促提示音
 */
void buzzerShortBeep(void) {
    tone(BUZZER_PIN, 2300, 100);
}

/**
 * @brief 报警音(交替频率)
 */
void buzzerAlarm(uint8_t repeat) {
    for (uint8_t i = 0; i < repeat; i++) {
        tone(BUZZER_PIN, 2000, 200);
        delay(250);
        tone(BUZZER_PIN, 3000, 200);
        delay(250);
    }
    noTone(BUZZER_PIN);
}

例程二:STM32 HAL 库(PWM 方式)

/*
 * 无源蜂鸣器 STM32 HAL PWM 驱动
 * 使用 TIM2_CH1 (PA0) 输出 PWM
 * 系统时钟 72MHz,TIM2 预分频 72-1 → 1MHz
 * ARR = 1000000/freq - 1
 */

#include "main.h"
#include <math.h>

// 音符频率定义
#define C4  262
#define D4  294
#define E4  330
#define F4  349
#define G4  392
#define A4  440
#define B4  494
#define C5  523

TIM_HandleTypeDef htim2;
static uint8_t buzzer_enabled = 0;

/**
 * @brief 蜂鸣器PWM初始化
 * @note  PA0 = TIM2_CH1, 预分频72→1MHz计数
 */
void Buzzer_PWM_Init(void) {
    __HAL_RCC_TIM2_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 72 - 1;          // 72MHz / 72 = 1MHz
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 1000 - 1;           // 默认1kHz
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    HAL_TIM_PWM_Init(&htim2);

    TIM_OC_InitTypeDef sConfigOC = {0};
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = 500;                  // 50%占空比
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);
}

/**
 * @brief 设置蜂鸣器频率
 * @param freq 频率(Hz),传0则停止
 */
void Buzzer_SetFrequency(uint16_t freq) {
    if (freq == 0) {
        HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1);
        buzzer_enabled = 0;
        return;
    }

    uint32_t arr = 1000000UL / freq - 1;     // ARR = 1MHz/freq - 1
    if (arr < 10) arr = 10;
    if (arr > 65535) arr = 65535;

    __HAL_TIM_SET_AUTORELOAD(&htim2, arr);
    __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, arr / 2);  // 50%占空比

    if (!buzzer_enabled) {
        HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
        buzzer_enabled = 1;
    }
}

/**
 * @brief 蜂鸣器发声指定时长(阻塞式)
 * @param freq 频率(Hz)
 * @param duration_ms 时长(ms)
 */
void Buzzer_Beep(uint16_t freq, uint32_t duration_ms) {
    Buzzer_SetFrequency(freq);
    HAL_Delay(duration_ms);
    Buzzer_SetFrequency(0);
}

/**
 * @brief 停止蜂鸣器
 */
void Buzzer_Stop(void) {
    Buzzer_SetFrequency(0);
}

/**
 * @brief 播放旋律(阻塞式)
 * @param notes 音符频率数组
 * @param durations 时值数组(如4=四分音符)
 * @param length 数组长度
 * @param tempo 速度(bpm)
 */
void Buzzer_PlayMelody(const uint16_t *notes, const uint8_t *durations,
                       uint8_t length, uint8_t tempo) {
    for (uint8_t i = 0; i < length; i++) {
        uint32_t note_ms = (60000UL / tempo) / durations[i];
        if (notes[i] > 0) {
            Buzzer_Beep(notes[i], note_ms * 0.9);
        }
        HAL_Delay(note_ms * 0.1);  // 音符间隔
    }
}

/* ====== 使用示例 ====== */

// 小星星旋律
const uint16_t twinkle_notes[] = {
    C4, C4, G4, G4, A4, A4, G4, 0,
    F4, F4, E4, E4, D4, D4, C4, 0
};
const uint8_t twinkle_durs[] = {
    4, 4, 4, 4, 4, 4, 2, 8,
    4, 4, 4, 4, 4, 4, 2, 8
};

int main(void) {
    HAL_Init();
    SystemClock_Config();

    Buzzer_PWM_Init();

    while (1) {
        // 方式一:直接调用
        Buzzer_Beep(2300, 200);   // 2.3kHz 200ms
        HAL_Delay(500);

        // 方式二:播放旋律
        Buzzer_PlayMelody(twinkle_notes, twinkle_durs, 16, 120);
        HAL_Delay(2000);
    }
}

例程三:ESP8266 (Arduino) 非阻塞驱动

/*
 * 无源蜂鸣器 ESP8266 非阻塞驱动
 * 使用 Ticker 定时器实现非阻塞发声
 * 硬件:GPIO D2 (GPIO4) → 1kΩ → S8050 → 蜂鸣器
 */

#include <Ticker.h>

#define BUZZER_PIN  4   // D2 = GPIO4

Ticker buzzerTicker;
volatile bool isPlaying = false;

void buzzerToggle() {
    static uint8_t state = 0;
    state = !state;
    digitalWrite(BUZZER_PIN, state);
}

/**
 * @brief 非阻塞蜂鸣器发声
 * @param freq 频率(Hz)
 * @param duration_ms 持续时间(ms)
 */
void buzzerBeepNonBlocking(uint16_t freq, uint32_t duration_ms) {
    if (freq == 0 || duration_ms == 0) return;

    // 计算Ticker间隔(微秒),频率=1/周期,周期/2=半周期(翻转间隔)
    float period_us = 1000000.0f / freq;
    float half_period_us = period_us / 2.0f;

    isPlaying = true;
    buzzerTicker.attach_us(half_period_us, buzzerToggle);

    // 使用 once 在指定时间后停止
    Ticker stopTicker;
    stopTicker.once_ms(duration_ms, []() {
        buzzerTicker.detach();
        digitalWrite(BUZZER_PIN, LOW);
        isPlaying = false;
    });
}

void setup() {
    pinMode(BUZZER_PIN, OUTPUT);
    digitalWrite(BUZZER_PIN, LOW);
    Serial.begin(115200);
}

void loop() {
    buzzerBeepNonBlocking(2300, 200);
    delay(1000);
}

信息

路径
/firmware/被动元件/无源蜂鸣器/无源蜂鸣器驱动代码例程.md
更新时间
2026/5/25