New and Improved DFPlayer Mini Library!!

Sorry if this question is inappropriate, but I stumbled on this Thread at the same time that I have an emerging interest in a device like this.

I have looked at the DFPlayer Mini Manual and it seems as if the tracks are only identified by numbers, and not by (for example) the names of the files. That suggests that the only way to identify a file (or track) is by the order of the files on the SD card.

Am I correct?

...R

Robin2:
I have looked at the DFPlayer Mini Manual and it seems as if the tracks are only identified by numbers, and not by (for example) the names of the files. That suggests that the only way to identify a file (or track) is by the order of the files on the SD card.

Am I correct?

...R

Sort of. Each track on the SD card must have the track number in the name (i.e. 001mysong.mp3, 002myothersong.mp3, etc). So, in a sense, it's both by the numbers and the names of the files.

In this case, play(1) would play 001mysong.mp3.

I hope this helps.

Thanks.

I am assuming that system would allow for missing numbers - for example one could have files named
001songA.mp3
004songD.mp3

and then play(1) and play(4) would work but play(2) and play(3) would not ?

...R

A just tried and have seen that the player takes the file index from the card FAT table.

I had at the beginning 5 files: 0001.mp3, 0002.mp3, ..., 0005.mp3.
Then I renamed 0003.mp3 to 0013.mp3.

The payer still showed the index number 3 for the renamed file.

Trying to run "play(13);" I got the error (5) message form the payer: "Specified track is out of current track scope".

Hence I think you have to make sure that the file numbers really match the file index of the FAT.

Regarding my previous question, I solved it with command stop() followed by command playback() (I did not take the latest version). This way the same song is going to be played from the beginning.

My understanding is that is matters on the ORDER the files are added to the SD card..

usually numbering helps this 'order'... but I thought the order mattered..

numbering and naming just helps identify visually..

Right, the order in which the files are added gives the file index in FAT.

I reworked (optimized) the lib, added some functions (stop, waitEndOfTrack, trackGetNr) and packed everything in only one header file, see attachment.

Dependency: Arduino Streaming (ArduinoStreaming/Streaming.h at master · geneReeves/ArduinoStreaming · GitHub)

DFPlayerMini_Fast.h (8.41 KB)

Can this library be found in the Arduino IDE: Library Manager or must it be manually installed by downloading it from Github? Thanks for the help.

Yes, it is in the Libraries Manager

Strange thing. loop function do nothing. 0_o. Play works, but Loop do nothing. When run same code (simple begin and loop) everything works.

UPDATE. Strange, but it dont work in setup(), in loop() it works. 0_0

Quite interesting indeed...

Can you post your code before and after working?

Now for some reason not Play nor Loop dont work. I have files from 0001.wav to 0005.wav in root and in mp3 folder. If I change library to DFRobot's and dont change anything else then sound plays. But with your library it wont.

#include <DFPlayerMini_Fast.h>

#include <MPU6050.h>

#include <SoftwareSerial.h>

#include "Wire.h"

#include "BladeHacking.h"

SoftwareSerial ss(4,5);

const int MPU_ADDR = 0x68;

int16_t accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z, temp;
float averageGyroX,averageGyroY,averageGyroZ;

MPU6050 MyGyro(MPU_ADDR);
DFPlayerMini_Fast myDFPlayer;
BladeHacking bladeHack;



#define Idle 1
#define Swing 2
#define Hit 3
#define Opening 4
#define Closing 5

#define SWITCH_PIN 10

