Globale Variable in setup() setzen und in loop() auslesen

Es wurde schon tausend Mal gefragt und eigentlich habe ich es verstanden und wie ich glaube richtig gemacht, aber es funktioniert nicht.
Ich möchte die Anzahl der Tracks auf der SD-Karte im DFPlayer Mini auslesen. Dazu mein Code (Auszug):

SoftwareSerial mySoftwareSerial(10,11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
...
int anzahl = 1; // define global

void setup() {   
  mySoftwareSerial.begin(9600);
  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    while(true) { delay(0); } // Code to compatible with ESP8266 watch dog.
  }
   delay(2000); // give it time to start
   ...
   anzahl = myDFPlayer.readFileCounts(); // set it
}

void loop() {
   Serial.print("Count: "); Serial.println(anzahl);  // print it
}

Beim Auslesen in loop() wird "anzahl" als -1 gelesen und die entsprechenden weiteren Abfragen funktionieren natürlich auch nicht.
Definiere ich anzahl = myDFPlayer.readFileCounts(); innerhalb von loop(), funktioniert alles bestens. Es ist aber Unfug, diese Zahl, die sich ja im Betrieb nicht ändert, bei jedem Durchlauf neu auszulesen, das muss doch möglich sein, sie in setup() nur einmal zu definieren?

Wo liegt der Fehler?
Danke!

Der Code ist ja unvollständig.
Wann wird der DF-Player initialisiert?
Gibst Du danach etwas Zeit, bis der bereit ist?

Habs nachgetragen. Ja, er wird initialisiert und ja, er bekommt Zeit.
Es funktioniert ja alles, solange ich die Abfrage der Anzahl in loop() stelle.

Da die includes fehlen uncompiliert

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;

int anzahl = -1; // define global

void setup()
{
  mySoftwareSerial.begin(9600);
  if (!myDFPlayer.begin(mySoftwareSerial))    //Use softwareSerial to communicate with mp3.
  {
    while (true)
    {
      delay(0);  // Code to compatible with ESP8266 watch dog.
    }
  }
  delay(2000); // give it time to start
  while (anzahl < 0)
  { anzahl = myDFPlayer.readFileCounts(); } // set it
  Serial.println(anzahl);
}

void loop()
{
  Serial.print("Count: ");
  Serial.println(anzahl);  // print it
}

Genial, es funktioniert. Aber warum?
Wieso klappt es mit der while-Schleife und mit einer einfachen Zuweisung nicht?

Weil deine 2 Sekunden nicht ausreichen. :slight_smile:

1 Like

Weil der DF-Player wohl mehr als 2 Sekunden braucht bis er die Anzahl erfasst hat.
Du kannst ja mal spaßeshalber das delay(2000); in ein delay(10000); abändern.
Dann funktioniert es wahrscheinlich auch.

Die While-Schleife läuft ja so lange bis nicht mehr "-1" zurückgegeben wird.

Hier eine Code-Variante ganz ohne delay(2000) aber mit Ausgabe der Variable Anzahl
Auch ohne includes weil die Zeilen nicht gepostet wurden

#define dbgi(myFixedText, variableName,timeInterval) \
  { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  }


SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;

int anzahl = -1; // define global

void setup() {
  mySoftwareSerial.begin(9600);
  if (!myDFPlayer.begin(mySoftwareSerial))    //Use softwareSerial to communicate with mp3.
  {
    while (true)
    {
      delay(0);  // Code to compatible with ESP8266 watch dog.
    }
  }
  while (anzahl < 0)
  { anzahl = myDFPlayer.readFileCounts(); } // set it
  dbgi("01",anzahl,500); // schreibe alle halbe Sekunde den Wert Anzahl in den seriellen Monitor
  Serial.println(anzahl);
}

void loop() {
  Serial.print("Count: ");
  Serial.println(anzahl);  // print it
}

vgs

1 Like

Wenn Sie den Quellcode der Funktion in der Bibliothek betrachten

können Sie sehen, dass die Funktion bei einem erfolglosen Anforderungsvorgang -1 zurückgibt. Das bedeutet, dass Ihr DFPlayer trotz der willkürlichen 2-sekündigen Verzögerung, die Sie zuvor hatten, noch nicht bereit war.

