DFPlayer Mini Ansteuerung mit dem Arduino

Über den Beitrag

Nachdem ich in meinem letzten Beitrag über das MP3-Player Modul YX5300 geschrieben habe, möchte ich mich der DFPlayer Mini Ansteuerung mit dem Arduino widmen.

  • Technische Daten und Pinbelegung
  • Dateistruktur der SD-Karte
  • Schaltung bei serieller Ansteuerung mit Arduino
  • Die DFRobotDFPlayerMini Bibliothek
  • Ein eigener Sketch mit Menüführung
  • Ansteuerung über Taster
  • DFPlayer Mini vs. YX5300 Modul
DFPlayer Mini: Foto der Vorder- und Rückseite
Klein aber oho, der DFPlayer Mini

Technische Daten / Eigenschaften des DFPlayer Mini

Übersicht

Der DFPlayer Mini ist für 5-10 Euro bei Amazon oder anderen Onlineshops erhältlich. Sehr beeindruckend ist die geringe Größe des Moduls, denn es ist kaum größer als der Micro SD-Kartenslot. Nicht weniger beeindruckend finde ich, dass dabei auch noch ein Verstärker auf dem Teil Platz findet, so dass man Lautsprecher bis 3 Watt direkt anschließen kann. Ein Datenblatt zum DFPlayer Mini findet man im Netz z.B. hier. Hier ein paar Basisdaten:

Spannungsversorgung 3.2 – 5.0 V
Stromaufnahme (Standby)~ 20 mA
Unterstützte DateitypenMP3 und WAV
Unterstützte SD-KartenMicro SD(HC) bis 32 GB
DateiformatFAT16 / FAT 32
Kommunikation Seriell RX/TX, Baudrate: 9600
USB-PortUSB 2.0 (Flashdrive / PC)
Audio AusgängeLautsprecher – bis 3W (Verstärker on Board)
DAC (für Kopfhörer oder Verstärker)

Das Anschlusschema

Pinbelegung des DFPlayer Mini
Anschlusschema des DFPlayer Mini
Bedeutung der Anschlüsse des DFPlayer Mini

Zu beachten ist, dass man vor den RX Eingang einen 1 kOhm Widerstand setzen muss, sonst produziert man ein sehr unschönes, lautes Brummen. 

Die Adkeyx und IOx Anschlüsse sind eine ziemlich geniale Einrichtung, die es einem erlaubt, den DFPlayer Mini weitgehend mit Tastern zu steuern. Dazu weiter unten mehr. 

Verzeichnis- und Dateistruktur auf der SD-Karte

Der DFPlayer Mini erwartet die Verzeichnis- und Dateinamen in einem bestimmten Format. Die Regeln für die Dateinamensgebung und die maximale Anzahl der Dateien pro Verzeichnis hängen von der Art des Verzeichnisses ab. 

Hinweis: Wenn es Probleme mit der SD-Karte gibt, dann prüft ob ihr dort mehrere Partitionen habt. Manchmal ist auf der SD-Karte eine kleine Bootpartition vorhanden, die Probleme machen kann. Wie man das Problem beseitigt, habe ich in meinem letzten Beitrag beschrieben.  

1. Hauptverzeichnis

Im Hauptverzeichnis der SD-Karte finden bis zu 3000 wav- oder mp3-Dateien Platz. Sie müssen als 0001.mp3 (bzw. 0001.wav), 0002.mp3 …. 3000.mp3 benannt werden. Hier gibt es allerdings das kuriose Problem, dass die Dateien in exakt der Reihenfolge ihrer Namen aufkopiert werden müssen. Sagt man dem Modul es soll 0001.mp3 abspielen, aber 0007.mp3 wurde zuerst aufkopiert, dann wird 0007.mp3 gespielt. Ich persönlich würde davon absehen Dateien ins Hauptverzeichnis zu kopieren. Andere Verzeichnisse haben das Problem nicht. 

2. Standardverzeichnisse

Man darf 99 Standardverzeichnisse erstellen, die nach dem Schema 01, 02, 03 …. 99 benannt werden müssen. In jedes Verzeichnis passen bis zu 3000 Dateien, allerdings lassen sich nur die ersten 255 direkt über die seriellen Kommandos ansprechen. Das heißt, dass ein Kommando wie „spiel Datei Nummer 627“ in den Standardverzeichnissen nicht möglich ist und man sich mit „next“-Anweisungen durchhangeln müsste. Die Dateinamen müssen die Struktur 001xxxxx.mp3 (bzw. wav), 002xxxxx.mp3, ….. 255xxxxx.mp3 haben. Dabei ist „xxxxx“ frei wählbar und kann mehr als die hier angedeuteten 5 Stellen haben. Auch Leerzeichen sind erlaubt. 

