Ich habe diese Erklärung vor längerer Zeit noch ausführlicher und mit Demo-Codes hier auf englisch geschrieben.
Jetzt habe ich mir mal Zeit genommen das wichtigste auf deutsch zu erklären.
Ich bin der Meinung wenn man es von einem Alltagsbeispiel aus kommend erklärt dann wird es sehr viel leichter verständlich.
Ich erkläre nicht-blockierendes Timing gerne mit "eine Tiefkühl-Pizza backen".
Wie macht man eine Tiefkühlpizza backen?
Ofen einschalten und ein paar Minuten aufheizen lassen.
Auf der Verpackung steht 10 Minuten backen.
Wenn der Ofen heiß ist Pizza hineinschieben.
Man schaut auf die Uhr es ist 13:05 Uhr.
Das bedeutet bei 10 Minuten Backzeit ist die Pizza um 13:15 Uhr fertig.
Das heißt bis die Pizza fertig ist könnte man noch ein paar andere Sachen machen.
Arduino-Forum lesen / posten
endlich mal wie man dieses Forum benutzt lesen
Teller und Besteck auf den Tisch
WhatsApp-Nachrichten checken.
Aus dem Keller was zu Trinken holen
Ne runde am Handy spielen
usw.
Dabei wird man immer wieder auf die Uhr schauen ob schon 10 Minuten vorbei sind.
Beispiel:
13:07 - 13:05 = 2 Minuten (Weniger als 10 Minuten => weiterbacken lassen
13:08 - 13:05 = 3 Minuten (Weniger als 10 Minuten => weiterbacken lassen
13:09 - 13:05 = 4 Minuten (Weniger als 10 Minuten => weiterbacken lassen
13:10 - 13:05 = 5 Minuten (Weniger als 10 Minuten => weiterbacken lassen
13:11 - 13:05 = 6 Minuten (Weniger als 10 Minuten => weiterbacken lassen
13:12 - 13:05 = 7 Minuten (Weniger als 10 Minuten => weiterbacken lassen
13:13 - 13:05 = 8 Minuten (Weniger als 10 Minuten => weiterbacken lassen
13:14 - 13:05 = 9 Minuten (Weniger als 10 Minuten => weiterbacken lassen
13:15 - 13:05 = 10 Minuten Hurra 10 Minuten vorbei Pizza ist fertig.
Was läuft da im Prinzip ab
man merkt sich die Startzeit 13:05
Das entspricht
Led_BlinkTimer = millis(); // Timer auf aktuelle Zeit setzen
Buzzer_Timer = millis();
Dann überprüft man immer wieder wie viel Zeit ist schon vergangen indem man aktuelle Zeit minus Startzeit berechnet
Das ist das was in der function TimePeriodIsOver gemacht wird
// prüfe ob LED-Blinkzeit vorbei ist
if ( TimePeriodIsOver(Led_BlinkTimer, LedBlinkInterval) ) {
Im Detail
aktuelle Zeit - StartZeit ist die größer gleich Intervall
if ( currentMillis - startOfPeriod >= TimePeriod ) {
13:07 - 13:05 ergibt 2
if ( currentMillis - startOfPeriod >= TimePeriod ) {
die Aussage 13:07 - 13:05 >= 10 ist FALSCH false
.
.
.
aktuelle Zeit - StartZeit ist das größer/gleich Intervall
if ( currentMillis - startOfPeriod >= TimePeriod ) {
13:15 - 13:05 ergibt 10
if ( currentMillis - startOfPeriod >= TimePeriod ) {
die Aussage 13:15 - 13:05 >= 10 ist WAHR true
Wenn es 13:07 ist liefert
TimePeriodIsOver(13:05, 10 Minuten) )
false
um 13:07 ist die Bedingung
if ( TimePeriodIsOver(13:05, 10 Minuten) ) {
nicht erfüllt
um 13:15 ist die Bedingung
if ( TimePeriodIsOver(13:05, 10 Minuten) ) {
erfüllt. Also führe den Code in der If-Bedingung aus
13:15 Uhr
if ( TimePeriodIsOver(13:05, 10 Minuten) ) {
Pizza_aus_dem_ofen_holen();
Man merkt sich die jeweilige Anfangszeit und vergleicht dann
ständig zig-tausendmal pro Sekunde
Aktuelle Zeit - Anfangszeit => ZeitIntervall
Aktuelle Zeit - Anfangszeit => 20 Sekunden nur wenn true => LED und Sirene neu einschalten
// prüfe ob ein 20-Sekunden-Intervall vorbei ist
if ( TimePeriodIsOver(Timer20Sec, MainInterval) ) {
// wenn WIRKLICH 20 Sekunden vorbei sind
Led_BlinkTimer = millis(); // Timer auf aktuelle Zeit setzen
Buzzer_Timer = millis();
blink_LED = true; // LED blinken einschalten
buzzerOn = true; // Sirene einschalten
}
Aktuelle Zeit - Anfangszeit => 10 Sekunden nur wenn true=> LED-Blinken ausschalten
Aktuelle Zeit - Anfangszeit => 5 Sekunden nur wenn true=> Sirene ausschalten
Aktuelle Zeit - Anfangszeit => 0,5 Sekunden nur wenn true=> LED an/aus
Aktuelle Zeit - Anfangszeit => 1,0 Sekunden nur wenn true=> Sirene An/aus
Diese Vergleiche werden zig-tausend mal pro Sekunde wiederholt.
Aber nur wenn die if-Bedingung true wird
wird der Code in der If-Bedingung ausgeführt.
Zusammengefasst:
Man merkt sich die jeweilige Anfangszeit und vergleicht dann
ständig zig-tausendmal pro Sekunde
ob eine bestimmte Zeitspanne schon vorbei ist oder nicht.
Dieser Vergleich ist in 0,1 Millisekunden abgearbeitet = nicht blockierend
Und nur wenn die Zeitspanne WIRKLICH vorbei ist
dann werde aktiv.
Wenn folgende Bedingung erfüllt ist Innerhalb von loop() gibt es wirklich nirgendwo ein delay().
Das Auswerten der If-Bedingung selbst dauert weniger als eine Millisekunde
Wenn die Auswertung der If-Bedingung false ergibt wird der Code-Block der If-Bedingung nicht ausgeführt.
Das bedeutet, dass das Abarbeiten der If-Bedingung ganz schnell erledigt ist.
Wenn der ganze Code innerhalb von loop() keine (länger dauernden ) For-Schleifen, keine While-Schleifen und auch sonst keine viel Ausführungszeit in Anspruch nehmenden function-calls enthält, wird loop() zig-tausende mal pro Sekunde durchlaufen.
Und das nennt man dann nicht-blockierendes Programmieren.
vgs
P.S. An bestimmten Stellen macht zum Verstehen des Grundprinzips Reduzierung auf das notwendigste Sinn. (Didaktische Reduzierung)
Wenn man es wissenschaftlich möglichst exakt und eindeutig und auch noch alle Sonderfälle einschließend beschreiben will dann landet man zwar bei wissenschaftlicher Exaktheit. Es ist dann aber eben auch schwer verständlich.
Es steht ja jedem frei seine eigene Erklärvariante zu posten.