基于RP2350B的PWM音乐播放器
该项目使用了RP2350B,实现了制作一个音乐播放器的设计,它的主要功能为:1. 支持 MP3 和 WAV 格式的音频文件播放。 2. 自动扫描 SD 卡或者Flash的 music 目录,生成播放列表。 3. 通过按键控制播放、暂停、下一曲等功能。 4. 在 OLED 显示屏上显示当前播放的曲目信息。 5. 支持播放音乐音阶。
标签
嵌入式系统
开发板
CircuitPython
SSD1306
RP2350B
keman
更新2025-07-11
4

这是一款基于Adafruit CircuitPythonRP2350B开发板的音乐播放器。它可以播放存储在SD上或者flashmusic目录下MP3WAV音频文件,并通过OLED显示屏显示当前播放的曲目信息。


1、项目功能介绍

1.支持MP3WAV格式的音频文件播放。

2.动扫描SD或者Flashmusic目录,生成播放列表

3.通过按键控制播放、暂停、下一曲等功能。

4.OLED显示屏上显示当前播放的曲目信息。

5.支持播放音乐音阶。

 2、设计思路

这个项目采用了模块化、可扩展的设计思路,充分利用了 CircuitPython 的优势实现

  • 存储介质的选择:

支持两种存储介质:SD卡和Flash。用户可以根据实际需求选择合适的存储方式。 通过抽象出 MusicPlayer 类,将存储方式的差异封装起来,使得上层代码不需要关心具体的存储位置。

  • 音频文件的播放:

使用 Adafruit CircuitPython 提供的 audiocore  audiopwmio 模块,实现了对 WAV 和 MP3 音频文件的播放。 通过 play_wav_music  play_mp3_music 函数,将不同格式音频文件的播放逻辑抽象出来,方便后续扩展。

  • 用户交互:

通过按键输入检测,实现了播放控制功能,如启动/暂停播放、播放下一曲等。 使用 OLED 显示屏显示当前播放的曲目信息,并实现了文本滚动效果,增强了用户体验。

  • 模块化设计:

将不同功能模块拆分成单独的文件,如按键输入检测、SD卡挂载、音乐播放器逻辑等,提高了代码的可读性和可维护性。 通过组合使用这些模块,实现了音乐播放器的整体功能。

  • 扩展性:

设计时考虑了扩展性,如新增 歌词显示等。通过抽象出 MusicPlayer 类,可以方便地添加新的存储介质支持,或者增加新的播放功能。



3、硬件要求&方案框图

1. RP2350B核心板+综合训练扩展板

2. SD卡模块非必须


image.png 

4、软件流程图

image.png

5、软件依赖

1. Adafruit CircuitPython

2. Adafruit SSD1306 OLED驱动库

3. Adafruit audiocoreaudiopwmio音频播放库

 

6、使用说明

SD卡存储模式:

确保SD卡已插入开发板,并且SD卡上有MP3WAV格式的音乐文件。

运行main()函数,player = MusicPlayer(music_dir="/sd/")取消注释。

Flash存储模式:

确保MP3WAV格式的音乐文件存放在设备的Flash文件系统的/music/目录下。

运行main()函数,player = MusicPlayer()取消注释。

在两种模式下,播放器的基本功能都是一样的:

 

按键1:停止播放

按键2:开始/继续播放

按键3:播放下一曲

按键4:播放音乐音阶

OLED显示屏会显示当前播放的曲目信息,并在播放过程中滚动显示



 7、主要代码片段及说明

1.按键输入检测(`get_key_info.py`)

该文件实现了按键输入的检测功能。它使用`analogio`模块读取模拟引脚的电压值,根据不同电压范围判断按键ID

 KEY_PRVENT_COUNT = 5

def get_key_value():
count = 0
sum_value = 0
while (count < KEY_PRVENT_COUNT):
sum_value += g_detect_pin.value
count += 1
time.sleep(0.005)

avg_value = sum_value /count
return avg_value

 

2. SD卡挂载(`mount_sd.py`)

该文件实现了SD卡的挂载功能,使用`storage``adafruit_sdcard`库完成。

 def my_mount_sd():
sd_spi = bitbangio.SPI(board.GP9, MOSI=board.GP8, MISO=board.GP10)
sd_cs = DigitalInOut(board.GP7) # any pin!

sdcard = adafruit_sdcard.SDCard(sd_spi, sd_cs)

vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")

 

3.音乐播放器主逻辑(`my_music_play.py`)

该文件实现了音乐播放器的主要逻辑,包括播放列表的生成、音乐播放、OLED显示等功能。

 def play_loop(self):
# 显示歌曲名
if self.old_index != self.current_index:
self.display_string = self.get_curr_mane()
oled_display_ufont.my_display_text(self.display_string, 0, 8, 1)
self.display_string = oled_display_ufont.rotate_string(self.display_string, -1)
time.sleep(1)
elif self.is_playing:
pass
oled_display_ufont.my_display_text(self.display_string, 0, 8, 1)
self.display_string = oled_display_ufont.rotate_string(self.display_string, -1)

