ESP32基于Arduino框架,SD卡+MAX98357模块+MP3播放器
- 🎬原创作者的制作教程讲解以及源码:
35 ESP32之简单的完整功能SD卡MP3播放器的制作讲解(ESP32-audioI2S库介绍)- 基于Arduino
链接:https://pan.baidu.com/s/1IxmHo1M8TLo13XMwSbZrfQ?pwd=2hgy
提取码:2hgy
- 📺OLED播放效果演示:
由于还没有购买
MAX98357
,不知道音质怎么样。
-
📌MAX98357 I2S 音频放大器模块
-
📌MAX98357 I2S 音频放大器模块 无滤波D类放大器资料:
https://pan.baidu.com/s/1Bn6zpobgbs93CyBALzPxqg
提取码: j9y9
🌼SD卡接线说明
- ✨使用VSPI接口接线
// #define SD_CS 5
// #define SPI_MOSI 23
// #define SPI_MISO 19
// #define SPI_SCK 18
🌷I2C OLED屏幕接线
原创代码定义的是4,15需要注意,可以根据自己的需求自行修改
OLED SCL-----> 21
OLED SDA ----> 22
📚所需库
- 📑编译信息参考:
使用 2.0.0 版本的库 Wire 在文件夹: C:\Users\Administrator\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\libraries\Wire
使用 2.0.0 版本的库 SPI 在文件夹: C:\Users\Administrator\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\libraries\SPI
使用 2.33.15 版本的库 U8g2 在文件夹: C:\Users\Administrator\Documents\Arduino\libraries\U8g2
使用 2.2.0 版本的库 SdFat 在文件夹: C:\Users\Administrator\Documents\Arduino\libraries\SdFat
使用 2.2.1 版本的库 RBD_Button 在文件夹: C:\Users\Administrator\Documents\Arduino\libraries\RBD_Button
使用 1.4.2 版本的库 RBD_Timer 在文件夹: C:\Users\Administrator\Documents\Arduino\libraries\RBD_Timer
使用 2.0.0 版本的库 ESP32-audioI2S 在文件夹: C:\Users\Administrator\Documents\Arduino\libraries\ESP32-audioI2S
使用 2.0.0 版本的库 WiFi 在文件夹: C:\Users\Administrator\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\libraries\WiFi
使用 2.0.0 版本的库 WiFiClientSecure 在文件夹: C:\Users\Administrator\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.5\libraries\WiFiClientSecure
"C:\\Users\\Administrator\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\xtensa-esp32-elf-gcc\\gcc8_4_0-esp-2021r2-patch3/bin/xtensa-esp32-elf-size" -A "d:\\arduino\\MyHexDir/real_player.ino.elf"
项目使用了 1084461 字节,占用了 (82%) 程序存储空间。最大为 1310720 字节。
全局变量使用了42272字节,(12%)的动态内存,余留285408字节局部变量。最大为327680字节。
U8g2
库
RBD_Button
库
RBD_Timer
库
SdFat
库
esp32-audioi2s
需要自己导入到Arduino IDE库当中
esp32-audioi2s
:https://github.com/schreibfaul1/esp32-audioi2s
⛳注意事项
- 需要按照原作者那样修改
ESP32-audioI2S
库代码。
Audio.h
头文件
- 源文件
Audio.cpp
- ⚡程序烧录后,需要初始化SD卡成功后,屏幕才能显,如果没有找到SD或识别到SD卡,则串口会打印
error
。(具体看代码)
📝程序代码
#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include <U8g2lib.h>//点击这里会自动打开管理库页面: http://librarymanager/All#U8g2
#include "SdFat.h"//点击这里会自动打开管理库页面: http://librarymanager/All#SdFat
#include <iostream>
#include <RBD_Button.h>//点击这里会自动打开管理库页面: http://librarymanager/All#RBD_Button
#include "Audio.h"
#include "FileEnumerator.h"
using namespace std;
//#define SCL 17
//#define SDA 16
// #define SD_CS 5
// #define SPI_MOSI 23
// #define SPI_MISO 19
// #define SPI_SCK 18
#define V_SUB_PIN 32 // v-
#define V_ADD_PIN 33 // v+
#define STOP_PIN 16 //stop
#define PREV_PIN 17 //prev
#define NEXT_PIN 15 //next
#define I2S_DOUT 25
#define I2S_BCLK 26
#define I2S_LRC 27
//U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // 没有重置显示的所有板
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // 1.3寸,默认引脚SCL:22,SDA:21
//U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE, /* clock=*/SCL, /* data=*/SDA); // 1.3寸,指定引脚
RBD::Button vsub_button(V_SUB_PIN, INPUT_PULLUP);
RBD::Button vadd_button(V_ADD_PIN, INPUT_PULLUP);
RBD::Button stop_button(STOP_PIN, INPUT_PULLUP);
RBD::Button prev_button(PREV_PIN, INPUT_PULLUP);
RBD::Button next_button(NEXT_PIN, INPUT_PULLUP);
int volume = 10; //音量
Audio audio;
FileEnumerator fe;
char buf[128];
int utf8CutLen(const String &src, int utf8Len) {
int utf8LenCnt = 0;
int srcIdx = 0;
int srcLen = src.length();
int cutLen = 0;
unsigned char tmp;
while (utf8LenCnt < utf8Len && srcIdx < srcLen) {
tmp = (unsigned char)src[srcIdx];
if (tmp >= 252)
cutLen = 6;
else if (tmp >= 248)
cutLen = 5;
else if (tmp >= 240)
cutLen = 4;
else if (tmp >= 224)
cutLen = 3;
else if (tmp >= 192)
cutLen = 2;
else if (tmp >= 65 && tmp <=90)
cutLen = 1;
else
cutLen = 1;
srcIdx += cutLen;
++utf8LenCnt;
}
return srcIdx;
}
void UpdateOLED()
{
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_wqy14_t_gb2312b); //换成中文字体
string str = "音量: " + std::to_string(volume);
if(audio.isRunning())
str+=" 播放中...";
else
str+=" 未播放...";
u8g2.drawUTF8(0, 15, str.c_str());
String tmp = fe.CurrentFileName();
int len = tmp.length();
int len1 = utf8CutLen(tmp, 10);
if(len>len1)
{
u8g2.drawUTF8(0, 40, tmp.substring(0, len1).c_str());
u8g2.drawUTF8(0, 55, tmp.substring(len1).c_str());
}
else
u8g2.drawUTF8(0, 40, fe.CurrentFileName());
u8g2.sendBuffer();
}
void PlayPrev()
{
auto filename = fe.Prev();
if(!filename)
return;
audio.stopSong();
delay(3);
audio.connecttoFS(SD, filename);
Serial.print("play: ");
Serial.println(filename);
}
void PlayNext()
{
auto filename = fe.Next();
if(!filename)
return;
audio.stopSong();
delay(3);
audio.connecttoFS(SD, filename);
Serial.print("play: ");
Serial.println(filename);
}
void setup() {
Serial.begin(115200);
delay(3000);
if(!SD.begin(SdSpiConfig(5, DEDICATED_SPI, 18000000)))
//if(!SD.begin(5, 18000000))
{
Serial.println("error");
return;
}
FsFile dir;
FsFile file;
fe.Init();
file.remove("/index.idx");
if(!file.open("/index.idx", O_RDWR|O_CREAT))
{
Serial.println("crate file error");
return;
}
// Open root directory
if (!dir.open("/")){
Serial.println("dir.open failed");
return;
}
while (file.openNext(&dir, O_RDONLY)) {
memset(buf, 0, 128);
file.getName(buf, 128);
fe.Add(buf);
file.close();
}
dir.close();
fe.Flush();
Wire.begin(SDA, SCL);
u8g2.setBusClock(800000); //设置时钟
u8g2.begin(); //初始化
u8g2.enableUTF8Print(); //允许UTF8
vsub_button.setDebounceTimeout(20);
vadd_button.setDebounceTimeout(20);
stop_button.setDebounceTimeout(20);
prev_button.setDebounceTimeout(20);
next_button.setDebounceTimeout(20);
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
audio.setVolume(10); // 0...21
PlayNext();
UpdateOLED();
}
void audio_eof_mp3(const char *info)
{
PlayNext();
UpdateOLED();
}
void audio_id3data(const char *info){
UpdateOLED();
}
void loop() {
if(vsub_button.onPressed())
{
// V-
volume --;
if(volume < 0)
volume = 0;
audio.setVolume(volume);
UpdateOLED();
}
if(vadd_button.onPressed())
{
// V+
volume ++;
if(volume > 21)
volume = 21;
audio.setVolume(volume);
UpdateOLED();
}
if(stop_button.onPressed())
{
//暂停,播放
audio.pauseResume();
UpdateOLED();
}
if(prev_button.onPressed())
{
PlayPrev();
UpdateOLED();
}
if(next_button.onPressed())
{
PlayNext();
UpdateOLED();
}
audio.loop();
}
📚工程代码
链接:https://pan.baidu.com/s/1XX_88x4WfDoW2DHvmN3gYA
提取码:k72b