基于RP2350B实现PWM音乐播放器
该项目使用了RP2350B核心板、MicroPython语言,实现了PWM音乐播放器的设计,它的主要功能为:根据不同的按键被按下,用PWM驱动蜂鸣器播放对应的音乐,并且在OLED屏幕上显示对应音乐的中文名。
标签
MPU
PWM
RP2350B
无源蜂鸣器
OLED显示中文
波波l
更新2025-07-10
10
  • 项目介绍

基于RP2350B实现PWM音乐播放器的项目主要是:使用了RP2350B核心板、MicroPython语言,实现了PWM音乐播放器设计,它的主要功能为:根据不同的按键被按下,用PWM驱动蜂鸣器播放对应的音乐,并且在OLED屏幕上显示对应音乐的中文名。可以播放的音乐有《小星星》《生日快乐》《告别》都是C调歌曲

  • 硬件介绍

这里硬禾科技提供的硬件为:RP2350B核心板、基于小脚丫FPGA的综合技能训练板

本次活动用到RP2350B核心板引出的引脚和小脚丫FPGA的综合技能训练板是兼容的可以直接使用。

image.png

小脚丫FPGA综合训练板


image.png

由于MicroPython固件的原因扩展板上的OLED屏幕无法使用,于是我外接了一个OLED屏幕,这个外接的OLED屏幕与扩展板上的OLED屏幕相同都是5线spi,都是SSD1306驱动的。唯一的区别就是扩展版上的屏幕分辨率是128x32的,我外接的屏幕分辨率是128x64的。具体如下图:


P20250504-160812.jpg

硬件图

OLED接线:

CLK-------GPIO4

MOSI-----GPIO5

RES-------GPIO6

DC--------GPIO7

CS--------GPIO8

蜂鸣器接线:

MLT-8530---GPIO20

三个按键:

button_1---GPIO17

button_2---GPIO18

button_3---GPIO19


  • 方案框图和项目设计思路介绍

程序流程相对简单,就是根据不同的按键被按下,用PWM驱动蜂鸣器播放对应的音乐,并且在OLED屏幕上显示对应音乐的中文名。

方案框图


这里按键采用了一个延时消抖的方式,没有采用中断是害怕中断对PWM播放音乐进行影响。PWM驱动蜂鸣器这里,设定了一个c调的蜂鸣器频率,然后根据乐谱查询PWM频率和PWM持续时间进行播放音乐。OLED屏幕上显示对应音乐的中文名这里,OLED显示汉字采用汉字字模的方式显示,因为显示的汉字个数不多采用字模的方式很方便。并且在歌曲列表前显示一个光标'>'来指示正在播放的音乐。

image.png

程序流程图


  • 关键代码介绍

main.py文件:

from machine import Pin, PWM, SoftSPI
from Drive.ssd1306 import SSD1306_SPI
import time

import Drive.Key_Scan #导入按键文件包含消抖函数
import Drive.PWM_Text #导入PWM文件包含播放音乐函数
import Drive.OLED_zh #导入OLED文件包含显示汉字函数

little_start_list = Drive.PWM_Text.little_start_list
happy_birthday_list = Drive.PWM_Text.happy_birthday_list
farewell_list = Drive.PWM_Text.farewell_list
#开启PWM
PWM_Music = PWM(Pin(20, Pin.OUT))
PWM_Music.duty_u16(0)
#屏幕初始化
oled = Drive.OLED_zh.OLED_Init()
flag = 0
while 1 :

flag = Drive.Key_Scan.Get_Key()
if flag == 1 :
Drive.OLED_zh.Rectangle_Blck(0, 16, 8, 48, oled, 0)
oled.text('>',0,20)
oled.show()
Drive.PWM_Text.Music_Play(PWM_Music,little_start_list)
if flag == 2 :
Drive.OLED_zh.Rectangle_Blck(0, 16, 8, 48, oled, 0)
oled.text('>',0,36)
oled.show()
Drive.PWM_Text.Music_Play(PWM_Music,happy_birthday_list)
if flag == 3 :
Drive.OLED_zh.Rectangle_Blck(0, 16, 8, 48, oled, 0)
oled.text('>',0,52)
oled.show()
Drive.PWM_Text.Music_Play(PWM_Music,farewell_list)

Drive.OLED_zh.Rectangle_Blck(0, 16, 8, 48, oled, 0)

Key_Scan.py文件:

from machine import Pin
import time

button_1 = Pin(17, Pin.IN, Pin.PULL_UP)
button_2 = Pin(18, Pin.IN, Pin.PULL_UP)
button_3 = Pin(19, Pin.IN, Pin.PULL_UP)
#按键消抖
def Deshaking_Key(button):
if not button.value():
time.sleep_ms(50)
if not button.value():
while not button.value():pass
return 1
else:
return 0
else:
return 0
#获取按键值
def Get_Key():
if Deshaking_Key(button_1):
return 1
elif Deshaking_Key(button_2):
return 2
elif Deshaking_Key(button_3):
return 3
else :
return 0

PWM_Text.py文件:

from machine import Pin, PWM
import time
#C调蜂鸣器频率
tone_list = [262, 294, 330, 350, 393, 441, 495,
525, 589, 661, 700, 786, 882, 990]
#小星星乐谱
little_start_list = [1,1, 5,5, 6,6, 5,0,
4,4, 3,3, 2,2, 1,0,
5,5, 4,4, 3,3, 2,0,
5,5, 4,4, 3,3, 2,0,
1,1, 5,5, 6,6, 5,0,
4,4, 3,3, 2,2, 1,0,]
#生日快乐乐谱
happy_birthday_list = [5,5,6,0,5,0, 8,0,7,0, 5,5,6,0,5,0, 9,0,8,0,
5,5,12,0,10,0, 8,0,7,6, 11,11,10,0,8,0, 9,0,8,0]
#告别乐谱
farewell_list = [5,0,3,5,8,0,0, 6,0,8,0,5,0,0, 5,0,1,2,3,0,2,1,2,0,0,0,
5,0,3,5,8,0,7, 6,0,8,0,5,0,0, 5,0,2,3,4,0,0,1,1,0,0,0,
6,0,8,0,8,0,0, 7,0,6,7,8,0,0, 6,7,8,6,6,5,3,1,2,0,0,0,
5,0,3,5,8,0,7, 6,0,8,0,5,0,0, 5,0,2,3,4,0,0,1,1,0,0,0]
#蜂鸣器播放音乐
def Music_Play(pwm0,Music_list):
duty = 0
i1 = 0
repeat = 0
for i1 in range(len(Music_list)) :
if Music_list[i1] == 0 :
if repeat == 0 :
duty = Music_list[i1 - 1]
repeat = 1
else :
pwm0.duty_u16(0)
time.sleep_ms(50)
duty = Music_list[i1]
repeat = 0
pwm0.duty_u16(255)
pwm0.freq(tone_list[duty - 1])
time.sleep_ms(300)
pwm0.duty_u16(0)

PWM_Music = PWM(Pin(20, Pin.OUT))
PWM_Music.duty_u16(0)

OLED_zh.py文件:

from machine import Pin, SoftSPI
from Drive.ssd1306 import SSD1306_SPI
import time

num0=[...] #'播放列表'字模
num1=[...] #'小星星'字模
num2=[...] #'生日快乐'字模
num3=[...] #'告别'字模
#显示中文函数
def Show_zh(x, y, num, oled):
for li in range(len(num)):
for i in range(16) :
num_binary = bin(num[li][i]).replace('0b', '')
while len(num_binary) < 8:
num_binary = '0' + num_binary
for j in range(8) :
oled.pixel(x+j+li*8,y+i,int(num_binary[j]))#画点
#指定区域刷黑函数
def Rectangle_Blck(x, y, w, h, oled, light):
for j in range(h//8):
for i in range(w):
oled.buffer[(i+x) + (y//8 + j) * 128] = light
oled.show()
#初始化oled屏幕
def OLED_Init():
#定义SPI
spi=SoftSPI(
sck=Pin(4), mosi=Pin(5), miso=Pin(29))
#定义OLEDSPI接口
oled=SSD1306_SPI(
width=128,
height=64,
spi=spi,
res=Pin(6, Pin.OUT),
dc=Pin(7, Pin.OUT),
cs=Pin(8, Pin.OUT)
)
oled.fill(0)#屏幕刷黑
#初始化显示
Show_zh(32, 0, num0, oled)
Show_zh(8, 16, num1, oled)
Show_zh(8, 32, num2, oled)
Show_zh(8, 48, num3, oled)
oled.show() #打开屏幕使屏幕显示
return oled

这里的字模代码就不放了,放在下方附件里了。

  • 实物功能展示图


P20250504-170831.jpg

播放生日快乐


P20250504-170908.jpg

播放告别

  • 项目中遇到的难题和解决方法

由于是采用MicroPython开发,但是MicroPython的固件没有比较合适RP2350B的,于是装了个RP2350A的固件再用。这就导致开发板30以上的引脚无发使用(RP2350B相比于RP2350A就是多一些引脚),板载的按键拨码开关和扩展板的OLED屏幕都接到了30以上的引脚上导致无法使用。于是我外接了一个OLED屏幕,这个外接的OLED屏幕与扩展板上的OLED屏幕相同都是5线spi,都是SSD1306驱动的。唯一的区别就是扩展版上的屏幕分辨率是128x32的,我外接的屏幕分辨率是128x64的。对于按键,我用杜邦线一端接GND一端去触碰设置为上拉输入的GPIO口以此来模拟按键。

  • 对本次活动的心得体会(包括意见或建议)

通过本次基于RP2350B的PWM音乐播放器开发实践,我深刻体会到MicroPython在嵌入式开发中的高效性与局限性。在项目实现过程中,我不仅掌握了PWM音频合成、SPI屏幕驱动等关键技术,更锻炼了在资源受限环境下的问题解决能力。
主要收获:

  1. 掌握了RP2350B的GPIO/PWM配置方法,理解了MicroPython的硬件抽象层特性
  2. 通过字模提取与显示实践,深化了对嵌入式GUI实现原理的理解
  3. 在固件不兼容的情况下,通过外设替代方案培养了工程应变能力

改进建议:

  1. 希望官方能提供更完善的MicroPython固件支持,特别是对RP2350B新增引脚的支持
  2. 希望官方经常开展这种有趣好玩的活动

此次活动让我认识到,在实际工程中往往需要在理想方案和可行方案之间做出权衡。虽然最终采用外接屏幕和模拟按键的方式并非最优解,但这种"解决问题导向"的开发经验尤为珍贵。特别感谢硬禾科技提供的开发平台,希望后续能推出更多支持MicroPython的RP系列开发套件。

软硬件
元器件
MLT-8530
一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于计算机、打印机、报警器、电子玩具、汽车电子设备、电话机、定时器等电子产品中作发声器件。
RP2350B
高性能、安全微控制器,48 GPIO,10×10 QFN 80 pin
SSD1306
单芯片 CMOS OLED/PLED 驱动器
附件下载
Key_Scan.py
按键文件包含消抖函数
main.py
主函数文件
OLED_zh.py
OLED文件包含显示汉字函数
PWM_Text.py
PWM文件包含播放音乐函数
ssd1306.py
ssd1306驱动
团队介绍
波波:电子爱好者
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号