Kann ich die Ausführung der loop() Methode unterbrechen?

Liebe Arduino nerds,

ich habe eine 8x32 LED Matrix, deren Features in verschiedene Modi unterteilt sind. Ich navigiere durch die entsprechenden Modi mit Hilfe von 2 Buttons. Ein Button erhöht die Zählvariable “volatile byte mode = 0” um 1, während der andere sie um 1 verringert. Die Überprüfung, welcher der beiden Knöpfe gedrückt wurde, befindet sich in der checkMode() Methode. Die variable “mode” ist volatile, damit ich sie, falls nötig, auch über eine ISR abändern kann. Momentan frage ich den Modus jedoch in meinem loop ab.

Jedes Mal wenn ein Knopf gedrückt wurde, wird ein Interrupt ausgelöst. Die ISR dafür ist jedoch, aufgrund meines Problems, noch nicht implementiert.

void loop() {

  checkMode();
  Serial.println(mode);

  switch (mode) {
    case 0:
      mode0();
      break;
    case 1:
      mode1();
      break;
    case 2:
      mode2();
      break;
  }

}

Hier also mein Problem: Der Lauftext, den ich in einer der Modi abspiele läuft erstmal vollständig ab, bevor die loop() Methode von Neuem anfängt und den richtigen Modus auswählt. Ich möchte jedoch den Modus direkt mit Drücken des entsprechenden Buttons umschalten. Gibt es also einen Befehl für meine ISR mit dem ich die loop() Methode unterbreche?

Kurz gesagt: Wenn ein Knopf gedrückt wird, soll die ISR dafür sorgen, dass die loop() Methode wieder von vorne anfängt. Damit wird das Durchlaufen der Laufschrift unterbrochen und der richtige Modus ausgewählt.

Disclaimer: Das letzte was ich programmiert habe war in Assembler. Dort könnte ich einfach ein Label an den Anfang setzen und darauf springen. Ich weiß, dass ein Interrupt dafür gedacht ist das Hauptprogramm kurz zu unterbrechen und danach wieder an die Stelle zurück zu kehren an der unterbrochen wurde.

Falls ihr meinen ganzen Code benötigt habe ich diesen als Anhang bereit gestellt.

Mfg. Pascal

Final.ino (11.9 KB)

Hallo Pascal,
schau Dir mal in Ruhe an, wie oft Deine checkMode()-Funktion [Umschaltung] drankommt, wenn mode1() [Text wird abgearbeitet] läuft. Ggf. helfen einige zusätzlicher Serial.print()-Aufrufe auch am Ende von modeX().

Da wird sich vielleicht ein Aha-Effekt einstellen.

Ich glaube nicht, dass eine ISR da helfen kann.

Gruß Walter

@TO: Eine ISR für Taster ist in 99,9% der Fälle der falsche Weg.
Du musst Deinen Loop so gestalten, dass er so schnell wie möglich durchlaufen wird.
Du suchst einen Endlichen Automaten (Finite State Machine).

Gruß Tommy

Für die Taster benötigst du keine ISR.
Also ein Problem weniger.

Dein abbrechen der Schleife, lässt sich durch endliche Automaten, ersetzen.

PS:
Doppelt gemoppelt hält besser.

Das ist der falsche Weg um loop() zu betrachten. Die Funktion sollte immer durchlaufen. Und entweder macht man in einem Durchlauf etwas oder nicht. In irgendeinen Modus zu schalten bedeutet nicht dass man dann eine Schleife o.ä. in einer anderen Funktion hat

Hallo,

Du brauchst mit absoluter Sicherheit keine ISR um die beiden Taster abzufragen. Nimm das mit in den Loop rein mit einer Flankenerkennung und Entprellung. Dann kannst Du vernünfig rauf und runter zählen. Mit dem von Dir angedachten select case verzweigst du dann in die entsprechen Programmteile.

Kann aber auch sein das ich Dein Problem nicht verstanden habe. Du kannst den loop doch so gestalten das nix passiert. if() geht gut . oder du baust eine Variable ein die du zurück setzt wann immer du willst. Letzlich hängt es davon ab wie du die Laufschrift steuerst. Davon sehen wir aber nichts.

was ist mode1(), mode2(),mode3(), für mich sind das drei funktionen ohne parameter.

Heinz

combie:
Doppelt gemoppelt hält besser.

Oder: Die Wiederholung ist die Mutter der Erkenntnis.

Gruß Tommy

Vielen Dank für eure Antworten!

Ich habe das Problem nun dadurch gelöst, dass ich den Modus innerhalb der Schleife meiner Laufschrift nochmals abfrage. Mir war bereits bewusst, dass das Abarbeiten der Schleife zu lange dauert aber ich habe mich davor gescheut, es mit einer weiteren Abfrage in der Schleife zu lösen, weil es mir nicht wie die eleganteste Lösung vorkam. Aber sind wir mal ehrlich, mein Code ist sowieso nicht elegant :^)

void mode1() {

  Serial.println("executing mode 1");

  for (int i = 0; i < message.length(); i++) {//runs as long as the input-string's length

    lc.makeColumns(symbols[message.charAt(i)], &textColumns0); //Examines a letter from the input-string and splits it into columns that are then stored in ByteBlock textColumns0

    for (int i = 0; i < 8; i++) { //runs the length of a ByteBlock
      checkMode();
      if(mode != 1){
        break;
      }
      lc.moveLeft(textColumns0[i]); //moves columns according to index
    }
  }
  
  Serial.println("DONE!!!!");
}

Ihr hattet recht damit, dass ich keinen Interrupt benötige… Was Finite State Machines damit zu tun haben erschließt sich mir jedoch immer noch nicht. Meine Zustände sind ja schon klar definiert und das Umschalten ist auch kein Problem solange die Programmlaufzeit des ensprechenden Modus nicht zu lange dauert.

Trotzdem vielen Dank für eure Hilfe!

mfg. Pascal

Mal ganz grob erklärt:

Du hast einen Status. z.B. 2 (Lauflicht)
Dann gehst Du in einem if (status == 2) lauflicht() in die Prozedur rein. Die schaut (über millis()) muss ich was tun: nein = return, ja tue einen Schritt + return

Damit hast Du immer den Zugriff auf alle Taster im Loop und kannst problemlos umschalten.

Gruß Tommy

for-Schleifen sind genau der falsche Weg. Du hast in loop() schon eine Schleife. Jede Schleife kann man daher durch if-Abfragen in loop() ersetzen. Und dann auch direkt auf andere Dinge reagieren

Das Problem ist, dass deine modex() blockieren.