While Schleife frühzeitig verlassen

Hallo liebe Community,

ich habe mal wieder ein paar kleine Hürden zu meistern. Für einen Testaufbau (Master-Slave) arbeite ich mit einer Switch Case Anweisung, darin verschachtelt eine While Schleife. Der Master sendet an den Slave alle 500ms einen Wert, jedoch ändert der Slave seinen Case immer erst wenn die While Schleife durchlaufen ist, obwohl ich im While Schleifenkopf eine Bedingung definiert habe, die nicht mehr stimmt. Selbst wenn ich in der While Schleife eine IF Anweisung einfüge mit dem Break Befehl passiert nichts.

Nur zum Verständnis, bitte korrigiert mich, wenn ich falsch liege. Sobald der Master sendet, bleibt der Slave im Programm stehen, empfängt die Daten und macht dann an der Stelle im Sketch weiter?!

Hier mal Auszüge aus beiden Codes:

Master

  if(zone == 3){
    Wire.beginTransmission(3);
    Wire.write(modus);
    Wire.write(stufe);
    Wire.write(eta);
    Wire.write(sup);
    Wire.endTransmission();
  }
  
  delay(500);

Slave

void setup() {
  Wire.begin(3);            // Tritt dem Datenbus mit der Adresse 3 bei
  Wire.onReceive(konfig);   // Registriert Konfiguration vom Master

  ...
}


void loop() {

  switch(modus){
    case 0:                         // PAUSE
      ...
      break;
    
    case 1:                         // WRG Modus
      ...
      break;
    
    case 2:                         // DL Modus
      digitalWrite(led_wrg, LOW);             // Im DL Modus WRG LED aus
      digitalWrite(led_dl, HIGH);             // Im DL Modus DL LED an

      while(zeit < 70 && modus == 2){
        zeit++;
        analogWrite(fan_1_eta, eta);          // Ventilator 1 ETA Betrieb mit definierter Abluftstufe
        analogWrite(fan_1_sup, 0);            // Ventilator 1 SUP Aus
        analogWrite(fan_2_eta, 0);            // Ventilator 2 ETA aus
        analogWrite(fan_2_sup, sup);          // Ventilator 2 SUP Betrieb mit definierter Zuluftstufe 
        delay(1000);                          // 1 Sekunde
      }
      zeit = 0;                               // Timer Zurücksetzen
      temp = 0;  
      break; 
  }
}

void konfig(int data){          // Konfiguration vom Master
  modus = Wire.read();          // Sendet Betriebsmodus vom Master
  stufe = Wire.read();          // Sendet Reglerstufe vom Master
  eta = Wire.read();            // ETA Stufe
  sup = Wire.read();            // SUP Stufe
}

Kurz zum Ablauf: Der Master sendet den Betriebsmodus (Modus), welcher ausgeführt werden soll. Dann springt der Slave in die entsprechende Case anweisung. Das funktioniert. Hier im Sketch für DL Modus dargestellt. Die anderen Modi sind ähnlich. Sobald ich aber vom Master den Modus ändere ist ja Modus nicht mehr ==2 und die Bedingung ist nicht mehr erfüllt. Jedoch bringt der die While Schleife zu ende (70s) und danach geht er erst in den neu definierten Modus.

Bitte sagt mir wo mein Denkfehler liegt, danke!

VG

while
if bedingung -> break

mit break kommst raus, aber wenn man so was braucht, sollte man überlegen, ob while das richtige ist ...

deine 3 Denkfehler(MZ) sind:

-die Verwendung des blockierende delay(1000);
-modus wird in der while nicht verändert, also kann es auch nicht als Abbruchbedingung während des While loop verwendet werden
-das wir hier mit Codeschnipseln sehen, was sich sonst im Code tut. poste IMMER einen minimal lauffähigen code den wir evtl. selber auf ein Target hochladen können. Er soll nur so kurz sein, wie unbedingt notwendig. 90% der Fälle wirst du dann lösen können, während du den Sketch für uns reduzierst - garantiere ich dir!

Okay das versteh ich, ich habe den Code nur kurz gehalten, damit es übersichtlich bleibt. Weil im prinzig die anderen Modi genauso aufgebaut sind.
Im Kopf der While wird doch der Modus mit seiner Bedingung festgelegt:

while(zeit < 70 && modus == 2)

Wenn ich durch erneutes senden vom Master den Modus auf Beispielsweise modus == 0 schalte, ist doch die Bedingung nicht mehr erfüllt, jedoch wird die Schleife weiter ausgeführt. Da steh ich auf dem Schlauch.
Ich nutze die Variable Modus einmal im Case und einmal in der Bedingung der While Schleife. Sollte man das lieber nicht tun und zwei verschiedene Variablen nehmen?

while(zeit < 70 && modus == 2)

Wenn ich durch erneutes senden vom Master den Modus auf Beispielsweise modus == 0 schalte, ist doch die Bedingung nicht mehr erfüllt, jedoch wird die Schleife weiter ausgeführt.

