Quickest, easiest way of controlling the DFPlayer Mini

I have got a new set of DFPlayer Mini chips and - the good news - these ones work!!

What would be the quickest and dirtiest way in my loop to tell the DFPlayer Mini to play a track? Can I simply send
execute_CMD(0x0D,0,1);
in my loop or would that code need to be in a void to avoid being called again and again?

(There is only one track on the SD card.)

If you add a counter/flag, you can stick in in the loop, otherwise loop() does what loop() does best: looping(), thus repeating it.

Having it in loop() or calling a function that contains that command from within loop() does not make any difference in terms of executing the command over and over.
Either way you need to wrap the command in some kind of condition test as @Moors7 already suggested (e.g. if(needsDoing))

There is a pin on the DFPlayer Mini that can be used to check whether a file is played or not.
IIRC there is also a command to instruct the module to loop-play all tracks (0x11) or the tracks of a specific folder (0x17) - this way you start once and when you want to finish send the stop command (0x16).

1 Like

Really sorry to be reviving this thread but after having success with the command 0x0D, I’m now trying to use 0x12 command and having a real bother figuring out what command to pass to the DFPlayer AFTER 0x12. I’ve tried hex, I’ve tried numbers and I’ve tried filenames.

7E FF 06 12 01 04 01 FE E3 EF 
0x7e 0xff 0x06 0x41 0x00 0x00 0x00 0xfe 0xba 0xef 0x7e 0xff 0x06 0x40 0x00 0x00 0x06 0xfe 0xb5 0xef 

is the response I get when I try. I don’t know how to convert this to any human readable form.

I have had success with 0x0D, but in that case all I needed to do was append 0 0 and it works like a charm.

I’ve got my files in a folder called ‘01’ and they are named ‘001.mp3’, ‘002.mp3’ etc.
Prior to that I had them in the root of the disk and prior to that I had them in a folder named mp3…

It’s working out

0x12 18 Play mp3 file [NUM] in mp3 folder * [DH]=highByte(NUM), [DL]=lowByte(NUM) Play mp3 file in folder named mp3 in your TF-card. File format exact - 4-digit number (0001~2999) e.g. 0235.mp3

what the above translates to in a real world example that’s baffling me. How do I convert [DH] and [DL] to my values?

Sorry…not a programmer…this grows ever obvious…

thanks

I guess you are using the sendCommand() or exectue_CMD() function of one of the available libraries, and IIRC these functions do take the two parameters and convert them into the required format.

If you have a 2byte number (aka uint16_t) you can separate the hi and low byte from that like this

uint16_t num = 1234;
uint8_t lo = num & 0xFF;
uint8_t hi = num >> 8;

void execute_CMD(0x12, hi, lo);

Thanks Scruff! It’s your particle function script I’m using. Sorry, should have said!

You mean this one?

In that case it would be

uint16_t num = 1234;
uint8_t lo = num & 0xFF;
uint8_t hi = num >> 8;

sendCmd(0x12, hi, lo); 
// optionally you can request a reply from the MP3 module via
// sendCmd(0x12, hi, lo, true); 

But in order to have that work you need to have your mp3 files named as four digit numbers with leading zeros (e.g. 0123.mp3) and stored in a root folder mp3.

Your request reply in your example above means this

0x7e 0xff 0x06 0x41 0x00 0x00 0x00 0xfe 0xba 0xef // 0x41 Reply ? [DH]=0, [DL]= 0~? Return code when command feedback is high
0x7e 0xff 0x06 0x40 0x00 0x00 0x06 0xfe 0xb5 0xef // 0x40 Error ? [DH]=0, [DL]= 0~7 Error code(Returned codes not yet analyzed) 

0x41 indicated that you have requested a reply but the module doesn’t request you to reply.
0x40 provides the error code 0x06 (what that means might be found in the datasheet of the MP3 chip)

