New and Improved DFPlayer Mini Library!!

Now Installable via Arduino IDE's Libraries Manager (search "DFPlayerMini_Fast")


Problem: The original DFPlayer Mini library is relatively slow and difficult to understand for newbies. After reading the datasheet/tutorials, I noticed that controlling the player could be a lot simpler.

Solution: Create my own library that is much simpler and easier to understand.

Here is a link to the final product!

If you think it can be improved, please let me know! (this is my first custom library)

1 Like

Thanks for your contribution!

This is a bit of a nitpick but you did ask for input:
The Arduino library specification states:

Library examples must be placed in the examples folder.
...
Sketches contained inside the examples folder will be shown in the Examples menu of the IDE.

However, the Arduino IDE actually does show all sketches bundled with a library in the File > Examples menu regardless of their folder location so actually your example is currently fine where it is, even though it does not meet the specification. However, I always think it's a good idea to follow the specification unless there is a good reason not to. You have no guarantee that the IDE will retain this behavior in the future whereas I guarantee that the handling of the examples folder is a permanent feature.

Thanks! I didn't notice the whole examples folder thing. I tested it and the example does show up in the IDE, but I'll change it to be in regulations anyway :wink:

I recently added a few features such as changing EQ, pause, and resume.

Did you delete the example file? Where can I get the reference doc for your lib?

smeand:
Did you delete the example file? Where can I get the reference doc for your lib?

Yeah, I deleted it. I tested the sketch earlier and everything worked except for the resume(). I'll eventually try to fix that function (my guess is the resume command ID is wrong, but not sure yet), but I don't have the hardware right now to do that. Until then, I didn't want an example sketch posted that didn't work 100%.

Here is the example posted I had on github earlier:

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


SoftwareSerial mySerial(10, 11); // RX, TX
DFPlayerMini_Fast myDFPlayer;


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


void loop()
{
  myDFPlayer.play(1); //play mp3 file with leading identifier "0001"

  myDFPlayer.volume(1); //set volume low

  delay(100); //wait 100ms

  myDFPlayer.volume(30); //crank that stuff!

  delay(100); //wait another 100ms

  myDFPlayer.EQSelect(1); //set EQ as pop

  delay(100); //wait another 100ms

  myDFPlayer.EQSelect(5); //set EQ as bass

  delay(100); //wait another 100ms

  myDFPlayer.pause(); //pause player

  delay(100); //wait another 100ms

  myDFPlayer.resume(); //resume player

  delay(100); //wait another 100ms

  myDFPlayer.loop(2); //loop mp3 file with leading identifier "0002"

  while(1); //halt
}

If you have any questions, I'd be happy to answer them.

1 Like
  • Cant believe this post didnt turn up in my MANY previous searches!!

I'm going to give this lib a try...

The current DFRobot lib I am using is giving me trouble (or it may be the module itself)..

Maybe your lib will behave better. My current issue(s) are:

1.) When doing just a regular myDFPlayer.play(#) command... then trying to check for when a file has finished/completed playback.. it always immediately says its completed.. (when it just started)

using a snippet of their printDetail() function.. that checks for: DFPlayerPlayFinished

If I used disableLoop() and disableLoop().. then the track reliably was 'wacthed' and reported playback completed accurately.. (however that audio file is NOT supposed to be a loop!..but was only way I could get it to accurately detect when finished)... so this file would sometimes get stuck in a loop...

Does your lib have some way to reliably detect when a file is finished playing?

I still dont see any examples folder? Was this ever finished? (is the lib ready for use?)

running this code:

#include <DFRobotDFPlayerMini.h>

/***************************************************
DFPlayer - A Mini MP3 Player For Arduino
https://www.dfrobot.com/index.php?route=product/product&product_id=1121


This example shows the basic function of library for DFPlayer.

Created 2016-12-07
By Angelo qiao

GNU Lesser General Public License.
See http://www.gnu.org/licenses/ for details.
All above must be included in any redistribution
****************************************************/

/Notice and Trouble shooting****
1.Connection and Diagram can be found here
https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299#Connection_Diagram
2.This code is tested on Arduino Uno, Leonardo, Mega boards.
****************************************************/

#include <Arduino.h>
#include <SoftwareSerial.h>

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
void printDetail(uint8_t type, int value);

void setup()
{
mySoftwareSerial.begin(9600);
Serial.begin(9600);

Serial.println();
Serial.println(F("DFRobot DFPlayer Mini Demo"));
Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));

if (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3.
Serial.println(F("Unable to begin:"));
Serial.println(F("1.Please recheck the connection!"));
Serial.println(F("2.Please insert the SD card!"));
while(true);
}
Serial.println(F("DFPlayer Mini online."));

