Quand millis() déborde
Fait partie de la section Gestion du temps sans delay du Journey Arduino de Coddy. Leçon 17 sur 18.
Un unsigned long s’arrête à 4,294,967,295. Au bout d’environ 49.7 jours, millis() l’atteint et recommence à 0. C’est ce qu’on appelle un retour à zéro.
Un type plus petit montre la même chose. Un unsigned int s’arrête à 65535 :
unsigned int a = 65530;
a = a + 10; // 65540 ne tient pas : a vaut maintenant 4La soustraction revient à zéro de la même manière, ce qui la rend sûre : une horloge qui a commencé à 65530 et qui indique maintenant 4 a compté 10 étapes, et 4 moins 65530, stocké dans un unsigned int, vaut exactement 10. De la même façon, millis() - start donne toujours le temps écoulé depuis start, même lors d’un retour à zéro.
L’addition n’est pas sûre. Dans now >= start + interval, la somme peut dépasser la limite et revenir à un petit nombre, ce qui fait que le minuteur est immédiatement terminé. Et lorsque now est revenu à zéro, mais que la somme ne l’a pas encore fait, le minuteur n’est jamais terminé. Faites toujours une soustraction :
if (now - start >= interval) {
// terminé
}Défi
MoyenPersonne ne peut attendre 49 jours pour un test, alors ce programme appelle isDone() à des moments proches du débordement et affiche ses réponses. Il indique « done » trop tôt et « waiting » indéfiniment. Corrige la ligne dans isDone() pour qu’elle compare le temps écoulé depuis start avec interval.
Appuie sur Run, lis les quatre réponses, corrige la ligne, puis appuie sur Check.
Essayez vous-même
const unsigned long interval = 2000;
// Le minuteur démarré à start est-il arrivé à terme à l’instant now ?
bool isDone(unsigned long start, unsigned long now) {
return now >= start + interval; // corrigez cette ligne
}
// Affiche le temps écoulé et ce qu’indique 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() s’arrête à 4294967295, puis repart de 0
test(4294966000, 4294966500); // juste avant le retour à 0
test(4294966000, 4294967200); // toujours avant le retour à 0
test(4294966000, 900); // l’horloge a dépassé 0
test(4294964000, 500); // un minuteur démarré plus tôt
}
void loop() {
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Gestion du temps sans delay
Entraînez-vous par vous-même : Playground Arduino