nein falsche Beobachtung.
Du springst bei zeit <70 und modus == 2 in die While UND BLEIBST DORT bis 70 erreicht ist.
Ich sehe im loop keinen Code wie sich modus IN DER SCHLEIFE ändern würde.

Bau dir ein serial.println(modus) ein, dann wirst du es sehen. Das wäre sowieso praktisch das Serial.print Ausgaben eine gute debug-Möglichkeit ist.

Konnte das Problem lösen. Vielen Dank.

Kommando zurück, die Freude war leider doch etwas verfrüht. Ich habe wie du mir empfohlen hast in jeden Case eine Serial.Print(modus) eingefügt, um zu sehen, ob sich der Modus in der Schleife ändert. Das hat auch Prima geklappt. JEDOCH als ich den Sketch "bereinigt" habe, sprich den Serial.print wieder entfernt habe und nochmap probierte, ging es nicht mehr...nachdem ich ihn wieder eingefühgt habe ging es wieder.

Also jetzt bin ich endgültig verwirrt.

VG

in jeden Case eine Serial.Print(modus) eingefügt,

Wire.onReceive(konfig);
konfig ist hier eine ISR und damit sind auch alle Sonderbehandlungen für ISR fällig.

  • kein Serial.print
  • kein delay
  • volatile Übergabe der Daten/Variablen
  • Atomares auslesen.

Du hast in loop() schon eine Schleife. Du solltest das Programm eher so betrachten dass loop() ständig durchläuft und jeder Durchlauf einen aktuellen Zustand darstellt. Und statt delay() Zeiten mit millis()/BlinkWithoutDelay machen. Dann kann man mehrere Dinge nebeneinander erledigen

Hast Du Arrays die über den Index hinausgehen?
grüße Uwe

Also ich habe jetzt nochmal ein wenig im Sketch experimentiert und es liegt einfach an der "blöden" Delay Funktion. Wenn ich diese deaktivere, dann nimmt der Slave alle Befehle vom Master sofort und ohne Verzögerung entgegen und setzt sie um. Soweit Prima.
ABER, da meine Programmierkenntnisse recht überschaubar sind, tue ich mich gerade schwer mit der millis Funktion einen Timer zu realiesieren, welcher sich alle 70s zurücksetzt.

Ich möchte Realiseren, dass der Ventilator alle 70s seine Drehrichtung ändert. Daher war es für sehr einfach dies mit der delay Funktion zu bewerkstelligen...

Dann schau Dir BlinkWithoutDelay und die Nachtwächtererklärung an.

Gruß Tommy

ABER, da meine Programmierkenntnisse recht überschaubar sind, tue ich mich gerade schwer mit der millis Funktion einen Timer zu realiesieren, welcher sich alle 70s zurücksetzt.

Das ist der/ein Hügel der Erkenntnis.
Da mussten/müssen wir alle drüber, und jetzt bist du dran.

Wenn er so vor einem liegt, sieht er viel größer aus, als wenn man oben steht und einen das "Aha" Erlebnis gefunden hat.

Ablaufsteuerung
Meine Standardantwort zu Ablaufsteuerungen:

Eine Stichworte Sammlung für Google Suchen:
Endlicher Automat,
State Machine,
Multitasking,
Coroutinen,
Ablaufsteuerung,
Schrittkette,
BlinkWithoutDelay,

Blink Without Delay
Die Nachtwächter Erklärung

Intervall Macro
Multitasking Macros
INTERVAL Ersatzstoff
CooperativeTask

Das konnte ich mir schon denken, dass ich diese Hürde meistern muss :slight_smile:
Macht ja auch Sinn, da ich in Zukunft sicher noch viel öfter mit dieser Thematik konfrontiert werde. Bin schon seint heute früh am rechachieren! Aber nochmal danke für den Denkanstoß!

Man kann sich das Leben auch etwas einfacher machen, wenn man den MoToTimer der MobaTools benutzt. Insbesondere wenn es nicht um regelmäßig wiederkehrende Intervalle, sondern um asynchron gestartete Zeitabläufe geht, erleichtert die 'expired' Methode das Leben. Die wird beim Ablauf der vorher gestarteten Zeit genau 1x wahr. Damit kann man dann ganz leicht etwas auslösen, dass nach Ablauf der Zeit gestartet werden muss.
Wer die MobaTools nicht komplett installieren will, kann sich auch die MoToTimer.h kopieren - da ist alles notwendige drin.
Das Grundprinzip des Nachtwächters ändert sich dadurch zwar nicht, aber nach meinen Erfahrungen und Rückmeldungen ist es einfacher und übersichtlicher als das direkte Hantieren mit den millis().

Also um die ganze Thematik mal abzuschließen. ich habe in meinem Sketch alle Delays verbannt und durch die Millis Funktion ersetzt. Funktioniert super und erlaubt mir dadruch auch ganz neue Möglichkeiten. Das ist echt Prima. Somit funktioniert jetzt auch die Master-Slave-Kommunikation fehlerfrei und alle machen das was sie sollen.

Mein nächste Herausforderung wird eine Kommunikation zwischen Arduino und einem Sensor über RS232...aber das hebe ich mir für einen anderen Tag auf :slight_smile: