草庐IT

ESP32基于Arduino框架,SD卡+MAX98357模块+MP3播放器

perseverance52 2023-04-03 原文

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-audioi2shttps://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

有关ESP32基于Arduino框架,SD卡+MAX98357模块+MP3播放器的更多相关文章

  1. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  2. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

  3. ruby - 如何以编程方式将 mp3 转换为 itunes 可播放的 aac/m4a 文件? - 2

    我一直在寻找一种以编程方式或通过命令行将mp3转换为aac的方法,但没有成功。理想情况下,我有一段代码可以从我的Rails应用程序中调用,将mp3转换为aac。我安装了ffmpeg和libfaac,并能够使用以下命令创建aac文件:ffmpeg-itest.mp3-acodeclibfaac-ab163840dest.aac当我将输出文件的名称更改为dest.m4a时,它无法在iTunes中播放。谢谢! 最佳答案 FFmpeg提供AAC编码功能(如果您已编译它们)。如果您使用的是Windows,则可以从here获取完整的二进制文件。

  4. STM32的HAL和LL库区别和性能对比 - 2

    LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L

  5. ruby - 如何播放 mp3 文件? - 2

    我如何用ruby​​编写一个脚本,当从命令行执行时播放mp3文件(背景音乐)?我试过了run="mplayer#{"/Users/bhushan/resume/m.mp3"}-aosdl-vox11-framedrop-cache16384-cache-min20/100"system(run)但它也不起作用,以上是播放器特定的。如果用户没有安装mplayer怎么办。有没有更好的办法? 最佳答案 我一般都是这样pid=fork{exec'mpg123','-q',file} 关于ruby

  6. ESP32学习入门:WiFi连接网络 - 2

    目录一、ESP32简单介绍二、ESP32Wi-Fi模块介绍三、ESP32Wi-Fi编程模型四、ESP32Wi-Fi事件处理流程 五、ESP32Wi-Fi开发环境六、ESP32Wi-Fi具体代码七、ESP32Wi-Fi代码解读6.1主程序app_main7.2自定义代码wifi_init_sta()八、ESP32Wi-Fi连接验证8.1测试方法8.2服务器模拟工具sscom58.3测试代码8.4测试结果前言为了开发一款亚马逊物联网产品,开始入手ESP32模块。为了能够记录自己的学习过程,特记录如下操作过程。一、ESP32简单介绍ESP32是一套Wi-Fi(2.4GHz)和蓝牙(4.2)双模解决方

  7. Spring Security 6.0系列【32】授权服务器篇之默认过滤器 - 2

    有道无术,术尚可求,有术无道,止于术。本系列SpringBoot版本3.0.4本系列SpringSecurity版本6.0.2本系列SpringAuthorizationServer版本1.0.2源码地址:https://gitee.com/pearl-organization/study-spring-security-demo文章目录前言1.OAuth2AuthorizationServerMetadataEndpointFilter2.OAuth2AuthorizationEndpointFilter3.OidcProviderConfigurationEndpointFilter4.N

  8. ruby - 需要帮助改进 Ruby DSL 以控制 Arduino 控制的饮料分配器(bar monkey) - 2

    我正在用Ruby编写DSL来控制我正在处理的Arduino项目;巴尔迪诺。这是一只酒吧猴子,将由软件控制来提供饮料。Arduino通过串行端口接收命令,告诉Arduino要打开什么泵以及打开多长时间。它目前正在读取一个食谱(见下文)并将其打印出来。串行通信的代码以及我在下面提到的其他一些想法仍然需要改进。这是我的第一个DSL,我正在处理之前的示例,所以它的边缘非常粗糙。任何批评、代码改进(是否有任何关于RubyDSL最佳实践或习语的良好引用?)或任何一般性评论。我目前有DSL的粗略草稿,因此饮料配方如下所示(Githublink):desc"Simpleglassofwater"rec

  9. ruby - 摘要::CRC32 与 Zlib - 2

    在我的代码中,我需要使用各种算法(包括CRC32)对文件进行哈希处理。因为我还在Digest系列中使用其他加密哈希函数,所以我认为为它们维护一个一致的接口(interface)会很好。为了记录,我确实找到了digest-crc,一颗完全符合我要求的gem。问题是,Zlib是标准库的一部分,并且有一个我想重用的CRC32工作实现。此外,它是用C编写的,因此它应该提供与digest-crc相关的卓越性能,后者是纯ruby​​实现。实现Digest::CRC32一开始看起来非常简单:%w(digestzlib).each{|f|requiref}classDigest::CRC32一切正常:

  10. ruby - 安装gem : Couldn't reserve space for cygwin's heap, Win32错误487错误 - 2

    我正在尝试在我的机器上安装win32-apigem,但在构建native扩展时我遇到了一些问题:$geminstallwin32-api--no-ri--rdocTemporarilyenhancingPATHtoincludeDevKit...Buildingnativeextensions.Thiscouldtakeawhile...C:\Programs\dev_kit\bin\make.exe:***Couldn'treservespaceforcygwin'sheap,Win32error0ERROR:Errorinstallingwin32-api:ERROR:Failed

随机推荐