基于RP2350B_PWM音乐播放器
该项目使用了RP2350B的PWM功能,实现了音乐播放器的设计,它的主要功能为:主要是实现在PWM音乐播放器。
标签
嵌入式系统
RP2350B核心板
PWM音频播放器
meiyao
更新2025-07-11
178

1、功能要求

上电开机显示PWM Music Player,按下任意按键时,会根据对应的设定播放不同音调,按键是通过ADC进行判断是哪一个按键按下的,再通过PWM驱动蜂鸣器播放不同音调,并支持按键切换歌曲和OLED显示曲名,使用的是CircuitPython固件代码。代码中按键消抖、PWM控制、OLED显示和音频播放逻辑。


2、硬件引脚


蜂鸣器PWM输出引脚:GP20(驱动),frequency=44000

按键:ADC引脚GP47(通过ADC检测按键,需配置为电阻分压模式)

按键工作电压分别是1.6V,2.5V,2.75V,3.0V

OLED SPI引脚:

SCK: 45,MOSI: 44,RES: 43,DC: 42,CS: 41.


3、软件框架图

image.png

4、代码:

下面的代码是音频音调

# 音符频率(Hz)
notes = {
'C4': 262, 'D4': 294, 'E4': 330, 'F4': 349,
'G4': 392, 'A4': 440, 'B4': 494,
'C5': 523, 'D5': 587, 'E5': 659, 'F5': 698,
'G5': 784, ' ': 0
}

# 生日快乐
melody_birthday = [
'G4', 'G4', 'A4', 'G4', 'C5', 'B4', ' ', ' ',
'G4', 'G4', 'A4', 'G4', 'D5', 'C5', ' ', ' ',
'G4', 'G4', 'G5', 'E5', 'C5', 'B4', 'A4', ' ',
'F5', 'F5', 'E5', 'C5', 'D5', 'C5', ' ', ' '
]

# 欢乐颂
melody_joy = [
'E4', 'E4', 'F4', 'G4', 'G4', 'F4', 'E4', 'D4',
'C4', 'C4', 'D4', 'E4', 'E4', 'D4', 'D4', ' ',
'E4', 'E4', 'F4', 'G4', 'G4', 'F4', 'E4', 'D4',
'C4', 'C4', 'D4', 'E4', 'D4', 'C4', 'C4', ' '
]
# 两只老虎
melody_tiger = [
'C4', 'D4', 'E4', 'C4', 'C4', 'D4', 'E4', 'C4',
'E4', 'F4', 'G4', 'E4', 'F4', 'G4', ' ', ' ',
'G4', 'A4', 'G4', 'F4', 'E4', 'C4', 'G4', 'A4', 'G4', 'F4', 'E4', 'C4', ' ',
'C4', 'C4', 'C4', ' ', 'C4', 'C4', 'C4', ' '
]

PWM引脚与ADC相关的代码


# 蜂鸣器PWM输出 - 使用GP20
buzzer = pwmio.PWMOut(board.GP20, duty_cycle=0, frequency=44000, variable_frequency=True)



# 初始化ADC用于按钮检测
adc = analogio.AnalogIn(board.GP47)

# 按键ADC值范围 (根据实际测量调整)
BUTTON_RANGES = [
(10000, 20000), # 按钮0 (停止)
(30500, 32000), # 按钮1 (歌曲1)
(30500, 33000), # 按钮2 (歌曲2)
(30500, 34000) # 按钮3 (歌曲3)
]


软件SPI代码和OLED

class SoftSPI:
def __init__(self, sck, mosi, miso=None):
self.sck = digitalio.DigitalInOut(sck)
self.mosi = digitalio.DigitalInOut(mosi)
self.sck.direction = digitalio.Direction.OUTPUT
self.mosi.direction = digitalio.Direction.OUTPUT
self._locked = False

def configure(self, **kwargs):
return self

def try_lock(self):
if not self._locked:
self._locked = True
return True
return False

def unlock(self):
self._locked = False

def write(self, buffer):
for byte in buffer:
for i in [7,6,5,4,3,2,1,0]: # MSB优先
self.sck.value = False
self.mosi.value = (byte >> i) & 0x01
self.sck.value = True

# 初始化OLED引脚
dc_pin = digitalio.DigitalInOut(board.GP42)
reset_pin = digitalio.DigitalInOut(board.GP43)
cs_pin = digitalio.DigitalInOut(board.GP41)

# 创建软件SPI对象
spi = SoftSPI(board.GP45, board.GP44) # sck, mosi

# 初始化OLED
oled = SSD1306_SPI(
width=128,
height=32,
spi=spi,
dc=dc_pin,
cs=cs_pin,
reset=reset_pin
)


显示字体代码

FONT_SHENG = [

0x01,0x00,0x11,0x00,0x11,0x00,0x11,0x00,

0x3F,0xFC,0x21,0x00,0x41,0x00,0x81,0x00,

0x01,0x00,0x3F,0xF8,0x01,0x00,0x01,0x00,

0x01,0x00,0x01,0x00,0xFF,0xFE,0x00,0x00

] # 生