myDFPlayer.volume(10); //Set volume value. From 0 to 30
myDFPlayer.play(1); //Play the first mp3
}

void loop()
{
static unsigned long timer = millis();

if (millis() - timer > 3000) {
timer = millis();
myDFPlayer.next(); //Play next mp3 every 3 second.
}

if (myDFPlayer.available()) {
printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states.
}
}

void printDetail(uint8_t type, int value){
switch (type) {
case TimeOut:
Serial.println(F("Time Out!"));
break;
case WrongStack:
Serial.println(F("Stack Wrong!"));
break;
case DFPlayerCardInserted:
Serial.println(F("Card Inserted!"));
break;
case DFPlayerCardRemoved:
Serial.println(F("Card Removed!"));
break;
case DFPlayerCardOnline:
Serial.println(F("Card Online!"));
break;
case DFPlayerPlayFinished:
Serial.print(F("Number:"));
Serial.print(value);
Serial.println(F(" Play Finished!"));
break;
case DFPlayerError:
Serial.print(F("DFPlayerError:"));
switch (value) {
case Busy:
Serial.println(F("Card not found"));
break;
case Sleeping:
Serial.println(F("Sleeping"));
break;
case SerialWrongStack:
Serial.println(F("Get Wrong Stack"));
break;
case CheckSumNotMatch:
Serial.println(F("Check Sum Not Match"));
break;
case FileIndexOut:
Serial.println(F("File Index Out of Bound"));
break;
case FileMismatch:
Serial.println(F("Cannot Find File"));
break;
case Advertise:
Serial.println(F("In Advertise"));
break;
default:
break;
}
break;
default:
break;
}

}

and getting this error in the serial monitor:

DFRobot DFPlayer Mini Demo
Initializing DFPlayer ... (May take 3~5 seconds)
Unable to begin:
1.Please recheck the connection!
2.Please insert the SD card!
it won't allow me to play the sound files. I am using mp3 files.

This example code has nothing to do with my new library.

I am also getting the errors

DFRobot DFPlayer Mini Demo
Initializing DFPlayer ... (May take 3~5 seconds)
Unable to begin:
1.Please recheck the connection!
2.Please insert the SD card!
it won't allow me to play the sound files. I am using mp3 files.

it was working 3 weeks ago finaly finshed other code for excape room whent to add
music now get error

xl97:
Does your lib have some way to reliably detect when a file is finished playing?

I still dont see any examples folder? Was this ever finished? (is the lib ready for use?)

Sorry for not getting back to you sooner, I don't visit this forum nearly as much as I used to.

There aren't any example programs other than this one (similarly to the one I posted above, just without the pause()):

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


SoftwareSerial mySerial(10, 11); // RX, TX
DFPlayerMini_Fast myDFPlayer;


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


void loop()
{
  myDFPlayer.play(1); //play mp3 file with leading identifier "0001"

  delay(100); //wait 100ms

  myDFPlayer.volume(1); //set volume low

  delay(100); //wait another 100ms

  myDFPlayer.volume(30); //crank that stuff!

  delay(100); //wait another 100ms

  myDFPlayer.EQSelect(1); //set EQ as pop

  delay(100); //wait another 100ms

  myDFPlayer.EQSelect(5); //set EQ as bass

  delay(100); //wait another 100ms

  myDFPlayer.pause(); //pause player

  delay(100); //wait another 100ms

  myDFPlayer.loop(2); //loop mp3 file with leading identifier "0002"

  while(1); //halt
}

Also, in order to keep the code as streamlined as possible (and use as few pins as possible), the library doesn't use any feedback from the mp3 module itself.

I don't think there is a way to really check if a file has finished playing - nomatter what library you use.

The DFRobot lib does offer a way to check for audio clip completion.

(its happens to have a bug in it however.. where it was sometimes firing twice.... but someone posted there work-around for it)

There is also the 'busy' pin if you want a physical approach.. (but its too slow to be used for anything timing critical or reactive..etc)

revrickv:
I am also getting the errors

DFRobot DFPlayer Mini Demo
Initializing DFPlayer ... (May take 3~5 seconds)
Unable to begin:
1.Please recheck the connection!
2.Please insert the SD card!
it won't allow me to play the sound files. I am using mp3 files.

it was working 3 weeks ago finaly finshed other code for excape room whent to add
music now get error

Change the sketch from

if (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3.
Serial.println(F("Unable to begin:"));
Serial.println(F("1.Please recheck the connection!"));
Serial.println(F("2.Please insert the SD card!"));
while(true);
}

to

while(!myDFPlayer.begin(mySoftwareSerial))
{
mySoftwareSerial.begin(9600);
delay(500);
}