4. OLED显示(`oled_display_ufont.py`)

该文件实现了OLED显示屏的驱动和文本显示功能,使用了`adafruit_ssd1306`库和自定义的bitmap字体。

 def my_display_text(string: str = "", x: int = 0, y: int = 0, color: int = 0xFFFF,
font = font, display = oled,
half_char: bool = True, auto_wrap: bool = False, line_spacing: int = 0):
display.fill(0)
font_size = font.font_size
initial_x = x
for char in range(len(string)):
if auto_wrap and ((x + font_size // 2 > display.width and ord(string[char]) < 128 and half_char) or
(x + font_size > display.width and (not half_char or ord(string[char]) > 128))):
y += font_size + line_spacing
x = initial_x

# 对控制字符的处理
if string[char] == '\n':
y += font_size + line_spacing
x = initial_x
continue
elif string[char] == '\t':
x = ((x // font_size) + 1) * font_size + initial_x % font_size
continue
elif ord(string[char]) < 16:
continue

# 超过范围的字符不会显示*
if x > display.width or y > display.height:
continue
str_bit = font.get_bitmap(string[char])
my_draw_char_2(oled, str_bit, x, y, color)
x += font_size

display.show()

def rotate_string(s, n):
"""
将字符串 s 循环向右移动 n 个字符
"""
n = n % len(s) # 确保 n 在字符串长度范围内
return s[-n:] + s[:-n]

 

5.音频播放(`play_wav_mp3.py``play_musical_scale.py`)

这两个文件实现了WAVMP3音频文件的播放,以及音乐音阶的播放。

 def play_wav_music(path, wait=True):
global g_muisc_file
while g_audio_handle.playing:
g_audio_handle.stop()
time.sleep(1)

g_muisc_file = open(path, "rb")
wav = audiocore.WaveFile(g_muisc_file)

print("playing: ", path)
g_audio_handle.play(wav)

if (wait == True):
while g_audio_handle.playing:
pass
print("stopped")

def play_mp3_music(path, wait=True):
global g_muisc_file
while g_audio_handle.playing:
g_audio_handle.stop()
time.sleep(1)

try:
g_muisc_file = open(path, "rb")
mp3 = audiomp3.MP3Decoder(g_muisc_file)
except OSError:
print("错误: 文件格式不支持或文件损坏")
return

print("playing: ", path)
g_audio_handle.play(mp3)

if (wait == True):
while g_audio_handle.playing:
pass
print("stopped")
def play_do_to_si(pwm):
# Play double-buffered
sample = audiocore.RawSample(sine_wave, single_buffer=False)
pwm.play(sample, loop=True)
time.sleep(play_duration)

# changing the wave takes effect almost immediately
musical_scale = [261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88]
for m in musical_scale:
for i in range(length):
sine_wave[i] = int(math.sin(math.pi * 2 * i / (length * m/440.0)) * (2 ** 15))
time.sleep(play_duration)
pwm.stop()

6.文件说明

- `get_key_info.py`:实现按键输入检测的功能。

- `mount_sd.py`:实现SD卡挂载的功能。

- `my_music_pla.py`:音乐播放器的主要逻辑实现。

- `oled_display_ufont.py`: OLED显示屏的驱动和文本显示功能。

- `play_musical_scale.py`:播放音乐音阶的功能实现。

- `play_wav_mp3.py`:音频文件播放的功能实现。

- `code.py`:程序入口文件,运行该文件可启动音乐播放器。

 

8、注意事项

1.确保SD卡上或者flashMP3WAV文件格式正确,否则可能无法正常播放。

2.按键输入检测是基于模拟量输入的,可能需要根据实际硬件进行调整。

3. OLED显示屏的驱动和字体文件需要事先准备好。

4.音乐音阶的播放是使用合成的方式实现的,可能与真实音乐有所不同。

5、基于“adafruit-circuitpython-solderparty_rp2350_stamp_xl-en_US-10.0.0-alpha.4.uf2”运行。

6、播放的MP3文件最好是恒定比特率CBR(Constant Bit-Rate)的。

9、心得体会

  1. 模拟按键的精准识别:通过电压范围判断按键ID的方案,需特别注意;添加多次采样取平均,有效抑制信号抖动;
  2. SD卡挂载时:设计目录扫描缓存机制减少IO操作;
  3. MP3播放时增加文件异常处理机制,保证播放流畅。
  4. SD和显示屏都使用了软SPI实现,在播放SD卡上文件时,程序执行效率较差,有待改进。


10、未来优化方向

  1. 支持歌词同步显示(LRC格式解析);
  2. 添加EQ音效处理模块;
  3. 增加播放状态图标(▶/❚❚)提供明确操作反馈;


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