Go Down

Topic: DFPlayer mini (MP3-Modul) - Auslesen der Anzahl von Tracks (Read 8041 times) previous topic - next topic

gj99

Hi,

ich experementiere gerade mit oben genanntem MP3-Modul. Start / Stop, Track vor / zurück, Lautstärke hoch / runter .... soweit funktioniert alles.

Was ich nicht hinbekomme ist die Anzahl der vorhandenen Sound-Files auslesen.

Die Bibliothek "DFPlayer_Mini_Mp3.h" beinhaltet eine Funktion namens "mp3_get_tf_sum". Ich komme nicht dahinter, wie diese funktionieren soll (bin auch kein Profi).

Kann mir jemand weiterhelfen, wie ich weiterkomme?

 

uxomm

Wenn ich das richtig sehe, dann gibt es da einen Fehler in der Player-Library*. Mit dem Befehl
Code: [Select]
mp3_get_tf_sum();
werden anscheinend die Tracks der "U-Disk" ausgelesen

und mit
Code: [Select]
mp3_get_u_sum();
werden die Tracks der "TF-Card" ausgelesen

also genau umgekehrt als es vorgesehen ist - jedenfalls gibt es da ein Diskrepanz zwischen der Doku auf der Website (siehe unten) und der Library.

Schick also mal den 2. "Befehl" und auf der (Software-)Seriellen Schnittstelle sollte dann der Player antworten und die Anzal der Tracks preisgeben.


----------------------------
*) Mit der Library ist das wieder mal so ne Sache - die ist eigentlich gar nicht nötig ist, weil die hauptsächlich einfache Kommandos an den Player schickt (siehe http://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299).
Das kann man auch einfach "per Hand" machen und weiß dann viel eher was da abgeht :)
Find ich jedenfalls.
Always decouple electronic circuitry.

gj99

Danke für den Hinweis des "Drehers", hatte ich noch nichts drüber gelesen.

Der Funktionsaufruf leuchtet mir schon ein. Aber dann?
Wie bekomme ich das Lesen der seriellen Schnittstele hin, so dass ich eine Variable mit dem Wert füllen kann?

Ja, die Befehle kann man auch "per Hand" senden, aber so ist es für mich erst einmal einfacher zu lesen. Mit etwas mehr Erfahrung werde ich sicherlich "umstellen".

uxomm

Bei der Library sind auch Beispiele dabei. Schau dir die mal an.
Beim Beispiel "DFPlayer_Mini_Test.ino" wird auch die Anzahl der Tracks auf der Karte ausgelesen. Zum Auslesen wird die Funktion
Code: [Select]
print_info ();
verwendet.
Damit kannst du dir die Antwort des Players am seriellen Monitor anschauen.
Schau dir mal an, wie das in dem Beispiel gemacht wird.

Allerdings ist das erwähnte Beispiel für einen Arduino Leonardo gedacht (Micro würde auch gehen). Dieser hat aber quasi 2 serielle Schnittstellen:
Serial - die zur Kommunikation über USB dient und
Serial1 - das sind die Pins D0 und D1

Wenn man einen anderen Arduino benutzt (du schreibst ja nicht, welchen du hast), zum Beispiel einen UNO, der nur eine serielle Schnittstelle in Hardware hat, dann musst man "Serial1" durch SoftwareSerial / "mySerial" ersetzen.

Ich kann dir leider nur so vage antworten, weil ich deine Hardware nicht habe und es deshalb nicht ausprobieren kann. Ich habe zwar schon öfter mit verschiedenen seriellen MP3-Playern gearbeitet, aber mit "deinem" noch nicht und ich weiß deshalb auch nicht genau, wie die Antwort des Players ausschaut. Von anderen Playern weiß ich aber, dass die Antwort (die auf der seriellen Schnittstelle zurückkommt) meist recht gut auszuwerten ist, ein wenig Erfahrung vorausgesetzt. :)
Always decouple electronic circuitry.

gj99

Also die grundsätzliche Vorgehensweise habe ich so verstanden:
Mit dem Funktionsaufruf "mp3_get_tf_sum()" bzw. "mp3_get_u_sum()" veranlasse ich den mp3-Player Daten auf die serielle Schnittstelle zu schicken. Danach muss ich den Arduino - hier übrigens ein Uno - auf "Empfang schalten".