It worked with my Arduino Uno

Today I updated the library to add a lot more functionality.

So far all of the commands have been implemented, but I still have yet to add the queries. I plan on adding those sometime in the not so terribly far out future.

Hello. Can you give me an example of your library controlling 2 players at the same time? SoftSerial1 pins 2,3 and SoftSerial2 pins 4,5. Serial will be used to debug messages from Arduino to the IDE terminal. I want to play a background music in loop with one player and another player will play sounds as needed when needed. I will mix the 2 players into one output and have a multichannel mp3 player. Like a beatbox. is it something like this?:

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

SoftwareSerial Serial1(2, 3); // RX, TX
SoftwareSerial Serial2(4, 5); // RX, TX

DFPlayerMini_Fast myMP3One;
DFPlayerMini_Fast myMP3Two;
// Or DFPlayerMini_Fast myMP3One, myMP3Two;

void setup()
{
  Serial.begin(115200);
  Serial1.begin(9600);
  Serial2.begin(9600);

  myMP3One.begin(Serial1);
  myMP3Two.begin(Serial2);
  
  Serial.println("Setting volume to max");
  myMP3One.volume(30);
  myMP3Two.volume(30);
  delay(20);
  
  Serial.println("Playing track 1 player 1 for 5 sec");
  myMP3One.play(1);
  Serial.println("Playing track 2 player 2 for 5 sec");
  myMP3Two.play(2);
  delay(5000);

  Serial.println("Looping track 1");
  myMP3One.loop(1);
}

void loop()
{
  //do nothing
}

Yes, but with one small edit: in order to use multiple software serial ports, you must call SWSerialPort.listen() (SWSerialPort being either Serial1 or Serial2 in your case) before each call from the class DFPlayerMini_Fast.

Here's an example:

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

SoftwareSerial Serial1(2, 3); // RX, TX
SoftwareSerial Serial2(4, 5); // RX, TX

DFPlayerMini_Fast myMP3One;
DFPlayerMini_Fast myMP3Two;
// Or DFPlayerMini_Fast myMP3One, myMP3Two;

void setup()
{
  Serial.begin(115200);
  Serial1.begin(9600);
  Serial2.begin(9600);

  myMP3One.begin(Serial1);
  myMP3Two.begin(Serial2);
  
  Serial.println("Setting volume to max");
  Serial1.listen();    //<---------------------------------- #
  myMP3One.volume(30);
  Serial2.listen();    //<---------------------------------- #
  myMP3Two.volume(30);
  delay(20);
  
  Serial.println("Playing track 1 player 1 for 5 sec");
  Serial1.listen();    //<---------------------------------- #
  myMP3One.play(1);
  Serial.println("Playing track 2 player 2 for 5 sec");
  Serial2.listen();    //<---------------------------------- #
  myMP3Two.play(2);
  delay(5000);

  Serial.println("Looping track 1");
  Serial1.listen();    //<---------------------------------- #
  myMP3One.loop(1);
}

void loop()
{
  //do nothing
}

I've been working with the player for a while and my latest project requires determining when a file has finished playing. I don't see a way to do that in this library, can you provide example code?

Thanks!

psycho774:
I've been working with the player for a while and my latest project requires determining when a file has finished playing. I don't see a way to do that in this library, can you provide example code?

Thanks!

I've never had to worry about it for my projects, but I know it is possible to do that - just not with this library in it's current state. One day I'll add query commands to the library, but I've been putting it off lately.

Can you describe your project?

I've done some preliminary testing and I've discovered how to determine if a song is playing or not. First, in order to send the query, you must send the following packet (in order):

  • $S: 0x7E
  • VER: 0xFF
  • Len: 0x6
  • CMD: 0x42
  • Feedback: 0x01
  • para1: 0x00
  • para2: 00
  • checksum: 0x-- <-- This is automatically calculated by my library (I don't have the exact value written down)
  • $0: 0xEF

The response is always in two packets. Here are example response packets for both when a track is playing and when it isn't:

Track is playing response:
7E FF 64 20 21 FE B6 EF ----- Response packet #1
7E FF 64 10 00 FE BA EF ----- Response packet #2

Track is not playing response:
7E FF 64 20 20 FE B7 EF ----- Response packet #1
7E FF 64 10 00 FE BA EF ----- Response packet #2

From these examples, you can tell the track playing status by seeing if the 10th byte of the first response packet is a 1 or a 0.

I should be able to have logic around this query implemented into the library soon.

In another thread about this module.. there was some discussion about how (the default) lib sometimes reported the file had stopped twice..

I dont recall the details.. just the topic.. might be worth a read when you go your path of updating..