/* Particle-function_MP3_Player

How to use?

Using the Particle App, for your Particle device, you can find the function "MP3".
There you can enter any of the commands for the MP3 module, with their parameters.

For example "0x17 2 0" (command, data low byte, data high byte) starts the loop for folder 2. It returns the decimal number of the command. In this example "23".

List of main commands:

0x01 1 Next * [DH]=0, [DL]=0 Next file in current folder.Loops when last file played
0x02 2 Previous * [DH]=0, [DL]=0 Previous file in current folder.Loops when last file played
0x03 3 Specify track(NUM) * [DH]=highByte(NUM), [DL]=lowByte(NUM) 1~2999 Playing order is order in which the numbers are stored. Filename and foldername are arbitrary, but when named starting with an increasing number and in one folder, files are played in that order and with correct track number. e.g. 0001-Joe Jackson.mp3...0348-Lets dance.mp3)
0x06 6 Specify volume * [DH]=0, [DL]=Volume (0-0x30) Default=0x30
0x07 7 Specify Equalizer * [DH]=0, [DL]= EQ(0/1/2/3/4/5) [Normal/Pop/Rock/Jazz/Classic/Base]
0x08 8 Specify repeat(NUM) * [DH]=highByte(NUM), [DL]=lowByte(NUM).Repeat the specified track number
0x0A 10 Enter into standby – low power loss * [DH]=0, [DL]=0 Works, but no command found yet to end standby (insert TF-card again will end standby mode)
0x0C 12 Reset module * [DH]=0, [DL]=0 Resets all (Track = 0x01, Volume = 0x30) Will return 0x3F initialization parameter (0x02 for TF-card) Clap sound after excecuting command (no solution found)
0x0D 13 Play * [DH]=0, [DL]=0 Play current selected track
0x0E 14 Pause * [DH]=0, [DL]=0 Pause track
0x0F 15 Specify folder and file to playback * [DH]=Folder, [DL]=File - Important: Folders must be named 01~99, files must be named 001~255
0x11 17 Loop play - Start at track 1 * [DH]=0, [DL]=1:play, 0:stop play
0x12 18 Play mp3 file [NUM] in mp3 folder * [DH]=highByte(NUM), [DL]=lowByte(NUM) Play mp3 file in folder named mp3 in your TF-card. File format exact - 4-digit number (0001~2999) e.g. 0235.mp3
0x16 22 Stop * [DH]=0, [DL]=0, Stop playing current track
0x17 23 Loop Folder 01 * [DH]=0, [DL]=1~99, Loops all tracks in folder named "01"
0x18 24 Random play * [DH]=0, [DL]=0 Random all tracks, always starts at track 1
0x19 25 Single loop * [DH]=0, [DL]=0 Loops the track that is playing
0x1A 26 Pause * [DH]=0, [DL]=(0x01:pause, 0x00:stop pause)
0x3F 63 Initialization parameters * [DH]=0, [DL]= 0 ~ 0x0F. Returned code when Reset (0x12) is used.(each bit represent one device of the low-four bits) See Datasheet. 0x02 is TF-card. Error 0x01 when no medium is inserted.
0x4F 79 The total number of folders * [DH]=0, [DL]=(NUM), Total number of folders, including root directory
*/

uint32_t msCmdReceived;


void setup()
{
    Serial.begin(115200);
    Serial1.begin(9600);
    
    Particle.function("MP3", mp3Command);
}


void loop()
{
    if ((millis() - msCmdReceived > 500))
    {
        if (Serial.available())
            Serial.println();
        while(Serial1.available())
            Serial.printf("0x%02x ", Serial1.read());
        msCmdReceived = 0;
    }
}