void setup() {        
  
  pinMode(10,INPUT_PULLUP);
  
  Serial.begin(9600);
  ss.begin(9600);

  
  pinMode(6, OUTPUT);
  digitalWrite(6, HIGH); 

  //delay(2000);
  
  pinMode(8, OUTPUT);
  digitalWrite(BLADE_DATA_PIN, SIG_IDLE);
  bladeHack.send_sig( SIG_CMD_OFF );
  delay(1000);

  
  
  Wire.begin();
  
  MyGyro.initialize();
  MyGyro.setFullScaleGyroRange(MPU6050_GYRO_FS_2000);
  MyGyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_4);
  MyGyro.setAccelerometerPowerOnDelay(3);
  MyGyro.setInterruptMode(true);
  MyGyro.setInterruptLatch(0);
  MyGyro.setIntMotionEnabled(true);
  MyGyro.setDHPFMode(1);
  MyGyro.setMotionDetectionThreshold(3);
  MyGyro.setMotionDetectionDuration(40);

  attachInterrupt(0,DetectedMotion, RISING);
  
  
  bool connectedToPlayer = false;
  while(!connectedToPlayer){
    connectedToPlayer = myDFPlayer.begin(ss);
  }
  Serial.println("Connected to player");
  
  myDFPlayer.volume(30);

  delay(100);
}


void DetectedMotion(){

  Serial.println("Detected motion. Detaching interrupt");
  detachInterrupt(0);
  
}

float getGlobalAccel(){

  MyGyro.getAcceleration(&accel_x,&accel_y,&accel_z);
  float ax = 1.0*(accel_x+1820)/8196;
  float ay = 1.0*(accel_y+4450)/8196;
  float az = 1.0*(accel_z+250)/8196;

  return abs(sqrt(ax*ax+ay*ay+az*az) - 1.0);
  
}

float getGlobalRot(){

  MyGyro.getRotation(&gyro_x,&gyro_y,&gyro_z);
  float gx = 1.0*(gyro_x+45)/16.4;
  float gy = 1.0*(gyro_y+55)/16.4;
  float gz = 1.0*(gyro_z+40)/16.4;

  return sqrt(gx*gx+gy*gy+gz*gz);
  
}

bool bladeOn = false;
bool isOpening = false;
bool isClosing = false;
bool isSwing = false;
bool isHit = false;
bool isLooping = false;
bool moving=false;


float minD=100000;
float maxD = 0;

float zeroMotionTimer=0;

float soundTimer=0;
float startMillis=0;

int playingSound = Idle;

void loop() {
  
  bladeHack.red_breath();
 
//  rot thres 350
//  accel thres 0.3-0.35

  if(digitalRead(SWITCH_PIN) == LOW && !bladeOn && playingSound != Opening)
  {
    //bladeOn=true;
    myDFPlayer.play(1);
    playingSound = Opening;
    soundTimer = 1826;
    startMillis = millis();
  }
  
  if(digitalRead(SWITCH_PIN) == HIGH && bladeOn)
  {
    bladeOn=false;
    myDFPlayer.play(2);
  }

  if(playingSound == Opening && millis()-startMillis > soundTimer){

    myDFPlayer.loop(3);
    playingSound = Idle;
    soundTimer = 300;
    startMillis = millis();
    bladeOn = true;
  }
  
  if(bladeOn)
  {
    float globalAcc = getGlobalAccel();
    //Serial.println(globalAcc);
    if(globalAcc>3.1 && playingSound != Hit){
      myDFPlayer.play(5);
      playingSound = Hit;
      soundTimer = 543;
      startMillis = millis();
    }
    else if(playingSound == Idle &&(getGlobalRot()>350 || globalAcc>0.33))
    {
      myDFPlayer.play(4);
      playingSound = Swing;
      soundTimer = 633;
      startMillis = millis();
    }
    else if(millis()-startMillis > soundTimer && playingSound != Idle)
    {
      myDFPlayer.loop(3);
      playingSound = Idle;
      soundTimer = 300;
      startMillis = millis();
    }
  }
}

I went ahead an reformatted your code so that it is a little more organized. I tried to compile it, but I couldn't find the "BladeHacking.h" library anywhere in GitHub, so you'll have to do the compile-time testing:

#include <DFPlayerMini_Fast.h>
#include <MPU6050.h>
#include <SoftwareSerial.h>
#include "Wire.h"
#include "BladeHacking.h"