Den von Dir genannten Beispielsketch habe ich mir angeschaut. Darin wird eine Funktion "print_Hex" aufgerufen, die wohl Bestandteil der Bibliothek  <DFRobot_utility.h> ist. Ich möchte diese aber nicht einbinden, damit der Code nicht aufgebläht wird und ausserdem will ich ja auch verstehen und lernen.

Hier mal ein Teil meines Codes "serielle Schnittstellen":


Code: [Select]

  #ifdef DEBUG                              // Debug-Routine
    Serial.begin(9600);                    // Ausgabe auf PC-Monitor
  #endif    
        
 mp3Serial.begin (9600);               // Serielle Verbindung zu MP3-Player
 mp3_set_serial (mp3Serial);           // Initilisierung Player


... und der Funktionsaufruf:

Code: [Select]

// Anzahl Files auf SD-Karte
void AnzahlTracks()
{
  byte incommingByte = 0;                                               // Variable für gelesene Daten
  mp3_get_u_sum();                                                      // Anzahl Files bestimmen
  delay (10);
  if (mp3Serial.available() > 0)
     {
       incommingByte = mp3Serial.read();     
       if (DEBUG == 1) Serial.println("Lese Wert ... ");
     }
  if (DEBUG == 1) Serial.print("Byte :  ");
  if (DEBUG == 1) Serial.println(incommingByte, DEC);
}



Lasse ich den Sketch laufen, dann erhalte ich als Ausgabe auf dem Monitor die Zahl "0". Die Meldung "Lese Wert ... " bleibt aus, also ist die If-Anweisung nicht erfüllt.

Da der Code der Arduino-Reference entnommen wurde und nicht funktioniert, stehe ich wieder auf dem Schlauch.  :o









gj99

Verwende ich diesen Code ...

Code: [Select]

// Anzahl Files auf SD-Karte
void AnzahlTracks()
{  
  int daten = 0;
  mp3_get_u_sum();                
  daten = mp3Serial.read ();
  if (daten)
   {
         Serial.println("Lese Wert ... ");
         Serial.println(daten);
    }
}



.... dann ist die If-Anweisung erfüllt und er meldet "-1". Es tut sich also was ...
 




Serenifly

Du verstehst nicht was du machst. -1 von read() bedeutet das keine Daten da sind. true/false ist aber so definiert, dass 0 false ist und alles ungleich 0 ist true. -1 ist aber dann wenn du dass so machst true.

uxomm

-1 bedeutet nur, dass KEINE Daten vorhanden sind.
Du musst dem Player und der Seriellen Schnittstelle auch Zeit geben zu antworten. Die serielle Übertragung ist ziemlich langsam (im Vergleich zu den meherern Millionen Anweisungen, die der Arduino pro Sekunde ausführen kann). Am besten geht das, indem du bei jedem Loop-Durchlauf (wenn du keine Delays verwendest, dann sind das oft mehrere Tausend pro Sekunde) mit
Code: [Select]
if(mySerial.available()) {
// einlesen eines Bytes und hinzufügen in ein Array oder in einen Buffer
}

abfragst ob neue Daten vorhanden sind oder nicht.
Meist gibt es ein "Endzeichen" am Ende der Antwort - sehr häufig ein Zeilenvorschub oder ein Carriage Return oder beisdes. So kannst du herausfinden, wann die Antwort fertig übertragen ist. Aber welches Endzeichen dein Player sendet musst du erst mal herausfinden. Die Doku ist da leider nicht so besonders gesprächig.

Weiters:
Code: [Select]
daten = mp3Serial.read();
liest nur ein einziges Byte und nicht die ganze Antwort.
Das sind die Fehler, die fast alle am Anfang machen. :)

Schau dir mal an, wie das mit serieller Übertragung so grundsätzlich funktioniert. Vor allem wie du die Antwort auswerten kannst die aus mehreren Zeichen bestehen. Zum Beispiel:
Serial Input Basics

