Gdy licznik millis() się przepełnia
Część sekcji Odmierzanie czasu bez delay() ścieżki Arduino w Coddy. Lekcja 17 z 18.
Typ unsigned long zatrzymuje się na wartości 4,294,967,295. Po około 49.7 dniach millis() osiąga tę wartość i zaczyna od 0. Nazywa się to przepełnieniem.
Mniejszy typ pokazuje to samo. Typ unsigned int zatrzymuje się na wartości 65535:
unsigned int a = 65530;
a = a + 10; // 65540 się nie mieści: a wynosi teraz 4Odejmowanie zawija się w ten sam sposób, co zapewnia bezpieczeństwo: zegar, który wskazywał 65530, a teraz wskazuje 4, odmierzył 10 kroków, a 4 minus 65530, zapisane w typie unsigned int, daje dokładnie 10. Podobnie millis() - start zawsze oznacza czas, który upłynął od start, nawet po przepełnieniu.
Dodawanie nie jest bezpieczne. W wyrażeniu now >= start + interval suma może przekroczyć górną granicę i zawinąć się do małej liczby, przez co timer natychmiast uzna, że czas minął. A gdy now zawinie się, ale suma jeszcze nie, czas nigdy nie minie. Zawsze odejmuj:
if (now - start >= interval) {
// gotowe
}Wyzwanie
ŚredniNikt nie może czekać 49 dni na test, dlatego ten szkic przekazuje do isDone() czasy bliskie przepełnieniu i wyświetla odpowiedzi. Zbyt wcześnie zwraca "done", a potem bez końca zwraca "waiting". Popraw ten jeden wiersz w isDone(), aby porównywał czas, który upłynął od start, z interval.
Naciśnij Run, przeczytaj cztery odpowiedzi, popraw wiersz, a następnie naciśnij Check.
Spróbuj swoich sił
const unsigned long interval = 2000;
// Czy licznik czasu uruchomiony w chwili start zakończył odliczanie w chwili now?
bool isDone(unsigned long start, unsigned long now) {
return now >= start + interval; // popraw tę linię
}
// Wypisuje, ile czasu upłynęło i co zwraca isDone().
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() zatrzymuje się na 4294967295, a potem zaczyna ponownie od 0
test(4294966000, 4294966500); // tuż przed przepełnieniem licznika
test(4294966000, 4294967200); // nadal przed przepełnieniem
test(4294966000, 900); // zegar przekroczył 0
test(4294964000, 500); // licznik czasu uruchomiony wcześniej
}
void loop() {
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Odmierzanie czasu bez delay()
1millis()
Zegar millis()Czas w typie unsigned longMiganie bez opóźnieniaDwie diody LED, dwa tempaMiganie podczas przełączania przyciskiemŚwiatło na czas4Precyzyjne odmierzanie czasu
Pomiar za pomocą micros()Gdy licznik millis() się przepełniaStoper z przyciskiemPoćwicz samodzielnie: Edytor online Arduino