Читать книгу Mit Arduino die elektronische Welt entdecken - Erik Bartmann - Страница 131
Den Code verstehen
ОглавлениеIn diesem Sketch haben wir es mit einigen Variablen zu tun. Ich beginne mit der sogenannten Intervallsteuerung. Das folgende Impulsdiagramm zeigt uns das Verhalten der Schaltung und es ist genau so, wie es erwünscht ist:
Abb. 4: Das Impulsdiagramm der Signale an Pin 13, Pin 8 und Pin 10
Jedes Mal, wenn der Taster (Taster-Pin) gedrückt wird, folgt der Pegel der Taster-LED. Und das Ganze unabhängig vom Zustand beziehungsweise Pegelwechsel an Pin 13 (Blink-LED). Für die Intervallsteuerung benötigen wir eine neue Funktion, die sich millis nennt und wie folgt aussieht:
Sie liefert einen Wert in Millisekunden seit dem Starten des Sketches zurück. Dabei ist etwas Wichtiges zu beachten: Der Rückgabedatentyp ist unsigned long, also ein vorzeichenloser 32-Bit-Ganzzahltyp, dessen Wertebereich sich von 0 bis 4.294.967.295 (232-1) erstreckt. Dieser Wertebereich ist so groß, weil er über einen längeren Zeitraum (maximal 49.71 Tage) in der Lage sein soll, die Daten aufzunehmen, bevor es zu einem Überlauf kommt.
Was ist ein Variablenüberlauf?
Ein Überlauf bedeutet bei Variablen, dass der maximal abbildbare Wertebereich für einen bestimmten Datentyp überschritten wurde und anschließend wieder bei 0 begonnen wird. Für den Datentyp byte, der eine Datenbreite von 8 Bits aufweist und demnach 28 = 256 Zustände (0 bis 255) speichern kann, tritt ein Überlauf bei der Aktion 255 + 1 auf. Den Wert 256 ist der Datentyp byte nicht mehr in der Lage zu verarbeiten.
Es wurden drei weitere Variablen eingefügt, die folgende Aufgabe haben:
interval: Nimmt die Zeit im ms auf, die für das Blinkintervall zuständig ist.
prev: Nimmt die aktuell verstrichene Zeit in ms auf. prev kommt von previous und bedeutet übersetzt vorher.
ledStatus: In Abhängigkeit des Status von HIGH oder LOW der Variablen wird die Blink-LED angesteuert.
Dann sehen wir mal, wie das Ganze so abläuft. Das folgende Diagramm soll den zeitlichen Verlauf der Intervallsteuerung verdeutlichen:
Abb. 5: Der zeitliche Verlauf der Intervallsteuerung
Ich analysiere einmal das Diagramm, wobei ich markante Zeitpunkte zur Verdeutlichung herausgegriffen habe. Natürlich läuft die Zeit nicht real in diesen Schritten ab:
Tabelle 2: Variableninhalte im zeitlichen Verlauf | |
Zeitpunkt | Erklärung |
---|---|
Es wird die aktuelle Zeit (in diesem Fall 1000) in Millisekunden in die Variable prev übernommen. Dies erfolgt einmalig in der setup-Funktion. Die Differenz millis() – prev liefert als Ergebnis den Wert 0. Dieser Wert ist nicht größer als der Intervallwert 2000. Die Bedingung ist nicht erfüllt und der if-Block wird nicht ausgeführt. | |
Weitere 1000ms später wird wieder die Differenz millis() – prev gebildet und das Ergebnis dahingehend überprüft, ob es größer als der Intervallwert 2000 ist. 1000 ist nicht größer 2000, also ist die Bedingung wieder nicht erfüllt. | |
Nochmals 1000ms später wird erneut die Differenz millis() – prev gebildet und das Ergebnis darauf überprüft, ob es größer als der Intervallwert 2000 ist. 2000 ist nicht größer 2000, also ist die Bedingung wieder nicht erfüllt. | |
Nach 3001ms Laufzeit erbringt die Differenz jedoch einen Wert, der größer als der Intervallwert 2000 ist. Die Bedingung wird erfüllt und der if-Block zur Ausführung gebracht. Es wird der alte prev-Wert mit dem aktuellen Zeitwert aus der millis-Funktion überschrieben. Der Zustand der Blink-LED kann umgekehrt werden. Das Spiel beginnt auf der Basis des neuen Zeitwertes in der Variablen prev von vorn. |
Während des gesamten Sketch-Ablaufs wurde an keiner Stelle im Quellcode ein Halt in Form einer Pause eingelegt, sodass das Abfragen des digitalen Pins 8 zur Steuerung der Taster-LED nicht beeinträchtigt wurde. Ein Druck auf den Taster wird fast unmittelbar ausgewertet und angezeigt.
Eine Zeile im Sktech könnte vielleicht noch ein wenig Kopfschmerzen bereiten. Was bedeutet ledStatus = !ledStatus? Und was heißt toggeln, wie ich es im Kommentar hinter dem Befehl genannt habe? In der Variablen ledStatus wird der Pegel gespeichert, der die rote LED ansteuert oder für das Blinken zuständig ist (HIGH bedeutet aufleuchten und LOW bedeutet dunkel). Über die nachfolgende Zeile wird die LED dann angesteuert:
digitalWrite(ledPinBlink, ledStatus);
Das Blinken wird gerade dadurch erreicht, dass du zwischen den beiden Zuständen HIGH bzw. LOW hin- und herschaltest. Das wird auch Toggeln genannt. Ich werde die Zeile etwas umformulieren, dann wird der Sinn deutlicher:
if(ledStatus == LOW) ledStatus = HIGH; else ledStatus = LOW;
In der ersten Zeile wird abgefragt, ob der Inhalt der Variablen ledStatus gleich LOW ist. Falls ja, setze ihn auf HIGH
andernfalls auf LOW
. Das bedeutet ebenfalls ein Toggeln des Status. Viel kürzer geht es mit der folgenden einzeiligen Variante, die ich im Sketch verwendet habe:
ledStatus = !ledStatus; // Toggeln des LED-Status
Ich benutze dabei den logischen Not-Operator, der ja durch das Ausrufezeichen repräsentiert wird. Wie wir schon in Kapitel 3 gelernt haben, wird er häufig bei booleschen Variablen verwendet, die nur die Wahrheitswerte true oder false annehmen können. Der Not-Operator ermittelt ein Ergebnis, das einen entgegengesetzten Wahrheitswert aufweist wie der Operand. Es funktioniert aber auch bei den beiden Pegeln HIGH und LOW. Am Schluss wird ganz normal und ohne Verzögerung der Taster an Port 8 abgefragt:
tasterStatus = digitalRead(tasterPin); if(tasterStatus == HIGH) digitalWrite(ledPinTaster, HIGH); else digitalWrite(ledPinTaster, LOW);