FONT_RI = [

0x00,0x00,0x1F,0xF0,0x10,0x10,0x10,0x10,

0x10,0x10,0x10,0x10,0x10,0x10,0x1F,0xF0,

0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,

0x10,0x10,0x10,0x10,0x1F,0xF0,0x10,0x10

] # 日



FONT_KUAI = [

0x10,0x40,0x10,0x40,0x10,0x40,0x13,0xF8,

0x18,0x48,0x54,0x48,0x50,0x48,0x50,0x48,

0x97,0xFE,0x10,0x40,0x10,0xA0,0x10,0xA0,

0x11,0x10,0x11,0x10,0x12,0x08,0x14,0x06

] # 快



FONT_LE = [

0x00,0x20,0x00,0xF0,0x1F,0x00,0x10,0x00,

0x11,0x00,0x21,0x00,0x21,0x00,0x3F,0xFC,

0x01,0x00,0x09,0x20,0x09,0x10,0x11,0x08,

0x21,0x04,0x41,0x04,0x05,0x00,0x02,0x00

] # 乐



FONT_HUAN = [

0x00,0x00,0x1F,0xF0,0x10,0x10,0x10,0x10,

0x1F,0xF0,0x10,0x10,0x10,0x10,0x1F,0xF0,

0x10,0x10,0x10,0x10,0x1F,0xF0,0x10,0x10,

0x10,0x10,0x1F,0xF0,0x10,0x10,0x00,0x00

] # 欢



FONT_SONG = [

0x00,0x00,0x3F,0xF8,0x20,0x08,0x20,0x08,

0x3F,0xF8,0x20,0x08,0x20,0x08,0x3F,0xF8,

0x20,0x08,0x20,0x08,0x3F,0xF8,0x20,0x08,

0x20,0x08,0x3F,0xF8,0x20,0x08,0x00,0x00

] # 颂



FONT_LIANG = [

0x00,0x00,0x3F,0xF8,0x20,0x08,0x20,0x08,

0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,

0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,

0x20,0x08,0x3F,0xF8,0x20,0x08,0x00,0x00

] # 两



FONT_ZHI = [

0x00,0x00,0x1F,0xF0,0x10,0x10,0x10,0x10,

0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,

0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,

0x10,0x10,0x1F,0xF0,0x10,0x10,0x00,0x00

] # 只



FONT_LAO = [

0x00,0x00,0x1F,0xF0,0x10,0x10,0x10,0x10,

0x10,0x10,0x1F,0xF0,0x10,0x10,0x10,0x10,

0x10,0x10,0x1F,0xF0,0x10,0x10,0x10,0x10,

0x10,0x10,0x1F,0xF0,0x10,0x10,0x00,0x00

] # 老



FONT_HU = [

0x00,0x00,0x3F,0xF8,0x20,0x08,0x20,0x08,

0x20,0x08,0x3F,0xF8,0x20,0x08,0x20,0x08,

0x20,0x08,0x3F,0xF8,0x20,0x08,0x20,0x08,

0x20,0x08,0x3F,0xF8,0x20,0x08,0x00,0x00

] # 虎


主循环代码

# 主循环

def main():

current_song = 0 # 0=停止, 1=生日, 2=欢乐颂, 3=两只老虎

is_playing = False

last_button = None



# 初始显示

show_song_title(current_song)



while True:

button = get_button_pressed()



if button is not None and button != last_button:

last_button = button



if button == 0: # 停止

stop_music()

current_song = 0

is_playing = False

print("音乐停止")



elif button == 1: # 生日快乐

stop_music()

current_song = 1

is_playing = True

print("播放生日快乐")



elif button == 2: # 欢乐颂

stop_music()

current_song = 2

is_playing = True

print("播放欢乐颂")



elif button == 3: # 两只老虎

stop_music()

current_song = 3

is_playing = True

print("播放两只老虎")



show_song_title(current_song)



# 播放音乐

if is_playing:

if current_song == 1:

play_song(melody_birthday)

elif current_song == 2:

play_song(melody_joy)

elif current_song == 3:

play_song(melody_tiger)



time.sleep(0.1)



if __name__ == "__main__":

main()



OLED初始化:使用SPI接口初始化OLED屏幕,显示“PWM Music Player”和当前播放歌曲名。

PWM输出:通过GP20引脚输出PWM信号驱动蜂鸣器。

按键检测:通过ADC检测按键值,使用debounce_key函数实现消抖。


4、文字取模

image.png

取模方式更改为逐行式,尺寸为16*16,格式需要为C51,取模走向为顺向。


5.演示操作图

待机界面

image.png

播放音频欢乐颂

image.png

播放音频两只老虎

image.png

播放生日快乐

image.png

6.设计流程

image.png

总结:

从这个任务,其实我从中还是学到了不少的东西,特别是软件SPI,这个之前我一直在研究,连屏都点不亮,最终是朋友的指导,细心的讲解了要点,才把屏驱动 起来,其次是这个音调,从来没有想过,用2350这个能实现音频声音的发出,只听说过能用蜂鸣器能播放音乐,没想到自己也能实现,总的来说还是收获满满,又前进了一小步。

附件下载
main1.py
团队介绍
个人
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号