void sendCmd(int cmd, int lb, int hb, bool reply = false)
{                 // standard format for module command stream
    uint8_t buf[] = {0x7E, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF}; 
    int16_t chksum = 0;
    int idx = 3;                    // position of first command byte

    buf[idx++] = (uint8_t)cmd;      // inject command byte in buffer
    if (reply) buf[idx++] = 0x01;   // set if reply is needed/wanted
    if (hb >= 0)                    // if there is a high byte data field
        buf[idx++] = (uint8_t)hb;   // add it to the buffer
    if (lb >= 0)                    // if there is a low byte data field
        buf[idx++] = (uint8_t)lb;   // add it to the buffer
    buf[2] = idx - 1;               // inject command length into buffer
    
    for (int i=1; i < idx; i++)     // calculate check sum for the provided data
        chksum += buf[i];
    chksum *= -1;

    buf[idx++] = (chksum >> 8);     // inject high byte of checksum before
    buf[idx++] = chksum & 0xFF;     // low byte of checksum
    buf[idx++] = 0xEF;              // place end-of-command byte

    Serial1.write(buf, idx);        // send the command to module
    for (int i = 0; i < idx; i++)   // send command as hex string to MCU 
      Serial.printf("%02X ", buf[i]);
    Serial.println();
}


int mp3Command(String para)
{
    int cmd = -1;                   
    int lb = -1;
    int hb = -1;
                                    // parse the command string
    int count = sscanf(para.c_str(), "0x%x %d %d", &cmd, &lb, &hb);

    if (count > 0 && cmd >= 0)      // if we got a well formed parameter string
      sendCmd(cmd, lb, hb, true);   // do the module talking

    msCmdReceived = millis();       // set a non-blocking delay timer

    return cmd;                     // return what command we think we received
}

is the copy pasta code I’m using :slight_smile:
thanks, will do some investigating now while wife is out!

You may want to look into using the library… it is much easier to manage.

this one?

If so I don’t think it’s Core compatible :frowning:

No this one:

it should work on any particle device… check out @ScruffR’s software serial library on the web IDE

Thanks - but it looks like there’s a lot for me to adapt from Arduino with that library for the Particle World (in the one hour left to me before my wife gets home)

  • Navigating the include Arduino.h problem
  • Navigating the Software serial problem
  • Reassigning digital pins

I have just had my first success all day in getting command 0x17 to work so now I’m going to keep plugging away to see if I can play specific files…

Sorry - bit demoralised - cannot crack this thing. I mean, I can get it to play files in the root of the SD card and I can get it to loop files in a folder but I CANNOT figure out how to specify specific tracks. I’ve Googled and Googled until I’m blue in the face. I’m also aware you guys are being very patient with me.

Any tips? I might just go to bed and try again tomorrow with a clear head. Never a bad idea! :wink:

As you can see in the below code, I’m experimenting with different ways of referring to the file…

#include "TimeAlarms/TimeAlarms.h"
uint32_t msCmdReceived;

uint16_t num = 0001;
uint8_t lo = num & 0xFF;
uint8_t hi = num >> 8;

void setup()
{
  Time.zone(0);
  Serial1.begin(9600);
  Serial.begin(115200);
  // create the alarms 
  Alarm.alarmRepeat(21,20,00, GONGS1);  // 17:14pm every day
  Alarm.alarmRepeat(21,14,30, GONGS2);  // 17:14pm every day
  Alarm.alarmRepeat(21,15,00, GONGS3);  // 17:14pm every day
  Alarm.alarmRepeat(21,15,30, GONGS4);  // 17:14pm every day
  Alarm.alarmRepeat(17,58,10,EveningAlarm);  // 5:45pm every day 
  Alarm.alarmRepeat(dowSaturday,8,30,30,WeeklyAlarm);  // 8:30:30 every Saturday 
 
  Alarm.timerRepeat(5, Repeats);            // timer for every 1 seconds    
  Alarm.timerOnce(10, OnceOnly);             // called once after 10 seconds 
}

void loop(){  
  // 
  Alarm.delay(0); // wait one second between clock display
     if ((millis() - msCmdReceived > 500))
    {
        if (Serial.available())
            Serial.println();
        while(Serial1.available())
            Serial.printf("0x%02x ", Serial1.read());
        msCmdReceived = 0;
    }
  
}

// functions to be called when an alarm triggers:
void GONGS1(){
  Serial.println("Fire 1!");    
  mp3Command("0x12, hi, lo");
}

void GONGS2(){
  Serial.println("Fire 2!");    
  mp3Command("0x12 0 0");
}

