2026年6月突然有了一种想听MP3音乐的冲动连续买了几个简单小模块如YX5300等然后再Arduino IED中搜库搞Arduino的都知道必须有库不然买回来也白搭。这种模块自带耳机插孔和TF卡自己买了32G的TF卡按要求下载了几个MP3歌曲并在文件名前加上001XXX.mp3002YYY.mp3...都是用串口控制波特率9600的程序也简单串口播放源代码需下载YX5300_ESP32库#include YX5300_ESP32.h//MP3头文件 #define RX2 16 #define TX2 17 YX5300_ESP32 mp3;//the mp3 object void setup() { Serial.begin(115200); mp3 YX5300_ESP32(Serial2, RX2, TX2);//用串口2控制波特率9600 mp3.playTrack(1);//第1文件 } void loop() { while (Serial.available()){ char theChar (char)Serial.read(); Serial2.write(theChar); } String strTxd ; if (Serial2.available()){ strTxd Serial2.readString(); } if (strTxd ! ){ Serial.write(strTxd.c_str(), strTxd.length()); switch (strTxd[3]){ case 0x3a://插入TF卡 mp3.playTrack(1);//播放第1文件 break; case 0x3b://拔出TF卡 break; case 0x3c: case 0x3d: case 0x3e://系统不忙 //mp3.playTrack(strTxd[6]); mp3.next(); break; } strTxd.clear(); } }用ESP32下载试试果然发出了声音呵呵不错。玩了几天感觉不爽歌曲名、歌手都显示不出来又在网上搜了VS1053B看到有SPI接口的几个线应该是读TF卡的可以读出文件目录先买回来试试。连接SPI应使用VSPI程序中也是默认这个HSPI不能用同时其他引脚应避开D12、D13脚以前踩了多次坑。VS1053第一次尝试#include UTF8ToGB2312.h//UTF8到GB2312码 #include Adafruit_VS1053.h//VS1053 #include vector//vector对象记录文件名 using namespace std;//使用std命名空间 typedef struct { int nNo;//文件序号 String strFileName;//GB2312的文字 String strOrgName;//UTF8格式的文字 } file;//文件结构 // 全局变量 vectorfile files;//文件名VECTOR int nCur -1;//播放序号 uint8_t volLeft 30;//左声道 uint8_t volRight 30;//右声道 #define CARDCS 5 //SPI chip select #define MP3_DREQ 27//VS1053 Data request, ideally an Interrupt pin #define MP3_XCS 14//VS1053 reset pin (output) #define MP3_XDCS 2//VS1053 chip select pin (output) #define MP3_RESET 4//VS1053 Data/command select pin (output) Adafruit_VS1053_FilePlayer MP3player Adafruit_VS1053_FilePlayer(MP3_RESET, MP3_XCS, MP3_XDCS, MP3_DREQ, CARDCS);//create mp3Player object! void setup() { Serial.begin(115200); if (!SD.begin()) { Serial.println(F(SD failed, or not present)); } printDirectory(SD.open(/), 0); sort(files.begin(), files.end(), [](const file a, const file b) { return a.nNo b.nNo; });//文件名升序 for (int i 0; i files.size(); i ) { Serial.println(files[i].strFileName);//打印文件目录 } // VS1053初始化 if (!MP3player.begin()) { Serial.print(F(Error code: mp3Player isnt begin)); } MP3player.setVolume(volLeft, volRight); } void loop() { if (MP3player.stopped()) { String str /; nCur nCur files.size() - 1 ? nCur : 0; str files[nCur].strOrgName; Serial.println(files[nCur].strFileName); MP3player.playFullFile(str.c_str());//将文件扔给VS1053 } if (Serial.available()) { Serial.println(Serial.read()); } } // File listing helper void printDirectory(File dir, int numTabs) { while (true) { File entry dir.openNextFile(); if (!entry) { break; } for (uint8_t i 0; i numTabs; i) { Serial.print(\t); } file f; f.strOrgName entry.name(); f.strFileName GB.get(entry.name()); f.nNo f.strFileName.toInt(); files.push_back(f); //Serial.print(f.strFileName); if (entry.isDirectory()) { Serial.println(/); printDirectory(entry, numTabs 1); } else { // files have sizes, directories do not } entry.close(); } }连接好ESP32和VS1053下载程序运行哈哈不错文件名全读出来了。文件也能播放但按“发送”键屏幕无反应应该发什么串口回什么。搜了一下MP3player.playFullFile();是阻塞式播放程序运行到此就会在函数内运行直至函数运行完即歌曲播放完网上也有解决办法即在初始化时MP3player.useInterrupt(VS1053_FILEPLAYER_PIN_INT);在循环里不要用MP3player.playFullFile();要用MP3player.startPlayingFile();看了好多文章都是这样说的于是就改代码改了代码就不断重启。到网上查rst:0x8有人说是溢出了有人说是中断执行太长我认为也是中断执行时间过长改了很多次包括改SPI的速度、默认一次拷贝32个字节换是16、甚至改成1个还是不行换头文件等等也不行看了不是代码执行速度的问题应该是代码以前不是针对ESP32 DEVKIT-V1开发的或是咱们使用的问题。最后把Adafruit_VS1053.cpp文件的相关代码逐一拷贝到源文件里测试试了一天终于让我发现秘密了。先用startPlayingFile(String strName)函数做打开文件的准备工作包括打开文件、定位到MP3数据的起始位置保证MP3_DREQ引脚变成高电平。关键代码while (playingResume digitalRead(MP3_DREQ)) {feedBuffer();//从文件读出数据送到播放缓冲区}这个循环不可能一直在循环数据拷到1024或1056左右时跟踪过MP3_DREQ引脚就变成低电平了则退出循环了速度很快我们的其他代码就能继续执行了。数据用完了MP3_DREQ引脚就变成高低电平了同样再进入循环...最终非阻塞式播放代码#include UTF8ToGB2312.h//UTF8到GB2312头文件 #include Adafruit_VS1053.h//VS1053必须头文件 #include vector//vector对象记录文件名 using namespace std;//使用std命名空间 typedef struct { int nNo; String strFileName; String strOrgName; } file; // 全局变量 vectorfile files;//记录文件容器 int nCur -1;//播放序号 int nSize 0;//歌曲总数 File mp3File;//当前播放的MP3文件 uint8_t mp3buffer[32] {0};//数据缓冲区 uint8_t nLoopMode 0;//正向播放0/逆序播放1/随机播放2/单曲3/停止4 bool bPlay false;//正在播放 bool bPlayResume false;//播放/暂停 bool bMuted false;//播放/暂停 uint8_t volLeft 30;//左声道 uint8_t volRight 30;//右声道 #define CARDCS 5 //SPI chip select #define MP3_DREQ 27//VS1053 Data request, ideally an Interrupt pin #define MP3_XCS 14//VS1053 reset pin (output) #define MP3_XDCS 2//VS1053 chip select pin (output) #define MP3_RESET 4//VS1053 Data/command select pin (output) Adafruit_VS1053_FilePlayer MP3player Adafruit_VS1053_FilePlayer(MP3_RESET, MP3_XCS, MP3_XDCS, MP3_DREQ, CARDCS);//create mp3Player object! void setup() { Serial.begin(115200); if (!SD.begin()) {//TF文件初始化 Serial.println(F(SD failed, or not present)); } printDirectory(SD.open(/), 0);//储存文件目录 sort(files.begin(), files.end(), [](const file a, const file b) { return a.nNo b.nNo; });//文件名升序 nSize files.size(); for (int i 0; i nSize; i ) { Serial.println(files[i].strFileName);//打印文件目录 } // VS1053初始化 if (!MP3player.begin()) { Serial.print(F(Error code: mp3Player isnt begin)); } MP3player.setVolume(volLeft, volRight);//初始化音量 } void loop() { //播放完毕自动循环的判断 if (!bPlay) { switch (nLoopMode){ case 0: nCur nCur nSize - 1 ? nCur : 0; break;//正序循环 case 1: nCur nCur 1 ? nSize - 1 : -- nCur; break;//逆序循环 case 2: nCur random(nSize); break;//随机循环 case 3: break;//单曲循环 } if (nLoopMode 4){ Serial.println(files[nCur].strFileName); startPlayingFile(files[nCur].strOrgName);//打开文件的准备工作 } } //关键代码 while (bPlayResume digitalRead(MP3_DREQ)) { feedBuffer();//从文件读出数据送到播放缓冲区 } //播放时的控制 if (Serial.available()) { char c Serial.read(); switch (c) { case : if (volLeft 0) { volLeft 0; } else { -- volLeft; -- volRight; MP3player.setVolume(volLeft, volRight);//加音量 Serial.println(volLeft); } break; case -: if (volLeft 255) { volLeft 255; } else { volLeft; volRight; MP3player.setVolume(volLeft, volRight);//加音量 Serial.println(volLeft); } break; case p: bPlayResume !bPlayResume;//播放\暂停 break; case a: nCur nCur nSize - 1 ? nCur : 0; Serial.println(files[nCur].strFileName); startPlayingFile(files[nCur].strOrgName);//下一首 break; case b: nCur nCur 1 ? nSize - 1 : -- nCur; Serial.println(files[nCur].strFileName); startPlayingFile(files[nCur].strOrgName);//上一首 break; case c: MP3player.setPlaySpeed(2);//快一倍 break; case d: MP3player.setPlaySpeed(1);//正常速度 break; case m: bMuted !bMuted; bMuted ? MP3player.setVolume(255, 255) : MP3player.setVolume(volLeft, volRight);//选静音 break; case n: nLoopMode nLoopMode 4 ? 0 : nLoopMode;//选循环模式 Serial.println(nLoopMode); break; } } } //打开文件的准备工作 boolean startPlayingFile(String strName) { String str /; str strName; mp3File SD.open(str); if (!mp3File) { return false; } if (MP3player.isMP3File(str.c_str())) { mp3File.seek(MP3player.mp3_ID3Jumper(mp3File)); } bPlay true; bPlayResume true; // wait till its dreq pin for high while (!digitalRead(MP3_DREQ)) { delay(1); #if defined(ESP8266) ESP.wdtFeed(); #endif } return true; } //从文件读出数据送到播放缓冲区 void feedBuffer(void) { if (!bPlay || (!mp3File) || (!digitalRead(MP3_DREQ))) { return; // paused or stopped } // Feed the hungry buffer! :) while (digitalRead(MP3_DREQ)) {//9344 // Read some audio data from the SD card file int bytesread mp3File.read(mp3buffer, 32); if (bytesread 0) { // wrap it up! bPlay false; bPlayResume false; mp3File.close(); break; } MP3player.playData(mp3buffer, bytesread); } } // File listing helper void printDirectory(File dir, int numTabs) { while (true) { File entry dir.openNextFile(); if (!entry) { break; } for (uint8_t i 0; i numTabs; i) { Serial.print(\t); } file f; f.strOrgName entry.name(); f.strFileName GB.get(entry.name()); f.nNo f.strFileName.toInt(); files.push_back(f); if (entry.isDirectory()) { Serial.println(/); printDirectory(entry, numTabs 1); } else { // files have sizes, directories do not } entry.close(); } }这下完美搞定VS1053非阻塞式播放了......