Frage do-while

Moin,

kleine Frage zur Do - While schleife. Mein Programmierbackround bezieht sich nur auf VB6 und bischen Java, daher bin ich mir bei der folgenden Problematik nicht so sicher.

Für mein aktuelles Projekt habe ich auf einem 20x4 LCD ein kleines Menu geschrieben, welches maximal 5 Eben tief geht und mit 3 Tastern gesteuert wird. Da ich keine bestehende Menu library benutzen möchte, zwecks Lerneffekt, hab ich mal selber begonnen.

Erst hab ich EINE Menu Funktion gebaut, die bei Tastendruck aufgerufen wird und mit do - while schleifen in den Eben umherspringt. Das geht auch alles wunderbar, nur ist die Funktion als ganzes extrem groß und sehr unübersichtlich. Also hab ich mir überlegt jede Menü Ebene in eine Extra Funktion auszulagern. Somit hat jede Funktion nur noch ein Abfragenblock für Tasteninput und reaktion und einen für LCD, macht das ganze viel übersichtlicher. Der normale Weg wäre nun wohl der, in jeder Funktion bzw. Ebene regulär aus der Do-While Schleife mit einer Ausgangsbedingung bei Tastendruck auszubrechen. Wenn ich nun aber zB. Aus der 5. Ebene mit der Exit/back Taste eine Ebene zurück möchte, der Exit Taster aber natürlich in jeder Ebene benutzt wird, würde ich bei einem Tasterdruck gleich alle Ebenen durchlaufen und sofort wieder verlassen. Also Sichtbar von Ebene 5 auf die Hauptebene springen. Das ist natürlich nicht gewollt. Delays möchte ich nicht haben, also hab ich Ausgangsvariablen benutzt, die erst aktiviert werden wenn der Exit/back Taster einmal losgelassen wurde. Somit muss man für jede Ebene einmal den Taster drücken und loslassen um die nächste Ebene zu erreichen. Dabei hab ich mir überlegt das ich die Ausgangsvariablen nicht zwingend brauche, zumindest nicht in der Fülle, wenn ich nicht aus der Schleife mit einer erfüllten Ausgangsbedingung gehe, sondern indem ich direkt die nächste Funktion aufrufe. Leider bin ich gerade auf der Arbeit und hab den Code nicht hier, aber ich werde das einmal kurz schematisch beschreiben. Syntax bitte nicht beachten, hab mich auf das konzentriert was zum Verständniss notwenig ist.

Void Menu()

Lcd.print "menu blabla"

do{ if button1 (btnPin, HIGH){

} } While(unwichtig da nicht benutzt)


Void Untermenu()

Lcd.print "untermenu blabla"

do{ if button1 (btnPin, HIGH){

} } While(unwichtig da nicht benutzt)

Ich hoffe es ist klar geworden was mir unklar ist: Ist es problematisch wenn ich eine do-while Schleife nicht mit der Ausgangsbedingung verlasse sondern zwischen den Funktionen hin und herspringe? Bleibt da irgendwo im Speicher was von den nicht beendeten Schleifen hängen?

Bisher funktioniert das ohne Probleme, nur weiss ich eben nicht was genau im Hintergrund passiert bzw. nicht passiert.

Danke und Gruß,

Christian

Erstmal ist mir unklar, wofür du eine do { } while (unwichtig); Konstruktion brauchst ???
Ich hätte gedacht, eine Menu Software beseht darin, zu wissen wo im Baum man grade ist, und bei Tastendruck eine Funktion auszuführen und/oder danach woanders im Baum zu sein ( und die passende Anzeige aufs LCD zu bringen ) und fertig.

Wenn das while () einer do while nie wahr ist, kannst du das Ganze weglassen und gleich mit if (digitalRead( buttonPin)) anfangen ???

Oder geht es dir ums Entprellen und neue Aktion erkennen ?

Mein Programmierbackround bezieht sich nur auf VB6 und bischen Java

Der Unterschied ist, dass du hier ein Programm schreibst das nie fertig wird, aber immer wieder aufgerufen wird, um in der Regel festzustellen, dass nichts zu tun ist.

Moin Michael,

kann sein das ich auch total falsch oder ungewöhnlich an die Sache Menu herangehe, das ist meine erste selbst programmierte Menuführung.

Der Begriff Entprellen ist mir zwar neu, aber nach kurzer Google suche meine ich nun zu wissen was es bedeutet. Quasi den Impuls durch das Tasten zeitlich zu begrenzen bzw. einzugrenzen, sodas nur in einer bestimmten Funktion der Impuls verarbeitet wird und nicht in der nächsten. Richtig?
Wenn ich das so ist, beantworte ich deine Frage mit ja. Genau deswegen brauche ich ja die Schleife und auch damit die neuen Tast-impulse regestriert werden.

Da ich nun Zuhasue bin poste ich mal den relevanten Code:

void loop()
{
  button3state = digitalRead(button3);
  
  if ((button3state == HIGH) && (button3preset == 1))
  {
    MainMenu();
  }
  else if (button3state == HIGH)
  {
    button3preset = 1;
  }
  
  ReadAndShow();


//-------------------------------------------------------------------

void MainMenu()
{
  button1set = 0; // reset der taster variablen
  button1preset = 0; 
  
  button2set = 0;
  button2preset = 0;
  
  button3set = 0;
  button3preset = 0;
  
  // --------------------- Menu anzeigen ----------------------------
  lcd.clear();
  lcd.print("**** MAIN MENU *****");
  lcd.setCursor(0, 1);
  lcd.print("Sensors  ->");
  lcd.setCursor(0, 2);
  lcd.print("SD Card  ->");
  lcd.setCursor(0, 3);
  lcd.print("Quit     <-");
  
  do // ------------------ Taster abfragen ------------------------------
  {
    button1state = digitalRead(button1);
    button2state = digitalRead(button2);
    button3state = digitalRead(button3);
     
     if ((button1state == HIGH) && (button1preset == 1)) // abfrage für taster 1
     {
       button1set = 1; // aufruf naechste ebene // aktion
     }
     else if (button1state == LOW)
     {
       button1preset = 1;
     }
     
     if ((button2state == HIGH) && (button2preset == 1)) // abfrage für taster 2
     {
       SDcard(); // aufruf naechste ebene // aktion
     }
     else if (button2state == LOW)
     {
       button2preset = 1;
     }
     if ((button3state == HIGH) && (button3preset == 1)) // abfrage für taster 3
     {
       button3preset = 0;
       button3set = 1; // zurueck vorherige ebene
       
     }
     else if (button3state == LOW)
     {
       button3preset = 1;
     }
     delay(1);
   }
   while(button3set == 0);
}


// ---------------------------------------------------

void SDcard()
{
  button1set = 0; // reset der taster variablen
  button1preset = 0; 
  
  button2set = 0;
  button2preset = 0;
  
  button3set = 0;
  button3preset = 0;
  
  // --------------------- Menu anzeigen ----------------------------
  lcd.clear();
  lcd.print("***** SD CARD ******");
  lcd.setCursor(0, 1);
  lcd.print("interval  = ");
  lcd.print(timeset);
  lcd.setCursor(17, 1);
  lcd.print("min");
  lcd.setCursor(0, 3);
  lcd.print("Quit     <-");
  
  do // ------------------ Taster abfragen ------------------------------
  {
    button1state = digitalRead(button1);
    button2state = digitalRead(button2);
    button3state = digitalRead(button3);
     
     if ((button1state == HIGH) && (button1preset == 1)) // abfrage für taster 1
     {
       button1set = 1; // aufruf naechste ebene // aktion
     }
     else if (button1state == LOW)
     {
       button1preset = 1;
     }
     
     if ((button2state == HIGH) && (button2preset == 1)) // abfrage für taster 1
     {
       button2set = 1; // aufruf naechste ebene // aktion
     }
     else if (button2state == LOW)
     {
       button2preset = 1;
     }
     
     if ((button3state == HIGH) && (button3preset == 1)) // abfrage für taster 1
     {
       button3preset = 0;
       MainMenu();
     }
     else if (button3state == LOW)
     {
       button3preset = 1;
     }
     delay(1);
   }
   while(button3set == 0);
}


}

Mir geht es um den Vorgang aus dem MainMenu in das SD menu und wieder zurück.

Vermutlich war mein Ansatz zu Objektorientiert also bezogen auf das Menu. Wie auch immer, meine ursprüngliche Frage bleibt allerdings noch bestehen. Bekomme ich irgendwelche Probleme wenn ich aus der Schleife eine neue Funktion aufrufe und aus der neuen wieder zurück springe?

Grüße

Bleibt da irgendwo im Speicher was von den nicht beendeten Schleifen hängen?

Von den Schleifen nicht, aber von den Sub-Routinen: die Rücksprungadresse auf dem Stack. Wenn Du dort wild herumspringst baut sich der Stack langsam (oder auch etwas schneller) auf und Dir (oder besser Deinem Arduino) wird bald der Speicher (RAM) ausgehen.

While(unwichtig da nicht benutzt)

Das "unwichtig, da nicht benutzt" kann ich nicht nachvollziehen, das wird sehr wohl benutzt.

Was Du wahrscheinlich brauchst, ist eine State Machine. Das ist eigentlich nichts mehr als eine Variable, die den aktuellen Status festhält. In der Hauptschleife (loop) machst Du dann je nach Wert dieser Variable andere Sachen. Einige davon können ein Statuswechsel, als ein Verändern dieses Werts sein.

Pseudocode:

uint8_t status = 0;
loop() {
  if (status == 0) {
    // könnte zum Beispiel das Hauptmenü sein
    if (buttonpress == 2) {
      status = 1;
    }
  } else if (status == 1) {
    // könnte das Untermenü sein
    if (buttonpress == 1) {
      status = 0; // zurück zum Hauptmenü
    }
  }
}

Bekomme ich irgendwelche Probleme wenn ich aus der Schleife eine neue Funktion aufrufe und aus der neuen wieder zurück springe?

Nein.
Mit "aus der Schleife" meinst du, dass du innerhalb von void loop() { /* d.h. hier irgendwo */ }
eine Funktion aufrufst, wie z.B. MainMenu();

Das Zurückspringen geschieht von allein am Ende, oder sobald der Befehl return; aufgeführt wird. Man landet stets hinter dem Aufruf der Funktion, und der Speicherzustand (Stack) ist wieder so wie vorher.
pylons Kommentar ist sicher nicht so furchterregend gemeint.

Innerhalb von MainMenu kannst du durchaus weitere Unterfunktionen aufrufen. Das ist ja Sinn der Sache.
Schwierig wird es nur, wenn du wieder MainMenu() selbst aufrufst. Das geht nur selten gut, denn unendliche Schachtelungstiefe geht natürlich nicht.

loop() ist übrigens selbst eine normale Funktion, mit dem einzigen Unterschied, dass die von der Arduino IDE drumherum gebaute Umgebung so funktioniert, dass loop() auf jeden Fall existieren muss und immer wieder neu aufgerufen wird.

Moin,

danke für die Antworten.

Ja, hatte ich vermutet das irgend sowas wie eine backpath hängen bleibt. Hab mir mal den RAM bei jedem "Sprung" anzeigen lassen, ging wirklich fix bis die paar Bytes voll sind :smiley: Also insofern war der Kommentar von Pylon genau richtig.