#define Idle 1
#define Swing 2
#define Hit 3
#define Opening 4
#define Closing 5
#define SWITCH_PIN 10


SoftwareSerial ss(4,5);
MPU6050 MyGyro(MPU_ADDR);
DFPlayerMini_Fast myDFPlayer;
BladeHacking bladeHack;


const int MPU_ADDR = 0x68;
int16_t accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z, temp;
float averageGyroX,averageGyroY,averageGyroZ;

bool bladeOn = false;
bool isOpening = false;
bool isClosing = false;
bool isSwing = false;
bool isHit = false;
bool isLooping = false;
bool moving=false;

float minD=100000;
float maxD = 0;

float zeroMotionTimer=0;

float soundTimer=0;
float startMillis=0;

int playingSound = Idle;


void setup()
{
  pinMode(10,INPUT_PULLUP);
  pinMode(6, OUTPUT);
  digitalWrite(6, HIGH);
  pinMode(8, OUTPUT);
  digitalWrite(BLADE_DATA_PIN, SIG_IDLE);
  
  Serial.begin(9600);
  ss.begin(9600);
  Wire.begin();
  bladeHack.send_sig(SIG_CMD_OFF);
  delay(1000);
 
  MyGyro.initialize();
  MyGyro.setFullScaleGyroRange(MPU6050_GYRO_FS_2000);
  MyGyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_4);
  MyGyro.setAccelerometerPowerOnDelay(3);
  MyGyro.setInterruptMode(true);
  MyGyro.setInterruptLatch(0);
  MyGyro.setIntMotionEnabled(true);
  MyGyro.setDHPFMode(1);
  MyGyro.setMotionDetectionThreshold(3);
  MyGyro.setMotionDetectionDuration(40);

  attachInterrupt(0, DetectedMotion, RISING);
  
  bool connectedToPlayer = myDFPlayer.begin(ss);
  while(!connectedToPlayer)
    connectedToPlayer = myDFPlayer.begin(ss);
  Serial.println("Connected to player");
 
  myDFPlayer.volume(30);
  delay(100);
}


void loop()
{
  bladeHack.red_breath();
 
//  rot thres 350
//  accel thres 0.3-0.35

  if(digitalRead(SWITCH_PIN) == LOW && !bladeOn && playingSound != Opening)
  {
    //bladeOn=true;
    myDFPlayer.play(1);
    playingSound = Opening;
    soundTimer = 1826;
    startMillis = millis();
  }
 
  if(digitalRead(SWITCH_PIN) == HIGH && bladeOn)
  {
    bladeOn=false;
    myDFPlayer.play(2);
  }

  if(playingSound == Opening && millis()-startMillis > soundTimer){

    myDFPlayer.loop(3);
    playingSound = Idle;
    soundTimer = 300;
    startMillis = millis();
    bladeOn = true;
  }
 
  if(bladeOn)
  {
    float globalAcc = getGlobalAccel();
    //Serial.println(globalAcc);
    if(globalAcc>3.1 && playingSound != Hit){
      myDFPlayer.play(5);
      playingSound = Hit;
      soundTimer = 543;
      startMillis = millis();
    }
    else if(playingSound == Idle &&(getGlobalRot()>350 || globalAcc>0.33))
    {
      myDFPlayer.play(4);
      playingSound = Swing;
      soundTimer = 633;
      startMillis = millis();
    }
    else if(millis()-startMillis > soundTimer && playingSound != Idle)
    {
      myDFPlayer.loop(3);
      playingSound = Idle;
      soundTimer = 300;
      startMillis = millis();
    }
  }
}


void DetectedMotion()
{
  Serial.println("Detected motion. Detaching interrupt");
  detachInterrupt(0);
}


float getGlobalAccel()
{
  MyGyro.getAcceleration(&accel_x,&accel_y,&accel_z);
  
  float ax = 1.0*(accel_x+1820)/8196;
  float ay = 1.0*(accel_y+4450)/8196;
  float az = 1.0*(accel_z+250)/8196;

  return abs(sqrt(ax*ax + ay*ay + az*az) - 1.0);
}


