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

news2024/11/20 15:22:51

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/156729.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

黑产系列02-黑产画像

黑产无利不起早&#xff0c;在利益的驱动下黑产几乎是屡禁不止&#xff0c;作为风控从业人员我们需要全方位的了解黑产&#xff0c;了解我们的对手&#xff0c;才能知己知彼&#xff0c;接下来我将结合我多年风控经验以及查阅的相关的资源&#xff0c;全方位介绍下黑产以及他们…

matplot绘制动图

import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation import numpy as np plt.rcParams[axes.unicode_minus] False plt.rcParams[font.sans-serif] SimHei# 准备数据 x np.linspace(0,3*np.pi,100) y1 np.sin(x) y2 np.cos(x)#创建画布和子图 …

Python用yield from 实现异步协程爬虫

文章目录一、什么是yield二、yield于列表的区别三、yield from 实现协程一、什么是yield 如果还没有怎么用过的话&#xff0c;直接把yield看做成一种特殊的return&#xff08;PS&#xff1a;本质 generator&#xff08;生成器&#xff09;&#xff09; return是返回一个值然后…

Python网络编程中getservbyport和getservbyname函数的用法

在Python的网络编程中&#xff0c;getservbyport()函数和getservbyname()函数是socket模块中的两个函数&#xff0c;因此在使用这两个函数时&#xff0c;需要导入socket模块。1 getservbyname()函数getservbyname()函数的作用是通过指定服务的名称获取该服务对应的端口号。相关…

BI工具+方案,这是要将大数据分析包了的节奏啊

BI工具是一个为企业提供大数据智能可视化分析功能板块的平台。虽然它提供了包括智能钻取、内存行列计算、多维动态分析等多种智能数据分析功能板块&#xff0c;但工具毕竟是工具&#xff0c;要真正地为企业所用&#xff0c;还需要针对企业的业务发展情况、数据分析需求等制定数…

用ode45解一个带有积分的微分方程(integro-differential equations)

一、问题提出: 这个方程来源于mathworks的论坛 l 这种方程叫 integro-differential equations ,大致是带有 integral term的微分方程。积分肯定是定积分,这类方程有的是变上限的积分,上下限是x或者其他微分的函数。 按照惯例,先分析。积分区间是0-1,x是自变量,y是应…

2022年终总结——工作第五年

2022是本命年&#xff0c;对我来说今年勉强可以算得上是一切顺利吧。 前几年的年终总结 先验收下去年的期望吧 去年的期望还是挺多的嗷&#x1f643; 1、关于订婚和云南一周游 ✅ 今年大概2月底开始上海疫情开始变得很严重&#xff0c;然后就是漫长的三个月封控&#xff0c;…

1.1.3 java学习的环境准备

文章目录1 相关文件准备及下载1.1 JDK下载1.2 开发工具下载1.2.1 eclipse1.2.2 idea2 JDK安装及配置2.1 JDK配置方法一2.2 JDK配置方法二3 eclipse软件安装及配置4 JDK JRE JVM解释&#xff1a;5 关于手写代码1 相关文件准备及下载 1.1 JDK下载 Oracle公司为常见的计算机系统…

【论文速递】ECCV2022 - ConMatch:置信度引导的半监督学习

【论文速递】ECCV2022 - ConMatch&#xff1a;置信度引导的半监督学习 【论文原文】&#xff1a;ConMatch: Semi-Supervised Learning with Confidence-Guided Consistency Regularization 获取地址&#xff1a;https://arxiv.org/abs/2208.08631博主关键词&#xff1a; 半监…

P8630 [蓝桥杯 2015 国 B] 密文搜索

题目描述 福尔摩斯从 X 星收到一份资料&#xff0c;全部是小写字母组成。 他的助手提供了另一份资料&#xff1a;许多长度为 88 的密码列表。 福尔摩斯发现&#xff0c;这些密码是被打乱后隐藏在先前那份资料中的。 请你编写一个程序&#xff0c;从第一份资料中搜索可能隐藏密码…

八大排序算法(C语言实现)

