上一贴学习测试了 D2按钮,特别是使用 Debounce库进行了消抖处理:
https://forum.eepw.com.cn/thread/398114/1
这次赶紧来测试下beep蜂鸣器,并且让它跟着D1 和 D2按钮的动作鸣起来~~
l Beep硬件和接线
蜂鸣器我使用的是手头的存货,比较简单的3根线,丝印上显著位置标着:低电平触发。如图

图中可以看出,三根线除了GND和VCC外,只有一个IO口控制发声,低电平触发(有声音)。接线图如下:
Beep的GND引脚-------- 板子的GND引脚
I/O引脚-------- 板子的D13(GPIO13)
VCC引脚-------- 板子的 VCC(3.3V)
l Beep播放音符原理
我们本次任务选择了8个音阶:“哆瑞米发嗦啦西哆”,主要组成是C大调,每个音符都有其特定的频率,八个音符的名字及其对应的音高分别是:
哆(Do) : C4 261.63 Hz
瑞(Re) : D4 293.66 Hz
米(Mi) : E4 329.63 Hz
发(Fa) : F4 349.23 Hz
嗦(Sol): G4 392.00 Hz
啦(La) : A4 440.00 Hz
西(Ti) : B4 493.88 Hz
哆(Do): C5 523.25 Hz
蜂鸣器要播放这些音阶,需要通过不同频率的PWM来实现。根据上面的接线图,在D13引脚上输出对应这些频率的PWM信号,从而Beep发出不同频率的音调声音,也就是对应的音符。
实现PWM信号输出,可以使用内置的pwmio模块功能,其官方文档地址:
https://docs.circuitpython.org/en/latest/shared-bindings/pwmio/index.html
其实主要是设置PWM发生器的占空比 duty_cycle 和 频率(Hz)。其中占空比是个16位整数,取值范围为0~65535,对应就是duty的0—100%。 控制beep发声时,我们始终采用 duty=50%,也就是 2**15 =32767。而PWM的频率呢则需要根据音符来控制输出对应的Hz数,比如要让beep发出啦(La)这个音符,就把PWM的频率设置为对应的 440Hz。通过使用pwmio库可以很方便地实现上述功能。
需要注意的是,我手头这个存货 Beeper,是低电平触发,所以输出为高电平时不发声,为LOW时才会发声。所以要停止beep鸣叫,需要占空比100%即全是高电平才行;而需要beep发声时,占空比认为 50%即设置duty_cycle值为 2**15。
l 按钮动作要求
将按钮D1 和 D2 的动作也配合上。我这里对老师的代码做了点更改,因为要用示波器测量频率和波形,我去掉了超时音符自动停止播放的功能,改为按下D2键上升沿触发,播放下一个音符,一直保持播放;按下D1键上升沿触发时,才停止当前音符的播放。
配合我的Beep低电平触发的不同,加上使用 Debounce库来消除按键抖动,我最终的代码如下:
import board
import digitalio
import time
from adafruit_debouncer import Debouncer
import pwmio
# 按钮D1配置:Configure the digital input pin
pin = digitalio.DigitalInOut(board.D1)
pin.direction = digitalio.Direction.INPUT
pin.pull = digitalio.Pull.DOWN #下拉,默认低电平
# Initialize the debouncer with the pin
button1 = Debouncer(pin)
# 按钮D2配置:Configure the digital input pin
pin2 = digitalio.DigitalInOut(board.D2)
pin2.direction = digitalio.Direction.INPUT
pin2.pull = digitalio.Pull.DOWN #下拉,默认低电平
# Initialize the debouncer with the pin
button2 = Debouncer(pin2)
# 设置蜂鸣器连接的引脚 D13 为PWM
pwm = pwmio.PWMOut(board.D13, duty_cycle=65535, 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]
# 音符播放时长(秒)
NOTE_DURATION = 0.5 #每个音符的最大播放时长(秒)
# 音符播放控制函数----------------------------------
def play_note(note):
if note in range(len(note_names)):
name = note_names[note]
freq = frequencies[note]
print(f"Playing {name} at {freq} Hz")
pwm.frequency = int(freq)
pwm.duty_cycle = 2**15 #占空比50%
else:
print(f"Note {name} is not valid in the scale")
# 停止播放音符
def stop_playing():
pwm.duty_cycle = 65535
#print(f"Stoped playing note")
# --------------------------------------------------
note_index = 0 #当前音符的索引
note_start_time = time.monotonic() #记录音符开始播放的时间
is_playing = False #记录当前是否在播放
#示例调用
while True:
# Update the debouncer state
button1.update()
button2.update()
if button2.rose: #电平由0-->1,按键刚被按下
#print("D2 Just pressed")
if is_playing:
stop_playing() #停止当前音符
is_playing = False
play_note(note_index) #播放下一个音符
note_start_time = time.monotonic() #重置音符开始播放的时刻
is_playing = True
#切换到下一个音符,若达到最后一个音符则从头开始
note_index = (note_index + 1 ) % len(note_names)
if button1.rose: #电平由0-->1,按键刚被按下
#print("D1 Just pressed")
if is_playing:
stop_playing() #停止当前音符
is_playing = False
#自动停止音符播放
#if is_playing and time.monotonic() - note_start_time > NOTE_DURATION:
# stop_playing() #超过最大时长后停止播放
# is_playing = False
time.sleep(0.01) #稍等一下,避免CPU占用过高
在online ide中输入上述代码,保存后自动运行:

看下效果,每按下一次D2键,播放下一个音符。Gif动图听不到声音,所以我接上示波器查看PWM频率,果然跟屏幕上显示的音符Hz数完全一样!

----------------------------------------------------
完成了beep蜂鸣器的输出控制,就剩最后一个,颜色传感器啰~~~
zhw 2025.12.9
我要赚赏金