Ganz grundsätzlich: Du musst erst mal den Player irgendwie zum Sprechen bekommen - bzw. sprechen tut er eh, du kannst es zur Zeit nur nicht lesen.
Quote
Den von Dir genannten Beispielsketch habe ich mir angeschaut. Darin wird eine Funktion "print_Hex" aufgerufen, die wohl Bestandteil der Bibliothek  <DFRobot_utility.h> ist. Ich möchte diese aber nicht einbinden, damit der Code nicht aufgebläht wird und ausserdem will ich ja auch verstehen und lernen.
Ja dein Wille sei dir gegönnt, aber du musst jetzt mal IRGENDWIE die Antworten des Players zu Gesicht bekommen. Über Optimierung etc. kann man später nachdenken.
Always decouple electronic circuitry.

Serenifly

Als Hack kann man erst mal nach dem Kommando z.B. 50ms warten. Das ist mehr als genug Zeit um eine Multi-Byte Antwort zu empfangen (bei 9600 Baud dauert ein Zeichen 1 / 9600 * 10 Sekunden ~ 1ms). Und dann in einer while-Schleife read() machen (nicht-blockierend geht das natürlich nicht)

Laut Datenblatt wird anscheinend 0xEF als Endzeichen verwenden. Sowohl beim Senden als auch beim Empfangen. Generell sollte man vielleicht die empfangenen Daten als HEX anzeigen lassen

gj99


uxomm

Natürlich läuft der nicht - siehe #3 (Antwort 3), weil dieser für ein anderes Arduino Board geschrieben ist - nämlich für eine Leonardo, der hat "Serial" und "Serial1" (das habe ich schon in #3 erwähnt).
Dein Uno hat kein "Serial1", deshalb musst du Serial1 durch dein "SoftwareSerial" ersetzen - du nennst es glaube ich "mp3Serial".

Ich würde dir ja gerne einen getesteten Code schicken, bin aber im Moment weit weg von meinen Arduinos und mp3-Playern.
Und so ganz ins Blaue hinein will ich nichts coden...
Always decouple electronic circuitry.

gj99

Habe mal "versucht" Serial1 durch mp3Serial zu ersetzen.
und hinzugefügt

SoftwareSerial mp3Serial(10, 11);                                 // Pins für RX, TX
mp3Serial.begin (9600);                                               // Serielle Verbindung zu MP3-Player
mp3_set_serial (mp3Serial);   

aber ...


Test_DFPlayer_Mini_Test:86: error: could not convert 'mp3Serial' from 'SoftwareSerial' to 'HardwareSerial'

         int recv_leng = serialRead (mp3Serial, recv_buf, 10, 3);


da muss noch was nicht passen.






gj99

Also seriell "senden" kann ich. mp3_play, mp3_volume etc. werden ausgeführt. Theoretisch muss also die serielle Verbindung "stehen".

Ein "delay(x)" > für x = 1, 5, 10, 20, 50, 100, 500 < nach "mp3_get_u_sum" hat keine Änderung gebracht.

Dass die gesendete serielle Information aus mehreren Zeichen besteht, habe ich nun verstanden. Diese sind zu sammeln bis ein "Endezeichen" - welches ea auch hier sein mag - ankommt und dann auszuwerten.
Aber damit brauche ich ja erst gar nicht anzufangen, wenn ich noch nicht einmal "ein" Zeichen erhalte.
Die if-Anweisung

            if (mp3Serial.available() > 0)

wird nicht befolgt, also kommt nichts an. 


gj99

Ich habe jetzt mal folgendes probiert:

Code: [Select]

// Anzahl Files auf SD-Karte
void AnzahlTracks()

  byte daten;
  mp3_get_volume (); 
  delay(5);
  int var = 0;             
  while (var < 20)
  {
    if (mp3Serial.available() > 0)
    {
     daten = mp3Serial.read();
     Serial.println("Lese Wert ... ");
     Serial.println(daten);
    }
    else
    {
     Serial.println("Fehler");
    }
    var++;
 }
}




Da ich ja Volume einstellen kann, habe ich es jetzt mal versucht zu lesen. Bei den ersten 5 Durchgängen der while-Schleife wurde mir "Fehler" gemeldet. Dann erhielt ich 10 Werte (alle anders, aber immerhin) und dann wieder 5 Fehler.

Laienhaft vermute ich jetz mal, das da was mit dem "Timing" nicht funktioniert. Vielleicht fällt Euch ja dazu was ein :-)