文章目录&#xff1a;1.排序的概念2.常见八大排序算法3.插入排序3.1直接插入排序3.2希尔排序4.选择排序4.1直接选择排序4.2.堆排序5.交换排序5.1冒泡排序5.2快速排序5.2.1快排递归实现5.2.1.1Hoare法&#xff08;霍尔法&#xff09;5.2.1.2挖坑法5.2.1.3双指针法5.2.2快排迭代实…

最火的聊天回复神器

客服高效回复容易收获用户的好感&#xff0c;也更容易将客户转化成功&#xff0c;借助聊天回复神器&#xff0c;可以助力客服高效快捷地回复。 前言 经常网购的用户&#xff0c;一定会发现在联系客服咨询产品相关问题时&#xff0c;刚把问题发出去&#xff0c;马上就可以收到客…

three.js入门-一些基础理论|大帅老猿threejs特训

前言 参加了threejs直播课。 本篇文章为入门理论部分笔记。 可以学到什么&#xff1a; 一、软能力 1. 系统全流程理解web3D 应用/数字孪生/元宇宙&#xff0c;程序开发与3D美术资源制作 2. 建立与3D美术团队良好沟通协作能力 3. 良好把控3D画面效果和性能平衡 4. 培养程…

数据分析师:星图Stagraph 2.1 Crack

Stagraph 是一个用于数据导入 - 数据整理 - 数据可视化的复杂软件工具。面向数据工程师、数据分析师、数据科学家、统计学家和其他“数据专业人员”的专业软件。在简单易用的可视化界面中提供最新数据科学工具的强大功能。采集 by Ω578867473 降低 降低处理数据的复杂性。使用…

作业帮:探索多云架构下的数据库集群解决方案

导语&#xff1a;面对业务多元、数据海量、数据库种类多样、多云架构复杂等痛点&#xff0c;该如何制定既能解决问题又能降本增效的数据库升级方案&#xff1f;作业帮作为实践者&#xff0c;从四方面分享其数据库选型过程与思考。以下为作业帮DBA刘强在DTCC大会中的讲述。 嘉宾…

移动端自动化python使用appium包登录qq

听标题挺高大上的&#xff0c;其实内容还是脚本小子的高度。。。 为了写个月报一下午抓紧学点东西&#xff0c;好凑点字数&#xff0c;汗。。。 为啥学这个内容&#xff0c;因为找内容的时候翻csdn翻到一个自动抢红包的&#xff0c;就是用的这个技术&#xff0c;前面实验挺好&a…

React Native 三端同构在雪球的实践

随着移动互联网的迅猛发展&#xff0c;目前市面上「端」的形态多种多样&#xff0c;iOS、Android 、H5、微信小程序等各种端大行其道&#xff0c;同一个业务需求往往又需要在多端上去实现&#xff0c;针对不同端去编写多套代码的成本显然非常高。雪球大前端团队将今年在跨端能力…

提取DC综合report_constrain all violator中big neg slack

问题描述 在综合前几版中&#xff0c;通过report_constrain -all_violator命令到得到的违反数量非常多&#xff0c;但暂时只关注比较大的setup/hold违例。 &#xff08;1&#xff09;我们希望提取 < -1.0的违例 &#xff08;2&#xff09;需要把多行合并到一行。 &#xf…

学习python,我使用代码悄悄集齐了五福~哎嘿嘿

啊哈哈哈哈&#xff0c;我又又又来啦 这不是快春节了吗&#xff0c;支付宝等一些集五福活动又又又又一次的到来 今天呢&#xff0c;写一个啥呀我也不晓得&#xff0c;啊哈哈哈哈哈 今天写一个%90会出敬业福哦&#xff0c;啊哈哈哈哈 1.制作文字福 这个其实挺“简单”的&…

如何计算单元测试的覆盖率

一、概念 单元测试的覆盖率有&#xff1a;语句覆盖率&#xff08;即行覆盖率&#xff09;、分支覆盖率、条件覆盖率、分支条件覆盖率、路径覆盖率等。 语句覆盖率 所谓语句就是那些非分支、非判断的语句。 计算公式&#xff1a;程序执行到的语句总数 / 全部语句的总数 分支覆…