float getGlobalRot()
{
  MyGyro.getRotation(&gyro_x,&gyro_y,&gyro_z);
  
  float gx = 1.0*(gyro_x+45)/16.4;
  float gy = 1.0*(gyro_y+55)/16.4;
  float gz = 1.0*(gyro_z+40)/16.4;

  return sqrt(gx*gx + gy*gy + gz*gz);
}

As for the library, I've double checked everything and it all checks out. It might be an issue with how you've saved your files to the SD card. A couple of things to note:

1.) Filenames do not matter - the track numbers with respect to the library are based solely on the order in which the files were saved to the SD card
2.) The folder structure of the SD card matters. Tbh, I forget exactly how it's supposed to be structured (I think you need to save all of your MP3s to a folder named "mp3" in the root directory)

Can you post the exact contents of your SD card in a zip file?

Power_Broker:
I went ahead an reformatted your code so that it is a little more organized. I tried to compile it, but I couldn't find the "BladeHacking.h" library anywhere in GitHub, so you'll have to do the compile-time testing:

#include <DFPlayerMini_Fast.h>

#include <MPU6050.h>
#include <SoftwareSerial.h>
#include "Wire.h"
#include "BladeHacking.h"

#define Idle 1
#define Swing 2
#define Hit 3
#define Opening 4
#define Closing 5
#define SWITCH_PIN 10

SoftwareSerial ss(4,5);
MPU6050 MyGyro(MPU_ADDR);
DFPlayerMini_Fast myDFPlayer;
BladeHacking bladeHack;

const int MPU_ADDR = 0x68;
int16_t accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z, temp;
float averageGyroX,averageGyroY,averageGyroZ;

bool bladeOn = false;
bool isOpening = false;
bool isClosing = false;
bool isSwing = false;
bool isHit = false;
bool isLooping = false;
bool moving=false;

float minD=100000;
float maxD = 0;

float zeroMotionTimer=0;

float soundTimer=0;
float startMillis=0;

int playingSound = Idle;

void setup()
{
  pinMode(10,INPUT_PULLUP);
  pinMode(6, OUTPUT);
  digitalWrite(6, HIGH);
  pinMode(8, OUTPUT);
  digitalWrite(BLADE_DATA_PIN, SIG_IDLE);
 
  Serial.begin(9600);
  ss.begin(9600);
  Wire.begin();
  bladeHack.send_sig(SIG_CMD_OFF);
  delay(1000);

MyGyro.initialize();
  MyGyro.setFullScaleGyroRange(MPU6050_GYRO_FS_2000);
  MyGyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_4);
  MyGyro.setAccelerometerPowerOnDelay(3);
  MyGyro.setInterruptMode(true);
  MyGyro.setInterruptLatch(0);
  MyGyro.setIntMotionEnabled(true);
  MyGyro.setDHPFMode(1);
  MyGyro.setMotionDetectionThreshold(3);
  MyGyro.setMotionDetectionDuration(40);

attachInterrupt(0, DetectedMotion, RISING);
 
  bool connectedToPlayer = myDFPlayer.begin(ss);
  while(!connectedToPlayer)
    connectedToPlayer = myDFPlayer.begin(ss);
  Serial.println("Connected to player");

myDFPlayer.volume(30);
  delay(100);
}

