Wenn millis() überläuft
Teil des Abschnitts Timing ohne Delay der Arduino-Journey von Coddy. Lektion 17 von 18.
Ein unsigned long endet bei 4,294,967,295. Nach etwa 49,7 Tagen erreicht millis() diesen Wert und beginnt wieder bei 0. Das nennt man Überlauf.
Ein kleinerer Typ zeigt dasselbe. Ein unsigned int endet bei 65535:
unsigned int a = 65530;
a = a + 10; // 65540 passt nicht hinein: a ist jetzt 4Subtraktion läuft auf dieselbe Weise über, und das macht sie sicher: Eine Uhr, die bei 65530 gestartet ist und jetzt 4 anzeigt, hat 10 Schritte gezählt, und 4 minus 65530, gespeichert in einem unsigned int, ergibt genau 10. Ebenso ist millis() - start immer die seit start vergangene Zeit, auch über einen Überlauf hinweg.
Addieren ist nicht sicher. Bei now >= start + interval kann die Summe den Höchstwert überschreiten und auf eine kleine Zahl überlaufen, sodass der Timer sofort abgelaufen ist. Und wenn now übergelaufen ist, die Summe aber nicht, ist er nie abgelaufen. Subtrahiere immer:
if (now - start >= interval) {
// fertig
}Aufgabe
MittelNiemand kann 49 Tage auf einen Test warten, deshalb übergibt dieser Sketch isDone() Zeitpunkte kurz vor dem Überlauf und gibt seine Antworten aus. Er meldet zu früh "done" und wartet für immer mit "waiting". Korrigiere die eine Zeile in isDone(), sodass sie die seit start vergangene Zeit mit interval vergleicht.
Drücke auf Run, lies die vier Antworten, korrigiere die Zeile und klicke dann auf Check.
Probier es selbst
const unsigned long interval = 2000;
// Ist der Timer, der bei start gestartet wurde, zum Zeitpunkt now abgelaufen?
bool isDone(unsigned long start, unsigned long now) {
return now >= start + interval; // korrigiere diese Zeile
}
// Gibt aus, wie viel Zeit vergangen ist und was isDone() zurückgibt.
void test(unsigned long start, unsigned long now) {
Serial.print(now - start);
Serial.print(" ms: ");
if (isDone(start, now)) {
Serial.println("done");
} else {
Serial.println("waiting");
}
}
void setup() {
Serial.begin(9600);
// millis() stoppt bei 4294967295 und beginnt dann wieder bei 0
test(4294966000, 4294966500); // kurz vor dem Überlauf
test(4294966000, 4294967200); // immer noch vor dem Überlauf
test(4294966000, 900); // die Uhr ist über 0 hinausgelaufen
test(4294964000, 500); // ein Timer, der früher gestartet wurde
}
void loop() {
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Timing ohne Delay
Übe selbstständig: Arduino-Playground