![]() |
|
Ein Automat ohne delay()Es gibt zwei Fragestellungen, die im Arduinoforum immer wieder auftauchen:
Frage eins hat meistens damit zu tun, dass jemand mehrere Vorgänge gleichzeitig ablaufen lassen möchte. Mit delay() erzeugte Pausen sind hierfür Gift. Die zweite Frage lässt sich oft mit dem Modell eines „endlichen Automaten“ (eine Art Strickmuster) beantworten. Ein endlicher Automat heißt so, weil er eine endliche Zahl von Zuständen annehmen kann. In Kurzform kann man die „Mechanik“ eines endlichen Automaten so beschreiben: Ein Vorgang wird in mehrere Schritte aufgeteilt, die benannt werden. Im weiteren Verlauf werden diese Schritte abgearbeitet, wobei am Ende jedes Schrittes zum nächsten „weitergeschaltet“ wird. Anstatt für zeitliche Strukturen delay() zu verwenden, wird mit millis() gearbeitet. Die Funktion millis() gibt die Zahl der seit dem Einschalten des Arduinos vergangenen Millisekunden zurück. Wenn man sich den Startzeitpunkt eines Ablaufs merkt, kann man die Laufzeit mittels Differenzbildung errechnen. Das Problematische an delay() ist, dass es den Prozessor blockiert. Mit der Abarbeitung weiterer Abläufe wird erst fortgefahren, wenn die mit delay() erzeugte Pause vorbei ist. Eine Frage, anhand der sich die Vermeidung von delay() und ein endlicher Automat erläutern lassen, lautet: Wie kann ich eine Blinksequenz so ablaufen lassen, dass nebenher weitere Dinge erledigt werden können? Die hier beispielhaft realisierte Blinksequenz lässt sich am besten mit „blinkblink … blinkblink … blinkblink …“ beschreiben – also ein wiederholtes zweifaches Blinken, gefolgt von einer etwas längeren Pause. Diese Blinksequenz kann man in vier Phasen gliedern:
Jede Phase bekommt einen „Namen“, den man in einer Aufzählungsvariable (enum) definiert. Die Dauer der Phasen ist in einer Feldvariable (array) festgelegt. In loop() wird in einer switch-Anweisung der Code angesprungen, der mit der aktuellen Phase der Blinksequenz zusammenhängt. Da das Fortschreiten zur nächsten Phase im Code einer Phase passiert, entscheidet der Code einer Phase sozusagen selbst, wann zur nächsten Phase weitergeschaltet wird. Der Einsatz von switch() ist nicht immer die beste oder verständlichste Konstruktion. Je nach Aufgabe kann ein if()-Konstrukt die bessere Wahl sein. Wer schon ein bisschen programmieren kann, wird mit dem folgenden Code kaum Schwierigkeiten haben:
// Blinken ohne delay() Eine ordentliche switch-Anweisung hört eigentlich mit einem „default:“-Abschnitt auf. Der Übersichtlichkeit wegen habe ich diesen Abschnitt hier weggelassen. Achtung: Da die Funktion millis() einen Wert zurückgibt, der 32 Bit breit ist, kann es je nachdem, wie man die Bedingung formuliert, nach rund 49 Tagen zu Überlaufproblemen kommen. Natürlich gibt es zum Modell des endlichen Automaten auch einen Artikel in der Wikipedia (siehe hier). Ich finde diesen Artikel allerdings ziemlich trocken und halte ihn für schwer nachvollziehbar. Eine andere Erklärung, wie man zu einem endlichen Automaten kommt, befindet sich hier. Weiter zu: Pimp my Code!
|