这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » Let'sdo-2025年第3期-02任务3:有源蜂鸣器实现八音

共1条 1/1 1 跳转至

Let'sdo-2025年第3期-02任务3:有源蜂鸣器实现八音

高工
2025-12-01 11:05:23     打赏

        本此任务的目标主要是通过简单的有源蜂鸣器输出层次分明的八音,这样就实现了我们基本的播放器的输出基础。在很多项目中,使用蜂鸣器发出音符是一种常见且简单的方式。而如果要获得层次感就要用到PWM,在本任务文章中,将使用PWM(脉冲宽度调制)控制有源蜂鸣器,生成基础八音阶(即"哆瑞米发嗦啦西哆"),主要是我们最小接触的音乐知识可能就是这个了。

        "哆瑞米发嗦啦西哆" 这一连串的音符通常称为 C大调音阶,其中每个音符都有其特定的频率。这八个音符的名字及其对应的音高分别是:

            哆(Do): C4

            瑞(Re): D4

                米(Mi): E4

            发(Fa): F4

            嗦(Sol): G4

            啦(La): A4

            西(Ti): B4

            哆(Do): C5

        这些音符广泛应用于全球的音乐教育和演奏中,尤其是在 C大调(自然音阶)中,是最基础且最常见的一组音符。无论是钢琴、吉他还是其他乐器,它们的音符与频率几乎是固定的,因此可以被视为一种普适性音阶。

        在音乐中,音符对应的频率值是固定的。每个音符的频率是通过科学的音律计算得出的,并且通常以赫兹(Hz) 作为单位。C大调的八个音符与它们对应的频率如下:

            C4(哆):261.63 Hz

            D4(瑞):293.66 Hz

            E4(米):329.63 Hz

            F4(发):349.23 Hz

            G4(嗦):392.00 Hz

            A4(啦):440.00 Hz

            B4(西):493.88 Hz

            C5(哆):523.25 Hz

        我们可以看到,C4 到 C5 之间的音符频率遵循一定的规律,每个音符的频率相差约为 1.059 倍(即音程为半音)。

        通过有源蜂鸣器实现这些音符,PWM(脉冲宽度调制)是控制蜂鸣器频率的一种常见方法。通过改变 PWM 信号的频率,可以产生不同的音高。每个音符的频率都对应一个特定的 PWM 输出频率,从而控制蜂鸣器发出相应的声音。在CircuitPython中,我们可以通过 pulseio 或 simpleio来进行PWM控制,当然pwmio也可以。

        使用PWM控制蜂鸣器时,我们需要设定正确的频率,使得每个音符的声音正确匹配。比如:

            C4(261.63 Hz):用PWM频率为 261 Hz

            D4(293.66 Hz):用PWM频率为 294 Hz

            E4(329.63 Hz):用PWM频率为 330 Hz

            F4(349.23 Hz):用PWM频率为 349 Hz

            G4(392.00 Hz):用PWM频率为 392 Hz

            A4(440.00 Hz):用PWM频率为 440 Hz

            B4(493.88 Hz):用PWM频率为 494 Hz

            C5(523.25 Hz):用PWM频率为 523 Hz

        我们在上一章节的基础上增加一个有源蜂鸣器,控制引脚选用的是D13,硬件连接如下:

1.jpg

        软件控制方面这里使用的是pwmio来实现的:
import pwmio

# 设置蜂鸣器连接的引脚(D13)
pwm = pwmio.PWMOut(board.D13, duty_cycle=0, frequency=440, variable_frequency=True)


# 8 音阶频率(C4, D4, E4, F4, G4, A4, B4, C5)
note_names = ['C4', 'D4', 'E4', 'F4', 'G4', 'A4', 'B4', 'C5']
frequencies = [261, 293, 329, 349, 392, 440, 493, 523]

# 按键防抖延迟
DEBOUNCE_TIME = 0.2  # 防抖延时(秒)

# 音符播放时长(秒)
NOTE_DURATION = 0.5  # 每个音符的最大播放时长(秒)

# 音符播放控制函数
def play_note(note):
    if note in range(len(note_names)):
        names = note_names[note]
        freq = frequencies[note]
        print(f"Playing {names} at {freq} Hz")
        pwm.frequency = int(freq)
        pwm.duty_cycle = 2 ** 15
    else:
        print(f"Note {names} is not valid in the scale")


# 停止播放音符
def stop_playing():
    pwm.duty_cycle = 0


        然后通过按键,每按一次进行下一个声音的顺序播放,可以中途打断:
note_index = 0  # 当前音符的索引
last_button_state = False  # 上一次的按键状态(上拉状态下,未按下为False)
note_start_time = time.monotonic()  # 记录音符播放开始的时间
# 示例调用
while True:
    # 检测按键是否按下(低电平表示按下)
    current_button_state = button2.value  # 获取当前按键状态

    if not current_button_state and last_button_state:  # 按键刚被按下(由高电平变低电平)
        stop_playing()  # 停止当前音符(如果正在播放)
        play_note(note_index)  # 播放下一个音符

        # 切换到下一个音符,若达到最后一个音符则从头开始
        note_index = (note_index + 1) % len(note_names)
            
        # 重置音符开始播放的时间
        note_start_time = time.monotonic()
            
        # 防抖处理
        time.sleep(DEBOUNCE_TIME)

    # 自动停止音符播放
    if time.monotonic() - note_start_time > NOTE_DURATION:
        stop_playing()  # 超过最大播放时长后停止播放
        note_start_time = time.monotonic()  # 记录下一个音符的开始时间

    last_button_state = current_button_state  # 更新按键状态

    time.sleep(0.01)  # 稍微等一下,避免CPU占用过高

        这里需要注意一下,pulseio 或 simpleio都是通过阻塞式的方法进行的蜂鸣器的控制,播放时间的长短会影响后面的颜色采集以及播放效果,使用pwmio模块必须开启variable_frequency=True,才能实现动态调整。

        相关效果可以看一下教程视频内容。




共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]