Für heute Feierabend, wünsche alle Lesern eine schönes Wochenende !

uxomm

Die serielle Kommunikation ist fürchterlich langsam im Vergleich zur Ausführung von Befehlen am Arduino und braucht bei 9600 Baud ca. 1 Millisekunde pro Zeichen - in dieser Zeit können wohl ein paar Tausend Befehle durchgeführt werden.

Aber wenn du 10 Werte erhalten hast, dann ist das ja gar nicht so schlecht.

Ich habe deine Hardware nicht, aber ich glaube, du könntest mal folgendes versuchen:
Code: [Select]
#include <SoftwareSerial.h>
#include <DFPlayer_Mini_Mp3.h>
SoftwareSerial mp3Serial(2,3);    // RX, TX

void setup() {
    mp3Serial.begin(9600);
    Serial.begin(9600);
    mp3_set_serial (mp3Serial);  //set softwareSerial for DFPlayer-mini mp3 module
    delay(1000);
    mp3_get_volume();
    delay(1000);       // ein wenig warten auf Antwort, "dirty method" :-)
    if (mp3Serial.available())
    {  Serial.println("Der MP3-Player antwortet:");
        while(mp3Serial.available())
        {   Serial.print(mp3Serial.read(),HEX);
             Serial.print(" ");
        }
    }
}

void loop()
{     
}

Damit wird die aktuelle Lautstärke abgefragt.
Das ist eher kein Code für "Normalbetrieb", sondern nur um "Quick&Dirty" mal eine Antwort zu bekommen.
Die Ausgabe erfolgt übrigens in HEX.

Du solltest auch bedenken, dass die Antwort vielleicht nicht unbedingt besonders "menschenlesbar" sein könnte...

Bei einem meiner MP3-Player zum Beispiel schaut eine Antwort auf die Frage nach der eingestellten Lautstärke so aus (es sind übrigens auch 10 Byte):
Code: [Select]
7E FF 06 43 00 00 1E FE 9A EF
Die Lautstärke "verbirgt" sich in diesem Fall im 1E, der Rest ist "Kommunikations-Beiwerk", bei meinem mp3-Player schaut das nämlich so aus:
Code: [Select]
Kommunikationsstruktur
z.B. Die Antwort des mp3-Players auf die Abfrage der Lautstärke
Die Lautstärke hat aktuell den Wert 1E

7E FF 06 43 00 00 1E FE 9A EF
   1. Byte: 0x7E   Startzeichen der Kommunikationssequenz
   2. Byte: 0xFF   immer 0xFF
   3. Byte: 0x06   Länge des Kommandos in Byte (ohne Start, Ende, Parity) - meist 06
   4. Byte: 0x43   Kommando (in diesem Fall die Lautstärke: 43)
   5. Byte: 0x00   Feedback 00 = kein Feedback, 01 = Feedback senden (default: 00)
   6. Byte: 0x00   Data 1 (High Byte)
   7. Byte: 0x1E   Data 2 (Low Byte) - hier also der aktuelle Wert der Lautstärke
   8. Byte: 0xFE   Checksumme / Parity (High Byte)
   9. Byte: 0x9A   Checksumme / Parity (Low Byte)
  10. Byte: 0xEF   Endzeichen der Kommandosequenz


Auf die Frage nach der Anzahl der Tracks auf der SD-Karte lautet die Antwort meines MP3-Players übrigens:
Code: [Select]
7E FF 06 48 00 00 13 FE A0 EF
Die Struktur ist ganz gleich wie oben.
48 ist das Kommando ("Anzahl der Tracks auf SD") und die eigentliche Trackanzahl ist 13 - das ist ja eine "HEX-Zahl", auf der SD-Karte befinden sich also 19 Tracks (HEX 13 = 19 Dezimal).

Wie ich schon mal erwähnt habe, hab ich schon mir mehreren MP3-Playern, die sich seriell steuern lassen und Arduino gearbeitet. Die Kommunikationsstruktur war meist ziemlich ähnlich (wenn auch nicht ganz gleich). Es wäre also durchaus möglich, dass dein MP3-Player auch so ähnlich kommuniziert.
Always decouple electronic circuitry.

Go Up