# \[Bericht\] Der (Millis) Ueberlauf im Test

**URL:** <https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179>\
**Category:** Deutsch\
**Created:** [September 16, 2021, 5:22pm UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179 "2021-09-16T17:22:08Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![combie](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/combie/32/217369_2.png) [@combie](https://forum.arduino.cc/u/combie)\
**Post date:** [September 16, 2021, 5:22pm UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/1 "2021-09-16T17:22:08Z")

</div>

Schönen guten Tag!

Hier im Forum kursieren einige Methoden, wie man ein "blink without delay" hin bekommt, oder auch andere Wartezeiten.

Drei davon habe ich hier mal grafisch aufbereitet. Ok, das eigentliche malen, das macht der **Serielle Plotter** , der Arduino IDE.

Da das Problem mit uint32\_t schlecht darstellbar ist, wg. der 49 Tage Wartezeit, habe ich es auf byte runtergebrochen. Darum auch die Casts, um wirklich in dem Zahlenbereich zu bleiben. Bei unsigned long sind die Casts nicht nötig.

Wie auch immer, ob uint8\_t oder uint32\_t, das Problembild ist im Grunde gleich.

Was sehen wir in den Diagrammen?  
In der blauen Kurve sehen wir die langsam ansteigende Zeit. Beim Überlauf gehts wieder mit Null los.  
Die rote Treppenstufe zeigt die gemerkte Zeit. An jeder Flanke beginnt ein neues Zeit Intervall.

Die kleine grüne Rechteckkurve(?) zeigt unseren Aktor. Z.B. eine blinkende LED oder die Anforderung für unsere 27KW Klimaanlage. Und genau diese fette Klimaanlage verträgt keine Hakler an der Stelle. Wir(nur ich?) wollen da ein sauberes, symmetrisches, von Überläufen unbeeindrucktes, Rechteck sehen.

Resultat der Geschichte:  
Drei Verfahren getestet, nur eins davon kommt unbeeindruckt durch den Überlauf.

Die Modulo Methode:

```cpp
if(not (jetztzeit % interval))

```

 ![image](https://europe1.discourse-cdn.com/arduino/original/4X/4/6/1/4617c615d3df7f2a8fa581b3943ed100385803ed.png)

* * *

Die Methode mit Addition:

```cpp
if(jetztzeit > byte(zeitmerker + interval))

```

 ![image](https://europe1.discourse-cdn.com/arduino/original/4X/b/4/4/b4473573ddd1a044069c4fe25baac6d5ac529b9a.png)

* * *

Die einzig richtige Methode:

```cpp
if(byte(jetztzeit - zeitmerker) >= interval)

```

 ![image](https://europe1.discourse-cdn.com/arduino/original/4X/6/5/e/65e8d62c4f4bcd2d107aa01f3aa51aeefffa8cb4.png)

* * *

Zu guter Letzt der Testcode:

```cpp
#include <Streaming.h> // die Lib findest du selber ;-)
Stream &cout = Serial; // cout Emulation für "Arme"

byte jetztzeit = 0; // macht sich blaue Rampe
byte zeitmerker = 0; // macht sich rote Treppe
byte interval = 60; // Zeit zwischen grüne Flanken
bool signal = false; // macht sich grünes Rechteck

void setup() 
{
  Serial.begin(9600);
  cout << F("jetztzeit,zeitmerker,signal") << endl;
}

void loop() 
{
  jetztzeit++;

  // if(not (jetztzeit % interval)) // fehlverhalten beim Ueberlauf
  // if(jetztzeit > byte(zeitmerker + interval))// fehlverhalten vor dem Ueberlauf
  if(byte(jetztzeit - zeitmerker) >= interval) // der wahre Jakob
  {
    zeitmerker = jetztzeit;
    signal = not signal;
  }
  
  cout << jetztzeit << "," << zeitmerker << "," << (signal * 20) << endl;

 delay(1);
}

```

Viel Freude damit, ich euch wünsche.

---

<div class="post-metadata">

**Author:** ![fony](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/fony/32/936882_2.png) [@fony](https://forum.arduino.cc/u/fony)\
**Post date:** [September 16, 2021, 5:57pm UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/2 "2021-09-16T17:57:08Z")

</div>

👍 👍 👍

---

<div class="post-metadata">

**Author:** ![HotSystems](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/hotsystems/32/219785_2.png) [@HotSystems](https://forum.arduino.cc/u/HotSystems)\
**Post date:** [September 16, 2021, 6:52pm UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/3 "2021-09-16T18:52:55Z")

</div>

Hallo combie,  
danke für deine sehr ausführlich und gut verständliche Beschreibung.

---

<div class="post-metadata">

**Author:** ![combie](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/combie/32/217369_2.png) [@combie](https://forum.arduino.cc/u/combie)\
**Post date:** [September 17, 2021, 10:34am UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/4 "2021-09-17T10:34:15Z")

</div>

Schön, dass es euch gefällt!  
Und ja, Bilder sagen oft mehr, als Tausend Worte.  
Um das nicht zu verwässern, habe/hatte ich etwas mit Worten gespart.  
Das hole ich mal hier nach...

Die "richtige" Methode:  
Genau dann, wenn der Überlauf des Zeitgebers uns einen Streich spielen möchte, wird dieser durch den Unterlauf bei der Subtraktion kompensiert.  
Also: Unterlauf neutralisiert Überlauf!

Das fehlt bei der "Addition" Methode:  
Egal wie man es anstellt, mit einem Überlauf bei der Addition, kann man nicht den Überlauf des Zeitgebers kompensieren.

Vom Rechen- bzw. Speicheraufwand sind beide Methoden gleichwertig.

Da fällt die "Modulo" Variante aus dem Rahmen:  
Diese spart eine Variable ein. Benötigt an der Stelle also weniger Speicher.  
Zur Strafe unterliegt sie starken Einschränkungen.

1. Wenn es nicht wirklich alle 1 ms an die Reihe kommt, können Intervall Enden übersehen werden.
2. Die Intervallzeiten müssen Zweierpotenzen sein, damit die Ausgabe im Überlauf symmetrisch wird/bleibt.

Ganz nebenbei, gehört Modulo zu den Divisionen, welche die teuersten Rechenoperationen auf den kleinen AVR sind.

---

<div class="post-metadata">

**Author:** ![f91w](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/f91w/32/1126596_2.png) [@f91w](https://forum.arduino.cc/u/f91w)\
**Post date:** [September 17, 2021, 11:13am UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/5 "2021-09-17T11:13:44Z")

</div>

Klasse! Das sollte man in die Dokumentation als Tutorial aufnehmen.

---

<div class="post-metadata">

**Author:** ![Plumps](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/plumps/32/1018546_2.png) [@Plumps](https://forum.arduino.cc/u/Plumps)\
**Post date:** [September 17, 2021, 1:01pm UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/6 "2021-09-17T13:01:47Z")

</div>

Man darf natürlich nicht vergessen, ob der Überlauf überhaupt kritisch ist. Wenn eine blinkende LED aller 49 Tage mal ein blinken außerhalb des Taktes macht, wird dass kaum jemand bemerken. Da ist der Modulo wahrscheinlich besser.

---

<div class="post-metadata">

**Author:** ![Doc\_Arduino](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/doc_arduino/32/215810_2.png) [@Doc\_Arduino](https://forum.arduino.cc/u/Doc_Arduino)\
**Post date:** [September 17, 2021, 1:18pm UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/7 "2021-09-17T13:18:24Z")

</div>

> [@Plumps](#):
>
> Man darf natürlich nicht vergessen, ob der Überlauf überhaupt kritisch ist. Wenn eine blinkende LED aller 49 Tage mal ein blinken außerhalb des Taktes macht, wird dass kaum jemand bemerken. Da ist der Modulo wahrscheinlich besser.

Gewöhne dir solchen Mist erst gar nicht an. Vor allen Dingen wenn man weiß wie man es richtig macht. Im Laufe der Zeit etablieren sich gewisse Standardverfahren die man einfach nur anwenden sollte.

---

<div class="post-metadata">

**Author:** ![combie](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/combie/32/217369_2.png) [@combie](https://forum.arduino.cc/u/combie)\
**Post date:** [September 17, 2021, 5:02pm UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/8 "2021-09-17T17:02:46Z")

</div>

> [@Plumps](#):
>
> aller 49 Tage mal ein blinken außerhalb des Taktes macht,

Nunja...  
Jedes mal, wenn irgendeiner deiner Loop Durchgänge länger als 1ms braucht, kann dir das auf die Füße fallen.

Ich sage:  
1 Fehler pro 49 Tage ist zuviel, da unnötig.  
Aber das Risiko jede ms einmal einzugehen, sollte auch dir zuviel sein.

Ganz schlimm wird es dann auch noch auf einem z.B. 3,3V Pro Mini.  
Da fällt sowieso fast jede 2te ms unter den Tisch. Dann ist das Versagen der Modulo Methode quasi unausweichlich.

---

<div class="post-metadata">

**Author:** ![combie](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/combie/32/217369_2.png) [@combie](https://forum.arduino.cc/u/combie)\
**Post date:** [September 20, 2021, 12:49pm UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/9 "2021-09-20T12:49:10Z")

</div>

> [@combie](#):
>
> Ganz schlimm wird es dann auch noch auf einem z.B. 3,3V Pro Mini.  
> Da fällt sowieso fast jede 2te ms unter den Tisch. Dann ist das Versagen der Modulo Methode quasi unausweichlich.

So, jetzt habe ich auch endlich mal die Zeit gefunden, den Beweis dafür anzutreten.  
Einzige Änderung im Programm:

```arduino
// jetztzeit++; // ersetzt
jetztzeit = millis(); // mit den unteren 8 Bit des echten Millis Wertes.

```

* * *

Das geänderte Programm, mit den echten millis() auf einem 8MHZ Pro Mini

 ![image](https://europe1.discourse-cdn.com/arduino/original/4X/5/e/5/5e55356dd6dcb340972bacc394e8ad7d589b815c.png)

* * *

Das geänderte Programm, mit den echten millis() auf einem 16MHZ UNO

 ![image](https://europe1.discourse-cdn.com/arduino/original/4X/3/9/2/392c47bd8fc646e3f7268c75961fc437e4a078a2.png)

* * *

Die "wahrhaftige" Methode liefert auf beiden gute Ergebnisse. VIEL symmetrischere.  
Dagegen ist die "Modulo" Methode eher ein Zufallsgenerator  
🕳

---

<div class="post-metadata">

**Author:** ![Rintin](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/rintin/32/1013044_2.png) [@Rintin](https://forum.arduino.cc/u/Rintin)\
**Post date:** [September 21, 2021, 7:06pm UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/10 "2021-09-21T19:06:35Z")

</div>

Die Modulo Variante macht einen X == Y Vergleich, wenn da die falsche ms übersprungen wird, gehts schief.

```cpp

unsigned long last;

void setup() {
  Serial.begin(115200);
  last = millis();
}

void loop() {
  auto now = millis();
  if (now == last) {
    return;
  }
  if ((now - 1) == last) {
    last = now;
    return;
  }
  Serial.println(now);
  last = now;
}
```

---

<div class="post-metadata">

**Author:** ![Doc\_Arduino](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/doc_arduino/32/215810_2.png) [@Doc\_Arduino](https://forum.arduino.cc/u/Doc_Arduino)\
**Post date:** [September 22, 2021, 9:40am UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/11 "2021-09-22T09:40:54Z")

</div>

Hallo Rintin,

das haste dir jetzt ausgedacht? Dieser falsche Code taucht nirgendswo auf. Auch sehe ich darin kein Modulo. Bist du dir im Klaren was dein _return_ bewirkt? Tipp. Vergiss das ganz schnell.

---

<div class="post-metadata">

**Author:** ![michael\_x](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/michael_x/32/628623_2.png) [@michael\_x](https://forum.arduino.cc/u/michael_x)\
**Post date:** [September 22, 2021, 11:04am UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/12 "2021-09-22T11:04:16Z")

</div>

Um zu erreichen, dass loop (höchstens) einmal je ms drankommen soll, könnte @Rintin evtl. so was wollen:

> [@Rintin](#):
>
> ```arduino
> void loop() {
> static unsigned long last;
> auto now = millis();
> if (now == last) return;
> else {
> // max. einmal je ms
> Serial.println(now);
> // ... usw. 
> // (now - last) sollte 1 sein. Oder evtl. größer, wenn das vorherige "usw." zu lange gedauert hat.
> // (now - last) wird aber nicht durch einen Überlauf beeinflusst.
> last = now;
> }
> }
> 
> ```

> [@Doc\_Arduino](#):
>
> Auch sehe ich darin kein Modulo.

Das ist gut so, denn modulo ist Mist. Außer der Compiler kann es wegoptimieren und ohne modulo-Division machen.

---

<div class="post-metadata">

**Author:** ![Doc\_Arduino](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/doc_arduino/32/215810_2.png) [@Doc\_Arduino](https://forum.arduino.cc/u/Doc_Arduino)\
**Post date:** [September 22, 2021, 11:39am UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/13 "2021-09-22T11:39:59Z")

</div>

Hallo,

na logisch ist Modulo hier Mist, Ich hatte nichts anderes geschrieben. Nur das war nicht mein Anliegen. Mein Anliegen war daraufhin zuweisen das Rintin was von Modulo erzählt aber kein Modulo im Code steht.  
Weiterhin steht die Frage im Raum was das return bewirken soll? Wo springt das return hin? Ich vermute das ist so nicht gewollt. Also weg damit.

---

<div class="post-metadata">

**Author:** ![michael\_x](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/michael_x/32/628623_2.png) [@michael\_x](https://forum.arduino.cc/u/michael_x)\
**Post date:** [September 22, 2021, 11:48am UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/14 "2021-09-22T11:48:54Z")

</div>

> [@Doc\_Arduino](#):
>
> Wo springt das return hin?

Natürlich beendet `return;` den aktuellen loop-Durchlauf (und startet also einen neuen).  
Der Rest von loop wird also nur (max.) einmal je ms durchlaufen.  
Die Frage ist eher, wofür das gut sein soll.

---

<div class="post-metadata">

**Author:** ![Rintin](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/rintin/32/1013044_2.png) [@Rintin](https://forum.arduino.cc/u/Rintin)\
**Post date:** [September 22, 2021, 7:53pm UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/15 "2021-09-22T19:53:48Z")

</div>

Ok... war schon spät... es ging mir hauptsächlich um das X == Y.

Jetzt überlegt mal was gibt der Code auf der Seriellen aus?  
Und was gibt der wirklich aus?

---

<div class="post-metadata">

**Author:** ![combie](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/combie/32/217369_2.png) [@combie](https://forum.arduino.cc/u/combie)\
**Post date:** [September 22, 2021, 8:05pm UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/16 "2021-09-22T20:05:30Z")

</div>

> [@Rintin](#):
>
> es ging mir hauptsächlich um das X == Y.

Ja, das ist das Problem mit dem Modulo.  
Zumindest in dem Bereich wo kein Überlauf stattfindet.

Im Überlauf zeigt es dann nochmal sein zweites Gesicht, welches auch nicht schöner ist.

---

<div class="post-metadata">

**Author:** ![Rintin](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/rintin/32/1013044_2.png) [@Rintin](https://forum.arduino.cc/u/Rintin)\
**Post date:** [September 22, 2021, 8:31pm UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/17 "2021-09-22T20:31:46Z")

</div>

> [@michael\_x](#):
>
> Der Rest von loop wird also nur (max.) einmal je ms durchlaufen.

Und wie oft wird auf Serial was ausgegeben?

---

<div class="post-metadata">

**Author:** ![michael\_x](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/michael_x/32/628623_2.png) [@michael\_x](https://forum.arduino.cc/u/michael_x)\
**Post date:** [September 23, 2021, 11:02am UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/18 "2021-09-23T11:02:11Z")

</div>

> [@Rintin](#):
>
> Und wie oft wird auf Serial was ausgegeben?

Ist der Sinn deines zweiten `return;` [( in #10)](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/10) , dass nur _Stolpern_ protokolliert werden soll ?

Ich hätte übrigens nicht gedacht, dass ein loop-Durchlauf dieser "Größe" so häufig \>1ms dauert.

```arduino
43
86
128
171
214
256
299
342
384

```

(Dein Code auf meinem Uno)

---

<div class="post-metadata">

**Author:** ![my\_xy\_projekt](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/my_xy_projekt/32/810062_2.png) [@my\_xy\_projekt](https://forum.arduino.cc/u/my_xy_projekt)\
**Post date:** [September 23, 2021, 12:20pm UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/19 "2021-09-23T12:20:44Z")

</div>

> [@michael\_x](#):
>
> Ich hätte übrigens nicht gedacht, dass ein loop-Durchlauf dieser "Größe" so häufig \>1ms dauert.

Macht er ja nicht. Mit dem return bricht er vorher ab und durch das jeweilige neu setzen von last kommt er nur ca. alle 40ms unten an, weil erst nach dieser Zeit der Durchläufe sich ein Unterschied von 2ms zwischen now und last ergibt.  
(Seins in Kurzform)

```arduino
  if ((now == last) || ((now - 1) == last)) {
    last = now;
    return;
  }
```

---

<div class="post-metadata">

**Author:** ![Rintin](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/rintin/32/1013044_2.png) [@Rintin](https://forum.arduino.cc/u/Rintin)\
**Post date:** [September 23, 2021, 7:48pm UTC](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179/20 "2021-09-23T19:48:26Z")

</div>

> [@Doc\_Arduino](#):
>
> Weiterhin steht die Frage im Raum was das return bewirken soll? Wo springt das return hin?

Dann erklär bitte einmal was es macht.

[Next page](https://forum.arduino.cc/t/bericht-der-millis-ueberlauf-im-test/906179.md?page=2)