void loop()
{
  bladeHack.red_breath();

//  rot thres 350
//  accel thres 0.3-0.35

if(digitalRead(SWITCH_PIN) == LOW && !bladeOn && playingSound != Opening)
  {
    //bladeOn=true;
    myDFPlayer.play(1);
    playingSound = Opening;
    soundTimer = 1826;
    startMillis = millis();
  }

if(digitalRead(SWITCH_PIN) == HIGH && bladeOn)
  {
    bladeOn=false;
    myDFPlayer.play(2);
  }

if(playingSound == Opening && millis()-startMillis > soundTimer){

myDFPlayer.loop(3);
    playingSound = Idle;
    soundTimer = 300;
    startMillis = millis();
    bladeOn = true;
  }

if(bladeOn)
  {
    float globalAcc = getGlobalAccel();
    //Serial.println(globalAcc);
    if(globalAcc>3.1 && playingSound != Hit){
      myDFPlayer.play(5);
      playingSound = Hit;
      soundTimer = 543;
      startMillis = millis();
    }
    else if(playingSound == Idle &&(getGlobalRot()>350 || globalAcc>0.33))
    {
      myDFPlayer.play(4);
      playingSound = Swing;
      soundTimer = 633;
      startMillis = millis();
    }
    else if(millis()-startMillis > soundTimer && playingSound != Idle)
    {
      myDFPlayer.loop(3);
      playingSound = Idle;
      soundTimer = 300;
      startMillis = millis();
    }
  }
}

void DetectedMotion()
{
  Serial.println("Detected motion. Detaching interrupt");
  detachInterrupt(0);
}

float getGlobalAccel()
{
  MyGyro.getAcceleration(&accel_x,&accel_y,&accel_z);
 
  float ax = 1.0*(accel_x+1820)/8196;
  float ay = 1.0*(accel_y+4450)/8196;
  float az = 1.0*(accel_z+250)/8196;

return abs(sqrt(axax + ayay + az*az) - 1.0);
}

float getGlobalRot()
{
  MyGyro.getRotation(&gyro_x,&gyro_y,&gyro_z);
 
  float gx = 1.0*(gyro_x+45)/16.4;
  float gy = 1.0*(gyro_y+55)/16.4;
  float gz = 1.0*(gyro_z+40)/16.4;

return sqrt(gxgx + gygy + gz*gz);
}





As for the library, I've double checked everything and it all checks out. It might be an issue with how you've saved your files to the SD card. A couple of things to note:

1.) Filenames do not matter - the track numbers with respect to the library are based solely on the order in which the files were saved to the SD card
2.) The folder structure of the SD card matters. Tbh, I forget exactly how it's supposed to be structured (I think you need to save all of your MP3s to a folder named "mp3" in the root directory)


Can you post the exact contents of your SD card in a zip file?

Blade hacking can be comented out with BladeHacking bladeHack; and all it method executions. It dont affect that situation. And problem is not that I cant play anything, but that I cant play anything using your library. Using DFRobot's library it plays like it should. I enden up using code to send commands directly, without any library.

You may try my header file posted here: New and Improved DFPlayer Mini Library!! - #32 by stevestrong - Exhibition / Gallery - Arduino Forum

I just want to point out that I tested the library as it stands today and it currently plays/loops file (etc) exactly as it should.

If anyone can't get their sketches to work in the future, please post:

  • Your entire sketch
  • Full wiring schematic (an additional set of pictures of your wiring is also a plus)
  • File contents of your SD card

Update

I did some work upgrading the library - now all DFPlayerMini commands and queries are supported by the library!

I literally just tagged the new release, so I expect the changes to be reflected in the IDE's libraries manager in a few hours. Either way, you can always get the latest version from the GitHub repo.

Here's the API listing for the library:

bool begin(Stream& stream);

void playNext();
void playPrevious();
void play(uint16_t trackNum);
void incVolume();
void decVolume();
void volume(uint8_t volume);
void EQSelect(uint8_t setting);
void loop(uint16_t trackNum);
void playbackSource(uint8_t source);
void standbyMode();
void normalMode();
void reset();
void resume();
void pause();
void playFolder(uint8_t folderNum, uint8_t trackNum);
void volumeAdjustSet(uint8_t gain);
void startRepeatPlay();
void stopRepeatPlay();
void playFromMP3Folder(uint16_t trackNum);
void repeatFolder(uint16_t folder);
void randomAll();
void startRepeat();
void stopRepeat();
void startDAC();
void stopDAC();
void sleep();
void wakeUp();

