Multitasking mit millis() statt delay()
Die delay()-Funktion wird in einem einfachen Programm ohne Verzweigungen verwendet um den Ablauf zeitweise zu
pausieren. (Bsp. LED an, Pause, LED aus, Pause, …) . Um den delay(500)- Befehl umzusetzen wird der µC veranlasst
wiederholt eine for-Schleife ohne zusätzliche Befehle zu durchlaufen. Solange bis die Anzahl der Durchläufe
multipliziert mit dem Prozessortakt dann 500ms ergibt. Der Prozessor ist die ganze Zeit über (sinnlos) beschäftigt
und kann dabei keine weiteren Aufgaben übernehmen (wie zum Beispiel einen Taster abfragen).
Abhilfe schafft ein Zeitstempel, welcher dann in einer if-Abfrage in jedem Loop überprüft wird ob dieser schon
erreicht wurde. Erst wenn die Zeit erreicht ist, werden die Befehle in der if-Verzweigung ausgeführt. millis() ist
übrigens ein Zähler, der ab dem Start oder Reset des Arduinos zu zählen beginnt.
Programmcode Möglichkeit 1 (nextTime)
Gleich innerhalb der if-Verzweigung wird die Zeit für die nächste Ausführung berechnet und in der Variablen 'nextTime' gespeichert. Dann wird bei jedem anschließenden 'Loop' Durchlauf geprüft ob die if-Bedingung mit der neuen Zeit bereits wieder erreicht wurde.
// Multitasking mit Timer (Bsp. LED toggeln)
int interval = 500; // Interval vorgeben (hier 500ms)
unsigned long nextTime;
bool ledStatus = LOW;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
if (millis() >= nextTime) {
nextTime = millis() + interval;
if (ledStatus == HIGH) {
ledStatus = LOW;
} else ledStatus = HIGH;
digitalWrite(LED_BUILTIN, ledStatus);
}
// Weiterer Code...
}
Programmcode Möglichkeit 2 (timeStamp)
Vom Prinzip handelt es sich hier um die gleiche Codeidee wie bei Möglichkeit 1. Nur wird hier ein Zeitstempel der letztmaligen Ausführung gesetzt. In der Bedingung für die if-Verzweigung ist dann die Berechnung für die neue Zeit.
// Multitasking mit Timer (Bsp. LED toggeln mit einem Zeitstempel)
int interval = 500; // Interval vorgeben (hier 500ms)
unsigned long timeStamp; // Zeitstempel
bool ledStatus = LOW;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
if (millis() >= timeStamp + interval) {
// Speichert die Ausführungszeit
timeStamp = millis();
// Toggeln in kurzer Schreibweise ohne Variablen
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
// Weiterer Code....
}
Programmcode Möglichkeit 3 (Modulo)
Bei dieser Methode nutzt man den Modulo Operator, der bei einer Division immer den Rest angibt. Wenn man zum Beispiel eine Zahl durch 1000 teilt kann der Modulo Operator nur Werte zwischen 0 und sich selbst minus 1 (hier 999) zurück geben.
// Multitasking mit Timer (Bsp. LED toggeln mit dem Modulo Operator %)
int interval = 500; // Interval vorgeben (hier 500ms)
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
// % liefert Werte zwischen 0 und 2x interval zurück (0-999)
if (millis() % (2*interval) < interval) { // von 0 - 499 wird die LED angeschaltet
digitalWrite(LED_BUILTIN, HIGH);
} else digitalWrite(LED_BUILTIN, LOW); // von 500 - 999 wird die LED ausgeschaltet
}