- 项目介绍
基于RP2350B实现PWM音乐播放器的项目主要是:使用了RP2350B核心板、MicroPython语言,实现了PWM音乐播放器的设计,它的主要功能为:根据不同的按键被按下,用PWM驱动蜂鸣器播放对应的音乐,并且在OLED屏幕上显示对应音乐的中文名。可以播放的音乐有《小星星》《生日快乐》《告别》都是C调歌曲
- 硬件介绍
这里硬禾科技提供的硬件为:RP2350B核心板、基于小脚丫FPGA的综合技能训练板。
本次活动用到RP2350B核心板引出的引脚和小脚丫FPGA的综合技能训练板是兼容的可以直接使用。
小脚丫FPGA综合训练板
由于MicroPython固件的原因扩展板上的OLED屏幕无法使用,于是我外接了一个OLED屏幕,这个外接的OLED屏幕与扩展板上的OLED屏幕相同都是5线spi,都是SSD1306驱动的。唯一的区别就是扩展版上的屏幕分辨率是128x32的,我外接的屏幕分辨率是128x64的。具体如下图:
硬件图
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显示汉字采用汉字字模的方式显示,因为显示的汉字个数不多采用字模的方式很方便。并且在歌曲列表前显示一个光标'>'来指示正在播放的音乐。
程序流程图
- 关键代码介绍
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))
#定义OLED的SPI接口
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
这里的字模代码就不放了,放在下方附件里了。
- 实物功能展示图
播放生日快乐
播放告别
- 项目中遇到的难题和解决方法
由于是采用MicroPython开发,但是MicroPython的固件没有比较合适RP2350B的,于是装了个RP2350A的固件再用。这就导致开发板30以上的引脚无发使用(RP2350B相比于RP2350A就是多一些引脚),板载的按键拨码开关和扩展板的OLED屏幕都接到了30以上的引脚上导致无法使用。于是我外接了一个OLED屏幕,这个外接的OLED屏幕与扩展板上的OLED屏幕相同都是5线spi,都是SSD1306驱动的。唯一的区别就是扩展版上的屏幕分辨率是128x32的,我外接的屏幕分辨率是128x64的。对于按键,我用杜邦线一端接GND一端去触碰设置为上拉输入的GPIO口以此来模拟按键。
- 对本次活动的心得体会(包括意见或建议)
通过本次基于RP2350B的PWM音乐播放器开发实践,我深刻体会到MicroPython在嵌入式开发中的高效性与局限性。在项目实现过程中,我不仅掌握了PWM音频合成、SPI屏幕驱动等关键技术,更锻炼了在资源受限环境下的问题解决能力。
主要收获:
- 掌握了RP2350B的GPIO/PWM配置方法,理解了MicroPython的硬件抽象层特性
- 通过字模提取与显示实践,深化了对嵌入式GUI实现原理的理解
- 在固件不兼容的情况下,通过外设替代方案培养了工程应变能力
改进建议:
- 希望官方能提供更完善的MicroPython固件支持,特别是对RP2350B新增引脚的支持
- 希望官方经常开展这种有趣好玩的活动
此次活动让我认识到,在实际工程中往往需要在理想方案和可行方案之间做出权衡。虽然最终采用外接屏幕和模拟按键的方式并非最优解,但这种"解决问题导向"的开发经验尤为珍贵。特别感谢硬禾科技提供的开发平台,希望后续能推出更多支持MicroPython的RP系列开发套件。