蜂鸣器详解:有源 / 无源区别、PWM 驱动与树莓派 Pico MicroPython 实战

1.蜂鸣器基本知识

蜂鸣器(Buzzer)是一种用于产生声音的电子元件,广泛应用于各种设备中以发出警告声、提示音或其他声音效果。根据工作原理不同,蜂鸣器主要有以下几种类型:

1280X1280 (3).PNG

  • 有源蜂鸣器​​(Active ​Buzzer​​​:有源蜂鸣器内部集成了一个震荡电路用于生成固定频率的振荡信号,从而驱动压电蜂鸣器通过压电效应来产生声音,简单来说就是当施加电压时,压电材料会发生机械变形,从而产生声音;也有一些有源蜂鸣器使用电磁振动原理,当电流流过线圈时,会产生磁场,磁场使得一个铁片或膜片振动,从而发出声音。

1280X1280.PNG

  • 无源蜂鸣器​​(Passive ​Buzzer​​​:无源蜂鸣器内部没有震荡电路,它使用线圈和铁片或膜片,需要外部信号来驱动它发声。

1280X1280 (1).PNG

在实际应用中,二者各有侧重:

  • 有源蜂鸣器​:它适用于需要简单、固定声音的场合,但缺点是产生的声音频率是固定的,不能调节
  • 无源蜂鸣器​:我们可以通过调整外部信号的频率和占空比来改变蜂鸣器发出的声音频率和音调,其适用于需要产生多种音调或音频效果的场合,例如音乐播放、报警系统等

2.PWM 信号驱动蜂鸣器输出 MIDI 音乐

在下面实验中,我们需要将风雅一号板-通用兼容扩展板插入到风雅一号板-OLED显示与交互扩展板上,同时打开风雅一号板-OLED显示与交互扩展板​ ​SWITCH1 拨码开关的 BUZZER 选项:

1280X1280.JPEG

在以下代码中,我们使用 PWM 信号驱动无源蜂鸣器实现播放 《小星星》 MIDI 音乐的功能,MIDI(Musical Instrument Digital Interface)是一种用于电子乐器、计算机和其他音频设备之间通信的协议,对于 MIDI 音乐而已,不同音符可以对应不同频率的信号,例如,MIDI 编号 60(C4)对应的频率是 261Hz;而调节 PWM 信号的占空比,则可以控制音乐的音量,我们再调节不同音符持续的时间,同时按照规定的顺序播放每个音符即可使得蜂鸣器生成对应的 MIDI 音乐。

16ce1f66-9235-4a6b-a642-07a4d3ed0eb5.jfif
图 3-39 音乐驱动蜂鸣器原理

以下实验中所有代码开源在我们提供的资料包中 elegance-devkit v1\Demo\28 PWM_Buzzer 文件夹找到。

这里,我们使用树莓派 Pico 的 GPIO9 连接到蜂鸣器的信号输入端,示例代码如下所示:

# Python env   : MicroPython v1.23.0
# -*- coding: utf-8 -*-        
# @Time    : 2024/9/19 下午9:09   
# @Author  : 李清水            
# @File    : main.py       
# @Description : PWM类使用,驱动蜂鸣器播放MIDI音乐

# ======================================== 导入相关模块 =========================================

# 导入硬件相关的模块
from machine import Pin, PWM
# 导入时间相关模块
import time

# ======================================== 全局变量 ============================================

# 音符到频率的映射
NOTE_FREQS = {
    'C4': 261, 'D4': 293, 'E4': 329, 'F4': 349, 'G4': 392, 'A4': 440, 'B4': 493,
    'C5': 523, 'D5': 587, 'E5': 659, 'F5': 698, 'G5': 784, 'A5': 880, 'B5': 987,
    'C3': 130, 'D3': 146, 'E3': 164, 'F3': 174, 'G3': 196, 'A3': 220, 'B3': 246
}

# 小星星的旋律和节奏:即每个音符和其对应持续时间
MELODY = [
    ('C4', 400), ('C4', 400), ('G4', 400), ('G4', 400), ('A4', 400), ('A4', 400), ('G4', 800),
    ('F4', 400), ('F4', 400), ('E4', 400), ('E4', 400), ('D4', 400), ('D4', 400), ('C4', 800),
    ('G4', 400), ('G4', 400), ('F4', 400), ('F4', 400), ('E4', 400), ('E4', 400), ('D4', 800),
    ('G4', 400), ('G4', 400), ('F4', 400), ('F4', 400), ('E4', 400), ('E4', 400), ('D4', 800),
    ('C4', 400), ('C4', 400), ('G4', 400), ('G4', 400), ('A4', 400), ('A4', 400), ('G4', 800),
    ('F4', 400), ('F4', 400), ('E4', 400), ('E4', 400), ('D4', 400), ('D4', 400), ('C4', 800)
]

# ======================================== 功能函数 ============================================

# ======================================== 自定义类 ============================================

# 蜂鸣器类
class Buzzer:
    """
​    蜂鸣器类,用于通过PWM驱动蜂鸣器播放音符和旋律。

​    该类封装了对蜂鸣器的控制逻辑,支持播放单个音符和一段旋律。通过PWM调节频率和占空比,
​    可以实现不同音调和时长的声音效果。

​    Attributes:
​        buzzer (PWM): 蜂鸣器的PWM实例,用于控制频率和占空比。

​    Methods:
​        __init__(self, pin: int):
​            初始化蜂鸣器类实例。

​        play_tone(self, frequency: int, duration: int) -> None:
​            播放一个音符。

​        play_melody(self, melody: list) -> None:
​            播放一段旋律。
​    """

​    ​def __init__(self, pin: int):
        """
​        初始化蜂鸣器。

​        Args:
​            pin (int): 蜂鸣器连接的GPIO引脚编号。
​        """
​        ​# 设置PWM驱动蜂鸣器
        self.buzzer = PWM(Pin(pin))
        # 初始频率为2000
        self.buzzer.freq(2000)
        # 初始占空比为0
        self.buzzer.duty_u16(0)

    def play_tone(self, frequency: int, duration: int) -> None:
        """
​        播放一个音符。

​        Args:
​            frequency (int): 音符的频率(赫兹)。
​            duration (int): 音符的持续时间(毫秒)。

​        Returns:
​            None
​        """
​        ​# 设置蜂鸣器的频率
        self.buzzer.freq(frequency)
        # 设置占空比为50%
        self.buzzer.duty_u16(32768)
        # 持续时间
        time.sleep_ms(duration)
        # 停止发声
        self.buzzer.duty_u16(0)

    def play_melody(self, melody: list) -> None:
        """
​        播放一段旋律。

​        Args:
​            melody (list): 旋律的音符和持续时间列表,每个元素为一个元组 (note, duration)。
​                           note为音符名称(如 'C4'),duration为持续时间(毫秒)。

​        Returns:
​            None
​        """
​        ​for note, duration in melody:
            # 根据音符获取频率
            frequency = NOTE_FREQS.get(note, 0)
            if frequency:
                # 播放音符
                self.play_tone(frequency, duration)
            # 每个音符之间的间隔
            time.sleep_ms(10)

# ======================================== 初始化配置 ==========================================

# 上电延时3s
time.sleep(3)
# 打印调试信息
print("FreakStudio : Use PWM to drive a buzzer to play MIDI music")
# 初始化蜂鸣器对象
buzzer = Buzzer(pin=9)

# ========================================  主程序  ===========================================

# 循环播放音乐
while True:
    # 播放旋律《致爱丽丝》
    buzzer.play_melody(MELODY)

在以上代码中,我们首先声明一个字典 NOTE_FREQS,保存音符名称(如 'C4')和对应频率(赫兹),然后定义一个 MELODY 列表,保存音符和对应的持续时间(毫秒),这是《小星星》的旋律数据。

然后自定义了一个 Buzzer 类用于控制蜂鸣器,具有以下方法:

  • play_tone​ 方法​:用来播放指定频率和持续时间的音符
  • play_melody​ 方法​:用于遍历旋律列表,为每个音符播放相应的音调,并在每个音符之间添加短暂的间隔

在主程序部分,我们创建一个 Buzzer 类的实例,并将其连接到 GP22 引脚,然后在一个无限循环中播放旋律《小星星》;烧录代码,可以听到蜂鸣器根据预定义的旋律数据发出声音,实现播放 MIDI 音乐的功能。

mmexport1780889781398.gif

posted @ 2026-08-31 19:26  FreakStudio  阅读(13)  评论(0)    收藏  举报