void GONGS3(){
  Serial.println("Fire 3!");    
  mp3Command("0x12 00 01");
}

void GONGS4(){
  Serial.println("Fire 4!");    
  mp3Command("0x12 00 02");
}


void EveningAlarm(){
  Serial.println("Alarm: - turn lights on");           
}

void WeeklyAlarm(){
  Serial.println("Alarm: - its Monday Morning");      
}

void ExplicitAlarm(){
  Serial.println("Alarm: - this triggers only at the given date and time");       
}

void Repeats(){
  digitalClockDisplay();         
}

void OnceOnly(){
  Serial.println("This timer only triggers once");  
}

void digitalClockDisplay()
{
  // digital clock display of the time
  Serial.print(Time.hour());
  printDigits(Time.minute());
  printDigits(Time.second());
  Serial.println(); 
}

void printDigits(int digits)
{
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void sendCmd(int cmd, int lb, int hb, bool reply = false)
{                 // standard format for module command stream
    uint8_t buf[] = {0x7E, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF}; 
    int16_t chksum = 0;
    int idx = 3;                    // position of first command byte

    buf[idx++] = (uint8_t)cmd;      // inject command byte in buffer
    if (reply) buf[idx++] = 0x01;   // set if reply is needed/wanted
    if (hb >= 0)                    // if there is a high byte data field
        buf[idx++] = (uint8_t)hb;   // add it to the buffer
    if (lb >= 0)                    // if there is a low byte data field
        buf[idx++] = (uint8_t)lb;   // add it to the buffer
    buf[2] = idx - 1;               // inject command length into buffer
    
    for (int i=1; i < idx; i++)     // calculate check sum for the provided data
        chksum += buf[i];
    chksum *= -1;

    buf[idx++] = (chksum >> 8);     // inject high byte of checksum before
    buf[idx++] = chksum & 0xFF;     // low byte of checksum
    buf[idx++] = 0xEF;              // place end-of-command byte

    Serial1.write(buf, idx);        // send the command to module
    for (int i = 0; i < idx; i++)   // send command as hex string to MCU 
      Serial.printf("%02X ", buf[i]);
    Serial.println();
}


int mp3Command(String para)
{
    int cmd = -1;                   
    int lb = -1;
    int hb = -1;
                                    // parse the command string
    int count = sscanf(para.c_str(), "0x%x %d %d", &cmd, &lb, &hb);

    if (count > 0 && cmd >= 0)      // if we got a well formed parameter string
      sendCmd(cmd, lb, hb, true);   // do the module talking

    msCmdReceived = millis();       // set a non-blocking delay timer

    return cmd;                     // return what command we think we received
}

OK, slog it out!

in case you want it for Particle, it is on the WebIDE and here adapted for Particle

/*!
 * @file DFRobotDFPlayerMini.h
 * @brief DFPlayer - An Arduino Mini MP3 Player From DFRobot
 * @n Header file for DFRobot's DFPlayer
 *
 * @copyright	[DFRobot]( http://www.dfrobot.com ), 2016
 * @copyright	GNU Lesser General Public License
 *
 * @author [Angelo](Angelo.qiao@dfrobot.com)
 * @version  V1.0
 * @date  2016-12-07
 */

#include "Particle.h"

#ifndef DFRobotDFPlayerMini_cpp
#define DFRobotDFPlayerMini_cpp


#define DFPLAYER_EQ_NORMAL 0
#define DFPLAYER_EQ_POP 1
#define DFPLAYER_EQ_ROCK 2
#define DFPLAYER_EQ_JAZZ 3
#define DFPLAYER_EQ_CLASSIC 4
#define DFPLAYER_EQ_BASS 5

#define DFPLAYER_DEVICE_U_DISK 1
#define DFPLAYER_DEVICE_SD 2
#define DFPLAYER_DEVICE_AUX 3
#define DFPLAYER_DEVICE_SLEEP 4
#define DFPLAYER_DEVICE_FLASH 5

#define DFPLAYER_RECEIVED_LENGTH 10
#define DFPLAYER_SEND_LENGTH 10

//#define _DEBUG

#define TimeOut 0
#define WrongStack 1
#define DFPlayerCardInserted 2
#define DFPlayerCardRemoved 3
#define DFPlayerCardOnline 4
#define DFPlayerPlayFinished 5
#define DFPlayerError 6

#define Busy 1
#define Sleeping 2
#define SerialWrongStack 3
#define CheckSumNotMatch 4
#define FileIndexOut 5
#define FileMismatch 6
#define Advertise 7

#define Stack_Header 0
#define Stack_Version 1
#define Stack_Length 2
#define Stack_Command 3
#define Stack_ACK 4
#define Stack_Parameter 5
#define Stack_CheckSum 7
#define Stack_End 9

class DFRobotDFPlayerMini{
  private:
    Stream* _serial;
    unsigned long _timeOutTimer;
    unsigned long _timeOutDuration = 500;
    uint8_t _received[DFPLAYER_RECEIVED_LENGTH];
    uint8_t _sending[DFPLAYER_SEND_LENGTH] = {0x7E, 0xFF, 06, 00, 01, 00, 00, 00, 00, 0xEF};
    uint8_t _receivedIndex=0;
    void sendStack();
    void sendStack(uint8_t command);
    void sendStack(uint8_t command, uint16_t argument);
    void sendStack(uint8_t command, uint8_t argumentHigh, uint8_t argumentLow);
    void enableACK();
    void disableACK();
    void uint16ToArray(uint16_t value,uint8_t *array);
    uint16_t arrayToUint16(uint8_t *array);
    uint16_t calculateCheckSum(uint8_t *buffer);
    void parseStack();
    bool validateStack();
    uint8_t device = DFPLAYER_DEVICE_SD;

  public:
    uint8_t _handleType;
    uint8_t _handleCommand;
    uint16_t _handleParameter;
    bool _isAvailable = false;
    bool _isSending = false;

    bool handleMessage(uint8_t type, uint16_t parameter = 0);
    bool handleError(uint8_t type, uint16_t parameter = 0);

    uint8_t readCommand();

    bool begin(Stream& stream, bool isACK = true);

    bool waitAvailable();

    bool available();

    uint8_t readType();

    uint16_t read();

    void setTimeOut(unsigned long timeOutDuration);

    void next();

    void previous();

    void play(int fileNumber=1);

    void volumeUp();

    void volumeDown();

    void volume(uint8_t volume);

    void EQ(uint8_t eq);

    void loop(int fileNumber);

    void outputDevice(uint8_t device);

    void sleep();

    void reset();

    void start();

    void pause();

    void playFolder(uint8_t folderNumber, uint8_t fileNumber);

    void outputSetting(bool enable, uint8_t gain);

    void enableLoopAll();

    void disableLoopAll();

    void playMp3Folder(int fileNumber);

    void advertise(int fileNumber);

    void playLargeFolder(uint8_t folderNumber, uint16_t fileNumber);

    void stopAdvertise();

    void stop();

    void loopFolder(int folderNumber);

    void randomAll();

    void enableLoop();

    void disableLoop();

    void enableDAC();

    void disableDAC();

    int readState();

    int readVolume();

    uint8_t readEQ();

    int readFileCounts(uint8_t device);

    int readCurrentFileNumber(uint8_t device);

    int readFileCountsInFolder(int folderNumber);

    int readFileCounts();

    int readCurrentFileNumber();

};

#endif

cpp

/*!
 * @file DFRobotDFPlayerMini.cpp
 * @brief DFPlayer - An Arduino Mini MP3 Player From DFRobot
 * @n Header file for DFRobot's DFPlayer
 *
 * @copyright	[DFRobot]( http://www.dfrobot.com ), 2016
 * @copyright	GNU Lesser General Public License
 *
 * @author [Angelo](Angelo.qiao@dfrobot.com)
 * @version  V1.0
 * @date  2016-12-07
 */

#include "DFRobotDFPlayerMini.h"


void DFRobotDFPlayerMini::setTimeOut(unsigned long timeOutDuration){
  _timeOutDuration = timeOutDuration;
}

void DFRobotDFPlayerMini::uint16ToArray(uint16_t value, uint8_t *array){
  *array = (uint8_t)(value>>8);
  *(array+1) = (uint8_t)(value);
}

uint16_t DFRobotDFPlayerMini::calculateCheckSum(uint8_t *buffer){
  uint16_t sum = 0;
  for (int i=Stack_Version; i<Stack_CheckSum; i++) {
    sum += buffer[i];
  }
  return -sum;
}

void DFRobotDFPlayerMini::sendStack(){
  if (_sending[Stack_ACK]) {
    while (_isSending) {
      available();
    }
  }
  else{
    delay(10);
  }

#ifdef _DEBUG
  Serial.println();
  Serial.print(F("sending:"));
  for (int i=0; i<DFPLAYER_SEND_LENGTH; i++) {
    Serial.print(_sending[i],HEX);
    Serial.print(F(" "));
  }
  Serial.println();
#endif
  _serial->write(_sending, DFPLAYER_SEND_LENGTH);
  _timeOutTimer = millis();
  _isSending = _sending[Stack_ACK];
}

void DFRobotDFPlayerMini::sendStack(uint8_t command){
  sendStack(command, 0);
}

void DFRobotDFPlayerMini::sendStack(uint8_t command, uint16_t argument){
  _sending[Stack_Command] = command;
  uint16ToArray(argument, _sending+Stack_Parameter);
  uint16ToArray(calculateCheckSum(_sending), _sending+Stack_CheckSum);
  sendStack();
}

void DFRobotDFPlayerMini::sendStack(uint8_t command, uint8_t argumentHigh, uint8_t argumentLow){
  uint16_t buffer = argumentHigh;
  buffer <<= 8;
  sendStack(command, buffer | argumentLow);
}

void DFRobotDFPlayerMini::enableACK(){
  _sending[Stack_ACK] = 0x01;
}

void DFRobotDFPlayerMini::disableACK(){
  _sending[Stack_ACK] = 0x00;
}

bool DFRobotDFPlayerMini::waitAvailable(){
  _isSending = true;
  while (!available());
  return _handleType != TimeOut;
}

bool DFRobotDFPlayerMini::begin(Stream &stream, bool isACK)
{
  //timer = new Timer(3000, (void (*)())&DFRobotDFPlayerMini::stopAdvertise, true);
  if (isACK) {
    enableACK();
  }
  else{
    disableACK();
  }

  _serial = &stream;
  _timeOutDuration += 3000;
  reset();
  waitAvailable();
  _timeOutDuration -= 3000;
  delay(200);
  return (readType() == DFPlayerCardOnline) || !isACK;
}

uint8_t DFRobotDFPlayerMini::readType(){
  _isAvailable = false;
  return _handleType;
}

uint16_t DFRobotDFPlayerMini::read(){
  _isAvailable = false;
  return _handleParameter;
}

bool DFRobotDFPlayerMini::handleMessage(uint8_t type, uint16_t parameter){
  _receivedIndex = 0;
  _handleType = type;
  _handleParameter = parameter;
  _isAvailable = true;
  return _isAvailable;
}

bool DFRobotDFPlayerMini::handleError(uint8_t type, uint16_t parameter){
  handleMessage(type, parameter);
  _isSending = false;
}

uint8_t DFRobotDFPlayerMini::readCommand(){
  _isAvailable = false;
  return _handleCommand;
}

void DFRobotDFPlayerMini::parseStack(){
  _handleCommand = *(_received + Stack_Command);
  _handleParameter =  arrayToUint16(_received + Stack_Parameter);

  switch (_handleCommand) {
    case 0x3D:
      handleMessage(DFPlayerPlayFinished, _handleParameter);
      break;
    case 0x3F:
      if (_handleParameter & 0x02) {
        handleMessage(DFPlayerCardOnline, _handleParameter);
      }
      break;
    case 0x3A:
      if (_handleParameter & 0x02) {
        handleMessage(DFPlayerCardInserted, _handleParameter);
      }
      break;
    case 0x3B:
      if (_handleParameter & 0x02) {
        handleMessage(DFPlayerCardRemoved, _handleParameter);
      }
      break;
    case 0x40:
      handleMessage(DFPlayerError, _handleParameter);
      break;
    case 0x41:
      _isSending = false;
      break;
    case 0x3C:
    case 0x3E:
    case 0x42:
    case 0x43:
    case 0x44:
    case 0x45:
    case 0x46:
    case 0x47:
    case 0x48:
    case 0x49:
    case 0x4B:
    case 0x4C:
    case 0x4D:
    case 0x4E:
    case 0x4F:
      _isAvailable = true;
      break;
    default:
      handleError(WrongStack);
      break;
  }
}

uint16_t DFRobotDFPlayerMini::arrayToUint16(uint8_t *array){
  uint16_t value = *array;
  value <<=8;
  value += *(array+1);
  return value;
}

bool DFRobotDFPlayerMini::validateStack(){
  return calculateCheckSum(_received) == arrayToUint16(_received+Stack_CheckSum);
}

bool DFRobotDFPlayerMini::available(){
  while (_serial->available()) {
    if (_receivedIndex == 0) {
      _received[Stack_Header] = _serial->read();
#ifdef _DEBUG
      Serial.print(F("received:"));
      Serial.print(_received[_receivedIndex],HEX);
      Serial.print(F(" "));
#endif
      if (_received[Stack_Header] == 0x7E) {
        _isAvailable = false;
        _receivedIndex ++;
      }
    }
    else{
      _received[_receivedIndex] = _serial->read();
#ifdef _DEBUG
      Serial.print(_received[_receivedIndex],HEX);
      Serial.print(F(" "));
#endif
      switch (_receivedIndex) {
        case Stack_Version:
          if (_received[_receivedIndex] != 0xFF) {
            return handleError(WrongStack);
          }
          break;
        case Stack_Length:
          if (_received[_receivedIndex] != 0x06) {
            return handleError(WrongStack);
          }
          break;
        case Stack_End:
#ifdef _DEBUG
          Serial.println();
#endif
          if (_received[_receivedIndex] != 0xEF) {
            return handleError(WrongStack);
          }
          else{
            if (validateStack()) {
              _receivedIndex = 0;
              parseStack();
              if (_isAvailable && !_sending[Stack_ACK]) {
                _isSending = false;
              }
              return _isAvailable;
            }
            else{
              return handleError(WrongStack);
            }
          }
          break;
        default:
          break;
      }
      _receivedIndex++;
    }
  }

  if (_isSending && (millis()-_timeOutTimer>=_timeOutDuration)) {
    return handleError(TimeOut);
  }

  return _isAvailable;
}

void DFRobotDFPlayerMini::next(){
  sendStack(0x01);
}

void DFRobotDFPlayerMini::previous(){
  sendStack(0x02);
}

void DFRobotDFPlayerMini::play(int fileNumber){
  sendStack(0x03, fileNumber);
}

void DFRobotDFPlayerMini::volumeUp(){
  sendStack(0x04);
}

void DFRobotDFPlayerMini::volumeDown(){
  sendStack(0x05);
}

void DFRobotDFPlayerMini::volume(uint8_t volume){
  sendStack(0x06, volume);
}

void DFRobotDFPlayerMini::EQ(uint8_t eq) {
  sendStack(0x07, eq);
}

void DFRobotDFPlayerMini::loop(int fileNumber) {
  sendStack(0x08, fileNumber);
}

void DFRobotDFPlayerMini::outputDevice(uint8_t device) {
  sendStack(0x09, device);
  delay(200);
}

void DFRobotDFPlayerMini::sleep(){
  sendStack(0x0A);
}

void DFRobotDFPlayerMini::reset(){
  sendStack(0x0C);
}

void DFRobotDFPlayerMini::start(){
  sendStack(0x0D);
}

void DFRobotDFPlayerMini::pause(){
  sendStack(0x0E);
}

void DFRobotDFPlayerMini::playFolder(uint8_t folderNumber, uint8_t fileNumber){
  sendStack(0x0F, folderNumber, fileNumber);
}

void DFRobotDFPlayerMini::outputSetting(bool enable, uint8_t gain){
  sendStack(0x10, enable, gain);
}

void DFRobotDFPlayerMini::enableLoopAll(){
  sendStack(0x11, 0x01);
}

void DFRobotDFPlayerMini::disableLoopAll(){
  sendStack(0x11, 0x00);
}

void DFRobotDFPlayerMini::playMp3Folder(int fileNumber){
  sendStack(0x12, fileNumber);
}

void DFRobotDFPlayerMini::advertise(int fileNumber){
  sendStack(0x13, fileNumber);
}

void DFRobotDFPlayerMini::playLargeFolder(uint8_t folderNumber, uint16_t fileNumber){
  sendStack(0x14, (((uint16_t)folderNumber) << 12) | fileNumber);
}

void DFRobotDFPlayerMini::stopAdvertise(){
  sendStack(0x15);
}

void DFRobotDFPlayerMini::stop(){
  sendStack(0x16);
}

void DFRobotDFPlayerMini::loopFolder(int folderNumber){
  sendStack(0x17, folderNumber);
}

void DFRobotDFPlayerMini::randomAll(){
  sendStack(0x18);
}

void DFRobotDFPlayerMini::enableLoop(){
  sendStack(0x19, 0x00);
}

void DFRobotDFPlayerMini::disableLoop(){
  sendStack(0x19, 0x01);
}

void DFRobotDFPlayerMini::enableDAC(){
  sendStack(0x1A, 0x00);
}

void DFRobotDFPlayerMini::disableDAC(){
  sendStack(0x1A, 0x01);
}

int DFRobotDFPlayerMini::readState(){
  sendStack(0x42);
  if (waitAvailable()) {
    return read();
  }
  else{
    return -1;
  }
}

int DFRobotDFPlayerMini::readVolume(){
  sendStack(0x43);
  if (waitAvailable()) {
    return read();
  }
  else{
    return -1;
  }
}

uint8_t DFRobotDFPlayerMini::readEQ(){
  sendStack(0x44);
  while (!available());
  if (waitAvailable()) {
    return read();
  }
  else{
    return -1;
  }
}

int DFRobotDFPlayerMini::readFileCounts(uint8_t device){
  switch (device) {
    case DFPLAYER_DEVICE_U_DISK:
      sendStack(0x47);
      break;
    case DFPLAYER_DEVICE_SD:
      sendStack(0x48);
      break;
    case DFPLAYER_DEVICE_FLASH:
      sendStack(0x49);
      break;
    default:
      break;
  }

  if (waitAvailable()) {
    return read();
  }
  else{
    return -1;
  }
}

int DFRobotDFPlayerMini::readCurrentFileNumber(uint8_t device){
  switch (device) {
    case DFPLAYER_DEVICE_U_DISK:
      sendStack(0x4B);
      break;
    case DFPLAYER_DEVICE_SD:
      sendStack(0x4C);
      break;
    case DFPLAYER_DEVICE_FLASH:
      sendStack(0x4D);
      break;
    default:
      break;
  }
  if (waitAvailable()) {
    return read();
  }
  else{
    return -1;
  }
}

int DFRobotDFPlayerMini::readFileCountsInFolder(int folderNumber){
  sendStack(0x4E, folderNumber);
  if (waitAvailable()) {
    return read();
  }
  else{
    return -1;
  }
}

int DFRobotDFPlayerMini::readFileCounts(){
  readFileCounts(DFPLAYER_DEVICE_SD);
}

int DFRobotDFPlayerMini::readCurrentFileNumber(){
  readCurrentFileNumber(DFPLAYER_DEVICE_SD);
}

OK, slog it out!

Bloody hell. Thank you James. OK, so I copy pasted your files, downloaded the .ino and made the adjustments mandated here and it is such a relief to hear all of the MP3s on the SD card playing in a loop. I feel sure I will now be able to control which one I want to ruddy play!! Thanks…