在成功实现播放MP3音乐文件的基础上,加入扫描SD卡的处理,实现自动连续播放的处理效果。实验依旧使用之前的线路。

预先在SD卡中准备多个mp3音乐。
程序代码如下:
#include <SPI.h>
#include <SD.h>
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
#include <vector>
// SD卡模块的SPI引脚
#define SCK_PIN 4
#define MISO_PIN 7
#define MOSI_PIN 6
#define CS_PIN 10
// 连接到MAX98357的I2S引脚
#define BCK_PIN 5 // 位时钟 (MAX98357的BCK)
#define WS_PIN 3 // 字时钟/左右声道选择 (MAX98357的LRC)
#define DATA_PIN 2 // 数据输出 (MAX98357的DIN)
I2SStream i2s; // final output of decoded stream
EncodedAudioStream decoder(&i2s, new MP3DecoderHelix()); // Decoding stream
StreamCopy copier;
File audioFile;
// --- 播放列表(按顺序播放)---
// 创建字符串向量
std::vector<String> playlist;
int playlistSize = 0; // sizeof(playlist) / sizeof(playlist[0]);
int currentIndex = 0; // 当前播放到第几首
bool isPlaying = false;
// ========== 列出SD卡中的MP3文件 ==========
void lisMp3Files() {
Serial.println("\nSD卡中的MP3文件:");
File root = SD.open("/");
if (!root) {
Serial.println("无法打开根目录");
return;
}
File file = root.openNextFile();
int count = 0;
while (file) {
if (!file.isDirectory()) {
String name = file.name();
name.toLowerCase();
if (name.endsWith(".mp3")) {
Serial.printf(" - %s (%llu bytes)\n", name.c_str(), file.size());
playlist.push_back(String("/") + name);
count++;
}
}
file = root.openNextFile();
}
if (count == 0) {
Serial.println(" 没有找到MP3文件");
playlistSize = 0;
} else {
playlistSize = playlist.size();
}
root.close();
}
void setup(){
Serial.begin(115200);
AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);
SPI.begin(SCK_PIN, MISO_PIN, MOSI_PIN, CS_PIN);
// 初始化 SD 卡
if (!SD.begin(CS_PIN)) {
Serial.println("SD 卡初始化失败,请检查接线!");
return;
}
Serial.println("SD 卡初始化成功");
lisMp3Files();
// setup i2s
auto config = i2s.defaultConfig(TX_MODE);
config.pin_bck = BCK_PIN; // MAX98357 的 BCLK
config.pin_ws = WS_PIN; // MAX98357 的 LRC
config.pin_data = DATA_PIN; // MAX98357 的 DIN
i2s.begin(config);
// setup I2S based on sampling rate provided by decoder
decoder.begin();
// 开始播放第一首
playNext();
}
void loop() {
if (playlistSize == 0) {
return;
}
if (!isPlaying) return;
// 持续复制音频数据
if (!copier.copy()) {
// 当前文件播放结束,切换到下一首
Serial.println("当前曲目播放结束");
audioFile.close();
currentIndex++;
if (currentIndex < playlistSize) {
playNext(); // 播放下一首
} else {
Serial.println("所有曲目播放完毕");
isPlaying = false;
}
}
}
// 播放下一首(或指定索引)
void playNext() {
if (currentIndex >= playlistSize) {
Serial.println("播放列表已到头");
return;
}
String fileName = playlist[currentIndex];
Serial.print("正在播放: ");
Serial.println(fileName);
audioFile = SD.open(fileName);
if (!audioFile) {
Serial.println("文件打开失败,跳过");
currentIndex++;
playNext(); // 递归尝试下一首
return;
}
// 重新配置解码器(重要:每次换文件都要重新关联)
decoder.begin();
// 开始复制数据
copier.begin(decoder, audioFile);
isPlaying = true;
}代码中使用了vector,方便动态追加文件。
我要赚赏金