bool isPlaying();
int16_t currentVolume();
int16_t currentEQ();
int16_t currentMode();
int16_t currentVersion();
int16_t numUsbTracks();
int16_t numSdTracks();
int16_t numFlashTracks();
int16_t currentUsbTrack();
int16_t currentSdTrack();
int16_t currentFlashTrack();
int16_t numTracksInFolder(uint8_t folder);
int16_t numFolders();

void findChecksum(stack *_stack);
void sendData();
void flush();
int16_t query(uint8_t cmd, uint8_t msb=0, uint8_t lsb=0);
bool getStatus(uint8_t cmd);
bool parseFeedback();
bool timeout();

void printStack(stack _stack);

Please let me know if you have any problems or run into any bugs!

Also, if you want to send custom packets or parse response packets (from the DFPlayer) if your sketch, you can use the following structs; sendStack and recStack:

struct stack {
 uint8_t start_byte;
 uint8_t version;
 uint8_t length;
 uint8_t commandValue;
 uint8_t feedbackValue;
 uint8_t paramMSB;
 uint8_t paramLSB;
 uint8_t checksumMSB;
 uint8_t checksumLSB;
 uint8_t end_byte;
 } sendStack, recStack;

Each member of the structs can be accessed directly in your sketch. Also, you can pass a stack struct pointer to

void findChecksum(stack *_stack);

to automatically find and insert the correct checksum into your stack. To automatically send the contents of sendStack to the DFPlayer to make a command or query, simply call

void sendData();

. When parsing a response to the recStack struct, just call

bool parseFeedback();

and the DFPlayer's response will automatically load into recStack. Your sketch can then access each member of recStack directly for processing.

To print the contents of any stack, call

void printStack(stack _stack);

Hello I'm new to the DF player module, I come from the Adafruit Sound FX platform.

Anyway your library is simple and lightweight, which means it's great for what I need.

For some reason though I am unable to use the myMP3.loop(x); command.

This is the code I have:

#include <SoftwareSerial.h>
#include <DFPlayerMini_Fast.h>

SoftwareSerial mySerial(3, 2); // RX, TX
DFPlayerMini_Fast myMP3;

void setup()
{
  Serial.begin(115200);
  mySerial.begin(9600);

  myMP3.begin(mySerial);
  
  Serial.println("Setting volume to max");
  myMP3.volume(20);
  delay(20);
  /*
  Serial.println("Playing track 1 for 5 sec");
  myMP3.loop(1);
  delay(20);
  Serial.println(myMP3.currentSdTrack());
  delay(5000);
  Serial.println("Sleeping for 5 sec");
  myMP3.sleep();
  delay(5000);

  Serial.println("Waking up");
  myMP3.wakeUp();
  delay(200);
  Serial.println("Looping track 1");
  myMP3.loop(2);
  Serial.println(myMP3.currentSdTrack());
  */
  //myMP3.volume(30);
  //delay(50);
 // myMP3.loop(0);
}

void loop()
{
  myMP3.loop(1);
  delay(5000);
  Serial.println(myMP3.currentSdTrack());
  delay(1000);
  myMP3.play(1);
  Serial.println(myMP3.currentSdTrack());
  delay(1000);
  myMP3.loop(1);
  Serial.println(myMP3.currentSdTrack());
  delay(600000);

}

The serial results are "0, 1, -1" Definitely wasn't expecting to return two different values after the same loop command. Maybe I'm doing it wrong.

The card is freshly formatted with only one audio file copied. It plays for the second that .play(1) runs.

Power_Broker:
I just want to point out that I tested the library as it stands today and it currently plays/loops file (etc) exactly as it should.

If anyone can't get their sketches to work in the future, please post:

  • Your entire sketch
  • Full wiring schematic (an additional set of pictures of your wiring is also a plus)
    - File contents of your SD card

What exactly does the content on the SD card look like? Do you have all of your files in a folder named "mp3"?