Die von austriaka @my_xy_projekt gepostete Lösung durchläuft eine Schleife, bis "anzahl" nicht mehr negativ ist, was bedeutet, dass sie auf das Modul wartet, bis es bereit ist, die Anzahl bereitzustellen, und erst dann fortsetzt.

1 Like

oops :grimacing:

2 Likes

Ach, so einfach kann es sein.
Da ich VOLUME, EQ etc. auch schon setze und das funktioniert, bin ich auf diese Idee natürlich nicht gekommen. Danke dir!
Sehe ich das richtig, dass ich mir den delay(2000) dann auch ersparen kann, weil es ohnehin erst weitergeht, wenn der Player alles gelesen hat?

Danke auch an @my_xy_projekt und @J-M-L !

Ja.

1 Like

Nein.
Das ist nur ein Workaround.
Und las Dich nicht von dem C-Kram ablenken, du musst definitiv noch eine Abbruchfunktion einbauen, da Du sonst dort gefangen bist.

void setup()
{
  mySoftwareSerial.begin(9600);
  if (!myDFPlayer.begin(mySoftwareSerial))    //Use softwareSerial to communicate with mp3.
  {
    while (true)
    { delay(0); }  // Code to compatible with ESP8266 watch dog.
  }
  while (anzahl < 0)
  {
    anzahl = myDFPlayer.readFileCounts(); // set it
    if (millis() > 20000)
    { anzahl = 0; }
  } 
  Serial.println(anzahl);
}

Nun ja, wenn der DFPlayer nicht funktioniert, scheint es in Ordnung zu sein, in einer Endlosschleife zu verbleiben...

Stimmt. Der muss da natürlich auch noch rein...
Aber das ist nciht meine Schleife :wink: Vielleicht soll der ja gar nicht weitermachen, wenn der DFPlayer nicht angeschlossen ist?

Wenn er angeschlossen ist und das Dateisystem kaputt ist, gibt es wenigstens eine 0 :grin:

1 Like

Aus meinem lange zurückliegenden C-Kurs glaube ich mich erinnern zu können daß jede Funktion ein -1 als Fehlermeldung zurückgibt.

Grüße Uwe

1 Like

Das ist Vereinbarung, aber weit verbreitet.
0 -> ok
kleiner 0 -> Fehler (evtl. mit jeweils einer Nummer nach Art des Fehlers)
größer 0 -> Warnung/Info (evtl. mit jeweils einer Nummer nach Art der Info)

Das wurde bei uns damals in C konsequent eingehalten. Auch die darunter liegenden PL/SQL - Routinen hielten sich an diese Konvention.

Natürlich muss man genau dokumentieren (bei uns im Headerfile) was welcher Returncode bedeutet.

Gruß Tommy

@J-M-L und @my_xy_projekt
myDFPlayer.begin() gibt auch false zurück, wenn keine SD-Karte eingelegt ist. Insofern gehts eh nicht weiter, wenn begin() nicht erfolgreich ist. Das ist ein Code-Teil, den ich einfach aus dem Beispiel der Bibliothek behalten habe.
if (anzahl > 0) wird vor dem Abspielen abgefragt. Insofern sollte also nichts passieren, außer dass dann eben nichts passiert, oder?
:slight_smile:

Sie meinen so etwas?

•••
SoftwareSerial dfSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
int anzahl = -1; // define global

void setup() {
  dfSerial.begin(9600);
  if (!myDFPlayer.begin(dfSerial)) {
    while (true) delay(0);
  }
}

void loop() {
  if (anzahl > 0) {
    •••
  } else {
    anzahl = myDFPlayer.readFileCounts();
    delay(0); // ESP8266 watch dog
  }
}

if (millis() > 20000) { anzahl = 0; }
funktioniert leider nicht. Anzahl ist dann immer 0. Und nachdem ich die millis()-Funktion noch nicht durchschaut habe ... lass ich es einfach :wink:

Gibt dir die Laufzeit des Controllers in ms zurück, läuft nach 49 tagen über und fängt dann erneut bei 0 an.
Da sollte also 20 sekunden bei rauskommen.
Und bis dahin sollte der ausgelesen sein.

Läuft das bei Dir auf einem ESP?