3. Sonderverzeichnis „MP3“

Dieses Verzeichnis muss exakt als „MP3“ benannt werden.  Hier passen bis zu 3000 Dateien mit dem Namensschema 0001.mp3 (bzw. wav), 0002.mp3, ….. 3000.mp3 hinein. Im Gegensatz zum Hauptverzeichnis sind alle Dateien direkt ansprechbar und es gibt auch keine Probleme mit der Reihenfolge. 

4. Sonderverzeichnis „ADVERT“

Es gelten dieselben Regeln wie für das MP3 Verzeichnis. Das ADVERT Verzeichnis hat eine besondere Funktion. Spielt man eine Datei aus einem der anderen Verzeichnisse ab und ruft währenddessen eine Datei aus dem ADVERT Verzeichnis auf, so wird das Abspielen der ursprünglichen Datei lediglich unterbrochen. Nach dem Beenden der ADVERT Einspielung wird das ursprüngliche Stück fortgesetzt. Es ist wie eine Werbeeinblendung und so deutet es der Name des Verzeichnisses ja auch schon an.

Die Schaltung für den seriellen Betrieb

Die Schaltung für den Betrieb über die serielle Schnittstelle ist relativ einfach. Zu beachten ist, dass man vor den RX Eingang des DFPlayer Moduls einen 1 kOhm Widerstand setzt.

Hinweis: Bei meiner Schaltung versorge ich den DFPlayer mit Strom vom Arduino. Bei Verwendung größerer Lautsprecher bis hin zu den max. 3 Watt sollte man den Gesamtstromverbrauch des Arduino im Auge behalten und 500 mA nicht überschreiten.  

Fritzing: DFPlayer Mini Ansteuerung mit dem Arduino - Schaltung auf dem Breadboard
DFPlayer Mini Ansteuerung mit dem Arduino – Schaltung
Photo: DFPlayer Mini Ansteuerung mit dem Arduino - Schaltung auf dem Breadboard
Und so sieht die Schaltung auf dem Breadboard aus

Ansteuerung über die Bibliothek
DFRobotDFPlayerMini

Die DFPlayer Mini Ansteuerung mit dem Arduino ist nicht schwer, da es eine Reihe von Bibliotheken auf Github gibt. Ich nutze die DFRobotDFPlayerMini Bibliothek, was aber nicht heißt, dass die anderen schlecht sind. Ich habe sie schlicht zuerst probiert und bin dabei geblieben. 

Wie üblich installiert man die Bibliothek indem man die Zip-Datei herunterlädt und im „Arduino\libraries“ Ordner entpackt. Der mitgelieferte Beispielsketch „FullFunction.ino“ gibt einen guten Überblick über alle Funktionen. Ich habe ihn ein wenig modifiziert, so dass man die Kommandos über den seriellen Monitor aufrufen kann. Hier ist das Ergebnis:

/***************************************************
 Durch Wolfgang Ewald modifizierte Version des FullFunction.ino Beispielsketches der DFRobotDFPlayerMini Bibliothek:
 
 DFPlayer - A Mini MP3 Player For Arduino
 <https://www.dfrobot.com/product-1121.html>
 
 ***************************************************
 This example shows the all the function of library for DFPlayer.
 
 Created 2016-12-07
 By [Angelo qiao](Angelo.qiao@dfrobot.com)
 
 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"
#include "DFRobotDFPlayerMini.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."));
  printHelp();
  
  myDFPlayer.setTimeOut(500); //Set serial communictaion time out 500ms
  
  //----Set volume----
  myDFPlayer.volume(10);  //Set volume value (0~30).
 // myDFPlayer.volumeUp(); //Volume Up
 // myDFPlayer.volumeDown(); //Volume Down
  
  //----Set different EQ----
  myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
//  myDFPlayer.EQ(DFPLAYER_EQ_POP);
//  myDFPlayer.EQ(DFPLAYER_EQ_ROCK);
//  myDFPlayer.EQ(DFPLAYER_EQ_JAZZ);
//  myDFPlayer.EQ(DFPLAYER_EQ_CLASSIC);
//  myDFPlayer.EQ(DFPLAYER_EQ_BASS);
  
  //----Set device we use SD as default----
//  myDFPlayer.outputDevice(DFPLAYER_DEVICE_U_DISK);
  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);
//  myDFPlayer.outputDevice(DFPLAYER_DEVICE_AUX);
//  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SLEEP);
//  myDFPlayer.outputDevice(DFPLAYER_DEVICE_FLASH);
  
  //----Mp3 control----
//  myDFPlayer.sleep();     //sleep
//  myDFPlayer.reset();     //Reset the module
//  myDFPlayer.enableDAC();  //Enable On-chip DAC
//  myDFPlayer.disableDAC();  //Disable On-chip DAC
//  myDFPlayer.outputSetting(true, 15); //output setting, enable the output and set the gain to 15
  

}

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

void readCommand(){
  char cmd = ' ';
  int value1, value2 = 0;
  cmd = Serial.read();
  value1 = Serial.parseInt();
  value2 = Serial.parseInt();
 
  switch(cmd){
    case 'h': 
      printHelp();
      break;
      
    case '>':
      myDFPlayer.next();
      break;
      
    case '<':
      myDFPlayer.previous();
      break;
      
    case 'p':
      if(value2 == '0') myDFPlayer.play(value1);
      else if(value1 != 0) myDFPlayer.playFolder(value1, value2);
      break;

    case 'P':
      if(value2 == '0') myDFPlayer.playMp3Folder(value1); 
      else if(value1 != 0)myDFPlayer.playLargeFolder(value1, value2);
      break;
    
    case '+':
      myDFPlayer.volumeUp(); 
      break;
      
    case '-':
      myDFPlayer.volumeDown();
      break;
      
    case 'v':
      myDFPlayer.volume(value1);
      break;
      
    case 'b':
      myDFPlayer.pause();
      break;

    case 's':
      myDFPlayer.start();
      break;
          
    case 'z':
      myDFPlayer.sleep();
      break;
      
    case 'L':
      if(value1 == "0") myDFPlayer.enableLoopAll();
      else myDFPlayer.loopFolder(value1);
      break;
    
    case 'l':
      if(value1 == "0") myDFPlayer.disableLoopAll();
      else myDFPlayer.loop(value1);
      break;
    
    case 'A':
      myDFPlayer.advertise(value1);
      break;
    
    case 'a':
      myDFPlayer.stopAdvertise();
      break;
    
    case 'q':
      if(value1 == 1) Serial.println(myDFPlayer.readState()); 
      else if(value1 == 2) Serial.println(myDFPlayer.readVolume());
      else if(value1 == 3) Serial.println(myDFPlayer.readEQ());
      else if(value1 == 4) Serial.println(myDFPlayer.readFileCounts());
      else if(value1 == 5) Serial.println(myDFPlayer.readFolderCounts());
      else if(value1 == 6) Serial.println(myDFPlayer.readCurrentFileNumber());
      break;
    default:
      Serial.println("Ungültiges Kommando");
      break;
  }

}

void printHelp(){
  Serial.println("DFPlayer Commands:");
  Serial.println(" h - help");
  Serial.println(" > - next ");
  Serial.println(" < - previous");
  Serial.println(" p3 - play");
  Serial.println(" p3,5 - play folder 3, file 5");
  Serial.println(" P3,5 - play large folder 3, file 5");
  Serial.println(" P3 - play file 3 in MP3 folder"); 
  Serial.println(" + - volume up");
  Serial.println(" - - volume down");
  Serial.println(" v10 - set volume to 10");
  Serial.println(" b - Pause");
  Serial.println(" s - start ");
  Serial.println(" z - sleep ");
  Serial.println(" L - enable loop all");
  Serial.println(" l - disable loop all");
  Serial.println(" L3 - loop folder 3");
  Serial.println(" l3 - loop file 3");
  Serial.println(" A3 - advertise file 3");
  Serial.println(" a - stop advertise "); 
  Serial.println(" qx - query No. x");
  Serial.println("     x = 1 - read state");
  Serial.println("     x = 2 - read volume");
  Serial.println("     x = 3 - read equalizer");
  Serial.println("     x = 4 - read file counts");
  Serial.println("     x = 5 - read current file number");
  Serial.println("     x = 6 - read file counts in folder");
  Serial.println("     x = 7 - read folder counts");
}

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 DFPlayerUSBInserted:
      Serial.println("USB Inserted!");
      break;
    case DFPlayerUSBRemoved:
      Serial.println("USB Removed!");
      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;
  }  
}

Das Einzige was zumindest noch nicht funktioniert, sind die Abfragen (in meinem Menü die „q“ Kommandos). Da muss ich wohl nochmal tiefer einsteigen. Wenn ihr das herausbekommt wäre ich für einen Hinweis dankbar. 

In meinem letzten Beitrag habe ich gezeigt, wie man das YX5300 MP3 Modul mit dem Smartphone steuern kann. Das ließe sich hier hierauf mit relativ wenig Aufwand übertragen.  

Geht’s auch ohne Bibliothek?

Den DFPlayer Mini mit dem Arduino ansteuern ist auch ohne Bibliothek kein großes Hexenwerk, da das Datenblatt recht gut verständlich ist. So sieht die Struktur der Befehle aus:

DFPlayer Ansteuerung mit dem Arduino - Struktur der seriellen Befehle

Jede Befehlssequenz startet mit „7E“. Darauf folgt VER (Version), was grundsätzlich die „77“ ist. „Len“ steht die Befehlslänge in Bytes. Dabei werden Startbyte, Endbyte und Checksumme nicht mitgezählt. Bleiben im Normalfall sechs Bytes. „CMD“ ist das eigentliche Kommando und dafür gibt es eine Liste im Datenblatt. „Feedback“ steuert ob man eine Antwort vom Modul haben möchte. Es gibt nur „01“ für Feedback und „00“ für kein Feedback. „para1“ und „para2“ sind – nicht zur Überraschung – die Befehlsparameter. Diese sind auch im Datenblatt aufgeführt. Die Checksumme gibt zusätzliche Sicherheit, man kann sie aber auch weglassen. Im Datenblatt ist erklärt, wie man die Checksumme berechnet. 

Hier nun ein Beispiel. Um eine bestimmte Datei in einem Standardverzeichnis abzuspielen wird das Kommando 0x0F verwendet. Wenn Datei 002 im Ordner 01 gespielt werden soll und kein Feedback wird gefordert, lautet die Befehlssequenz ohne Checksumme:

7E FF 06 0F 00 01 02 EF

Die Bytes werden einzeln über ein Serial.write(x-tes Byte) übermittelt. Dabei ist „Serial“ durch den vereinbarten SoftwareSerial zu ersetzen. Es ist schon eine ziemliche Fleißarbeit die Kommandos zu implementieren, so dass man froh sein kann, dass es Bibliotheken gibt. Aber ich persönlich möchte gerne auch immer verstehen was hinter den Kulissen passiert. 

Ansteuerung über Taster

Die DFPlayer Mini Ansteuerung mit dem Arduino ist noch nicht alles. Wie oben schon erwähnt, lassen sich viele Funktionen auch über die Adkeyx und IOx Anschlüsse an den Pins 9, 11, 12 und 13 erreichen. 

Die IOx Anschlüsse werden über Taster mit GND verbunden. Je nachdem ob man kurz oder lang drückt, wird die nächste Datei gespielt oder die Lautstärke erhöht bzw. die vorhergehende Datei gespielt oder die Lautstärke verringert. 

Bei den ADKEYx Anschlüssen kann man verschiedene Funktionen erreichen, indem man noch zusätzliche Widerstände einbaut. Ich habe es probiert und es funktioniert einwandfrei.

„Segment X“ heißt dabei übrigens „spiel Datei Nr. X“. Allerdings ist hier wieder die Reihenfolge des Aufkopierens entscheidend und zwar unabhängig von der Verzeichnisart. 

Schaltplan für Anschluss von Tastern an ADKEY und IO ohne Widerstände

Anschluss von Tastern an ADKEY und IO ohne Widerstände
Schaltplan für Anschluss von Tastern an ADKEY mit Widerständen
Anschluss von Tastern an ADKEY mit Widerständen

DFPlayer Mini vs. YX5300

Nachdem ich nun beide Module getestet habe muss ich sagen, dass beide vom Funktionsumfang her recht ähnlich sind. Man ist aber mit dem DFPlayer Mini durch seine Tastenfunktionen deutlich flexibler unterwegs  als mit dem YX5300 Modul. Für den DFPlayer Mini spricht darüber hinaus noch, dass er Pins für den Lautsprecher- bzw. Verstärkeranschluss hat. Hinzu kommt die geringe Größe des Moduls. Der Vorteil des YX5300 Moduls hingegen ist die Klinkensteckerbuchse, an die man Kopfhörer oder (Aktiv-)Lautsprecher direkt anschließen kann. Wer keine Lust hat zu basteln, ist mit dem YX5300 vielleicht besser bedient. 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.