If Funktion bei delay()

Hallo zusammen,

Hab vor kurzem mit Arduino angefangen daher habe ich etwas Basic-Wissen aber kann damit noch nicht richtig jonglieren (auch wenn ich gut in Excel bin :-))

ich habe eine MP3 Player mit der dyplayer Library am Arduino und will eine Wenn-Funktion laufen lassen aber es gibt scheinbar ein Problem: (ich weiß wie man eine Wenn Funktion erstellt...)

Beispiel allgemein:
Wenn X=1
player.playSpecified(3); // Da spielt der Player leider noch nicht los
delay(100000); // Erst hier spielt der Player für diese Zeit

Wenn X=0
player.stop();

delay(500);

Aber durch das delay(100000); (also abspielen des Songs) stoppt die Wenn-Funktion für diese Zeit und erreicht also die nächste Wenn.Funktion (X=0) nicht.

Wie könnte man das lösen?

Hab es schon mit eigenen void`s versucht aber das hat den gleichen Effect.

Vielen Dank

Hallo,

um es kurz zu machen, delay() blockiert an der Stelle im Code. Demzufolge muss man Methoden finden um einen Zeitunterschied festzustellen bzw. abzufragen wie man das früher (TM) mit der Armbanduhr gemacht hat. Ist Oldschool aber genau das Thema. Wie bildet man mit einer einzigen Zeitangabe Zeitdifferenzen. millis ist deine ewig laufende Zeit. Das einzig interessante daran ist zu wissen das man maximale Zeitdifferenzen von bis zu 49 Tagen bilden kann. Hausaufgabe :wink:, geh die Bsp. durch und lerne den Umgang damit. Damit kannst du dann alles quasi "Parallel" ablaufen lassen bzw. programmieren obwohl alles immer nacheinander abgefragt und entsprechend abgearbeitet wird je nachdem ob die "Pausenzeit" schon um ist oder nicht.

Theseus erklärt millis()

GuntherB - BlinkwithoutDelay - Die Nachtwächtererklärung

Beruht alles auf dem IDE Bsp.: 02.Digital -> BlinkwithoutDelay

Hallo,
ich denke schon das der Player hier anfängt zu spielen. Dein Problem ist vermutlich ehr die Wartezeit. Mit if(X==0) willst Du ja wieder ausschalten. Zeig Doch mal einen kleinen BeispielSketch bei dem das nicht Funktioniert.
Bedenke die Abfrage mit zwei == zu machen , bei einem = ist das eine Zuweisung und keine Abfrage.
Eventuell stimmt die Bedingung nicht und Du schaltest direkt wieder aus, und deshalb glaubst Du du benötigst das delay(100000),

if(x==1) {
player.playSpecified(3);
}
if(x==0){  // besser wäre hier noch else
player.stop();
}

Ansonsten gilt das was @Doc_Arduino bereits geschrieben hat

Das wäre super... aber auch ohne Wenn-Funktion spielt der bei player.playSpecified(3); nicht los...

Also Sinn ist, dass der spielt wenn ein Knopf gedrückt/losgelassen wird... das ist jetzt nur TestSketch...

#include <Arduino.h>
#include "DYPlayerArduino.h"

// Initialise the player, it defaults to using Serial.
DY::Player player;

// Alternatively initialise on another serial port.
// DY::Player player(&Serial);
int Volume=30;
int Delay=500;

int SoundPin_1=A1;
int V1=0;
int X1;
//_________________________________


void setup() {  
player.begin();
player.setVolume(Volume);
Serial.begin(9600);

pinMode(SoundPin_1,INPUT_PULLUP);
}
//_________________________________


void loop() {
V1=analogRead(SoundPin_1);
float X1=map(V1, 0,1023,0.,5.);
Serial.println(X1);

if (X1>4.0) {
player.playSpecified(5);
delay(100000);

}
if (X1<4.0) {
player.stop();
}                                                                                  



delay(Delay);

}

Das ist der BeispielSketch von dem Libraryersteller:

#include <Arduino.h>
#include "DYPlayerArduino.h"

// Initialise the player, it defaults to using Serial.
DY::Player player;

// Alternatively initialise on another serial port.
// DY::Player player(&Serial2);

void setup() {
  player.begin();
  player.setVolume(15); // 50% Volume
}

void loop() {
  player.playSpecified(1);
  delay(5000);
}

Ich denke das liegt daran das bei jedem Durchlaufen der void loop() Schleife die Bedingung X1>4.0 erfüllt ist und der Player von vorne anfängt zu spielen und du denkst der Player spielt nicht. Mit einem delay(100000) verhinderst du für die nächsten 100 Sekunden den Ablauf und der Player kann durchspielen.
Hier musst du mit einer Statusvariable das einmalige Starten des Player ermöglichen so das es beim nächsten Durchlaufen nicht erneut startet.
If (playerisplaying==false && x1>4.0) { start player, playerisplaying=true;}
und natürlich :

if (X1<4.0) {
player.stop();
playerisplaying=false;
}

Hallo, ich kenne auch die lib nicht , ich nutze normal die DFPlayer Lib
Hast Du mal ein Beispiel aus der Lib getestet.
warum liest DU den "Knopf" analog ein ?
Map geht auch nicht mit float Werten

wie ist denn der Player mit dem Arduino verbunden ? Sieht so aus als wenn das über die normale Serielle geht. Das geht so nicht, die willst Du ja für die Ausgabe auf dem Monitor nutzen. Eine Serielle Schnittstelle ist in dem Fall einen Punkt zu Punkt Verbindung und kein Bus. Je schnittstelle gehen zwei Teilnehmer.

Du solltest vermutlich eine zweite Serielle Schnittstelle nutzten. Wenn dein Arduino nur einen hat UNO / Nano dann musst Du eine Softserial nutzen.

Guter Gedanke , dann müsste es gehen wenn das delay am ende des loop steht

Hi @vadim86 ,

habe momentan keine Zeit, Dir konkret weiter zu helfen, aber die von Dir vermutlich genutzte Library

https://github.com/SnijderC/dyplayer/blob/main/src/DYPlayer.h

verfügt über eine Variable vom Typ play_state_t, über die man erkennen kann, ob der Player läuft, pausiert oder gestoppt wurde:

 typedef enum class PlayState : int8_t
  {
    Fail = -1, // UART Failure, can be a connection or a CRC problem.
    Stopped = 0,
    Playing = 1,
    Paused = 2
  } play_state_t;

Die Funktion dazu ist diese

    /**
     * Check the current play state can, be called at any time.
     * @return Play status: A [`DY::PlayState`](#typedef-enum-class-dyplay_state_t),
     *         e.g DY::PlayMode::Stopped, DY::PlayMode::Playing, etc.
     */
    play_state_t checkPlayState();

Mit

  if (player.checkPlayState() == Stopped) {
   // Hier alles, was im gestoppten Zustand laufen soll
  }
  if (player.checkPlayState() == Playing) {
   // Hier alles, was während des Abspielens laufen soll, z.B. das Reagieren auf eine Stopptaste
  }

sollte es in der loop() möglich sein, Funktionen, die nicht während des Abspielens betätigt werden sollen, auszuschliessen bzw. was während des Abspielens berücksichtigt werden soll.

So die Theorie, testen kann ich es leider nicht.

Vielleicht können Du oder ein anderer Forumteilnehmer das mal umsetzen ...

Viel Erfolg!
ec2021

Hallo,
probiere mal den hier (nicht getestet )

#include <Arduino.h>
#include "DYPlayerArduino.h"

bool ispalying;
const byte pinTaster = 2;// schalter auf Pin2
bool tasterstatus;

// Initialise the player, it defaults to using Serial.
// Serielle nicht für den Monitor nutzen
DY::Player player;

// Alternatively initialise on another serial port.
// DY::Player player(&Serial2);

void setup() {
  pinMode(pinTaster, INPUT_PULLUP);
  player.begin();
  player.setVolume(15); // 50% Volume
}

void loop() {

  tasterstatus = !digitalRead(pinTaster);
  if ( tasterstatus && !isplaying) {
    isplying = true;
    player.playSpecified(1);
  }
  if (!tasterstatus) {
    player.stop();
    isplying = false;
  }
  delay(20) // Taster entprellen 
}

Hallo zusammen
VIELEN DANK FÜR DIE VIELEN HILFESTELLUNGEN!

Ich habe es mal für mich von den Bezeichnungen etwas umgeschrieben mit den Ansätzen von @Rentner und @ec2021 (ist eingentlich das gleiche, was @Rentner gemacht hat. Ich glaube für mich, als erstes Projekt, erstmal einfacher). Vielen Dank dafür. Jetzt verstehe ich besser.
Und stimmt: Wenn es im setup ist spielt der Befehlt
player.playSpecified(1);
auch ohne delay() ab.

Ich hoffe es so gebaut zu haben, dass wenn Schalter 1 betätig wird Sound 1 abspielt und wenn Schalter 2 betätigt wird Sound 2 abspielt. (Es werden paar Schalter am Ende sein...)

Ich kann es erst heute Abend testen. Aber auch wenn es klappt:
Was ist wenn Schalter 1 an ist und Schalter 2 gerückt wird? Spielt er dann die Musik von Schalter 2? Es muss jetzt nicht jeder erdenktliche Fall hier abdeckt sein, nur das Schlimmste.
Das ist ein Spaßprojekt (Remout Controller aus Zurück in die Zukunft) was ich selten einschalten werde :slight_smile:

PS: Verstehe ich es richtig?:
ein "!" vor der Variable --> false (man spart sich also das ==false?)
keine "!" vor der Variable --> true (man spart sich also das ==true?)

#include <Arduino.h>
#include "DYPlayerArduino.h"

DY::Player player;

const byte SoundPin_1 = A1;
const byte SoundPin_2 = A2;

bool SoundPin_1_Status;
bool Playing_1_Status;
bool SoundPin_2_Status;
bool Playing_2_Status;



void setup() {
  pinMode(SoundPin_1, INPUT_PULLDOWN);
  pinMode(SoundPin_2, INPUT_PULLDOWN);
  
  player.begin();
  player.setVolume(15); // 50% Volume}

  void loop() {
    SoundPin_1_Status = !digitalRead(SoundPin_1);
    SoundPin_2_Status = !digitalRead(SoundPin_2);
   
    if (SoundPin_1_Status==true && Playing_1_Status==false) { //oder=!=false)
      player.playSpecified(1);
      Playing_1_Status = true;
    }
    if (SoundPin_2_Status==true && Playing_2_Status==false) { //oder=!=false)
      player.playSpecified(2);
      Playing_2_Status = true;
    }
    
    
    if (SoundPin_1_Status==false) {
      player.stop();
      Playing_1_Status = false;
    }
     if (SoundPin_2_Status==false) {
      player.stop();
      Playing_2_Status = false;
    }
    delay(20); // Taster entprellen }
  }

! liest man als not (auf deutsch nicht).

!digitalRead(Pin) liest sich dementsprechend "not digitalRead(Pin)".

Das ! invertiert einen logischen Wert (also z.B. den einer boolschen Variablen, die entweder den Wert "true" oder den Wert "false" einnehmen kann).

boolean istOk = true;  // hier wird der Wert false zugewiesen 
boolean nichtOk = !istOk; // nichtOk wird der inverse Wert von istOk zugewiesen, hier als  "nicht true" = false

Hallo,

wegen der Frage "oder=!=false"

Wenn man sich vor Tippfehler schützen möchte dreht man die Beteiligten um. Die Konstante links.
Damit erzeugt man einen Compilerfehler wenn man statt == nur = schreibt. Weil man der Konstante nicht zuweisen kann.

if (true = SoundPin_1_Status && false = Playing_1_Status) // absichtlich Tippfehler

Wenn man auf 'true' abfragt, kann man den Vergleich auch weglassen.

if (SoundPin_1_Status && false == Playing_1_Status)

Das kann man noch kürzen auf

if (SoundPin_1_Status && !Playing_1_Status)

Je nach eigenen optischen Gefallen. Hin und wieder sind Klammern für die Lesbarkeit auch ganz nett.

1 Like

nein.
Ein ! (Rufezeichen) dreht den logischen Zustand um.
Eine Bedingung ( in if, while dowhile for ecc) wird "ausgerechnet" . Das Ergebnis ist dann je nach Vergleich logisch 0 (falsch ) oder logisch 1 (richtig).
Eine Bedingung wird ausgeführt wenn die Bedingung logisch 1 ist. Mann kann sich den Vergleich sparen wenn die Variable 0 oder 1 zurückgibt.
ZB gibt digitalRead(pin) eines Eingangs ein 0 oder ein 1 zurück je nachdem obe der Eingang auf Masse oder auf Versorgungsspannung geschaltet ist. Diesen Rückgabewert kann man direkt als Bedingung verwenden ohne kontrollieren zu müssen ob der Rückgabewert 1 ist

Also
"digitaleRead(pin)"
ist das gleiche wie
(digitalRead(pin) == 1)
und
"!digitaleRead(pin)"
ist das gleiche wie
(digitalRead(pin) == 0) oder (!digitalRead(pin) == 1)

Zahlen verschieden von 0 werden als wahr interpretiert.

Grüße Uwe

Edit Hab etwas zu ungenau gelesen darum das Entfernen des "nein".

Der Tip mit dem rumdrehen der Konstante gefällt mir. Danke :slightly_smiling_face:

Falls Du mal mit JAVA zu tun hast, hilft diese Variante auch in einigen Fällen Null-Pointer-Exceptions zu verhindern, indem man die Methoden der konstanten Klasse nutzt.

Gruß Tommy

1 Like

Hallo zusammen,

das klappt leider nicht. So gehts nur mit einem Delay. Das mit dem Playing_1_Status müsste aber eigentlich funktionieren: Das ist dann
SoundPin_1 Status=1
Playing_1_Status=1

Danach im loop gibts doch nichts,was es aufhalten kann?

#include <Arduino.h>
#include "DYPlayerArduino.h"

//DY::Player player;
DY::Player player(&Serial1);

const byte SoundPin_1 = A1;
const byte SoundPin_2 = A2;

bool SoundPin_1_Status;
bool Playing_1_Status;
bool SoundPin_2_Status;
bool Playing_2_Status;

 typedef enum class PlayState : int8_t
  {
    Fail = -1, // UART Failure, can be a connection or a CRC problem.
    Stopped = 0,
    Playing = 1,
    Paused = 2
  } play_state_t;

void setup() {
  pinMode(SoundPin_1, INPUT_PULLUP);
  pinMode(SoundPin_2, INPUT_PULLUP);
  
  player.begin();
  player.setVolume(30); // 50% Volume}
  Serial.begin(9600);
}

void loop() {
    SoundPin_1_Status = !digitalRead(SoundPin_1);
    SoundPin_2_Status = !digitalRead(SoundPin_2);
    Serial.print(SoundPin_1_Status) & Serial.println(Playing_1_Status);

    if (SoundPin_1_Status==1 && Playing_1_Status==0) {
      Playing_1_Status = 1;
      player.playSpecified(1);
      //delay(10000) --> NUR DANN GIBS MUSIK
    }
    if (SoundPin_2_Status==1 && Playing_2_Status==0) {
      Playing_2_Status = 1;
      player.playSpecified(3);
      //delay(10000) --> NUR DANN GIBS MUSIK
    }
    
    
    if (SoundPin_1_Status == 0) {
      player.stop();
      Playing_1_Status = 0;
    }
     if (SoundPin_2_Status == 0) {
      player.stop();
      Playing_2_Status = 0;
    }
    delay(20); // Taster entprellen }
}

Ahhhh! Sorry, das ist das Problem. SoundPin_1 ist zwar bei 1 aber SoundPin_2 ist ja bei 0, daher stop der. Wie könnte man das aushebeln?

Was mich eigentlich auch wunder, ist das wenn man den Knopf druckt es paar Sekunden daher bis die Musik spielt? Ist das üblich bei den MP3 Playern?

    if (SoundPin_1_Status == 0) {
      player.stop();
      Playing_1_Status = 0;
    }
     if (SoundPin_2_Status == 0) {
      player.stop();
      Playing_2_Status = 0;

Hallo,

ich habe leider keinen DF Player mehr zum testen , ist also alles ungetestet.
das wird so nix,
nehmen wir mal an der schalter 1 ist ein und die Datei1 wird abgspielt, dann ist ja der schalter2 aus und damit wird gleich wieder gestoppt.

Es würde sicher gehen wenn du den playing_x_Status noch mit logisch und verknüpfst. Sorry das mit dem ! hast du ja inzwischen mitbekommen

if ( !SoundPin_1_Status && Playing_1_Status) {   // Schalter ist jetzt aus war aber ein
     player.stop();
     Playing_1_Status = false;
  }

Wenn während 1 gespielt wird 2 eingeschaltet wir dann sollte auch zwei gespielt werden , allerdings muss in dem Fall der Status von 1 auf false gesetzt werden, und natürlich umgekehrt.

if (SoundPin_2_Status==true && Playing_2_Status==false) { //oder=!=false)
      player.playSpecified(2);
      Playing_2_Status = true;
      Playing_1_Status = false;
    }

Mal einen Vorschlag wenn Du viele Schalter verwenden willst. Bau noch eine kleine Anzeige dazu. und einen Taster der zählt bei jedem drücken einen hoch von 1-20. Und mit Schalter startetst du. dann . der Schalter kann naturlich auch ein Taster sein der einen Status toggelt. Auf der Anzeige kannst Du dann anzeigen was abgespielt wird, die Lautstärke , und sicher noch einiges mehr. natürlich kannst Du auch einen Drehencoder zur Auswahl nehmen.

Nein eigentlich nicht, Es wird ein paar ms dauern da das ja seriell übertragen wird. Ich sehe aber ehr das Problem bei der MP3 Datei, wie lange Stille ist denn da am Anfang.

Du solltest Dir das Beispiel mit der Softseriell aus der lib ansehen und die verwenden, damit Du die normale Serielle Schnittstelle frei bekommst und Deinen Sketche auch debuggen kannst mit dem Monitor der IDE.