Warum delay() Arduino-Projekte im Unterricht scheitern lässt (und wie man Kindern millis() vermittelt)

Die Verwendung von delay() versetzt den Mikrocontroller in den Tiefschlaf, blendet Sensoren aus und blockiert Motoren. So vermittelt das Stoppuhr-Mentallmodell Lernenden der Senior Phase nicht-blockierendes Timing.
Die Funktion delay() lässt Arduino-Projekte im Unterricht scheitern, weil sie den Mikrocontroller vollständig anhält. Während der gesamten Dauer der Verzögerung tut der Prozessor nichts: Er kann keinen Kontaktsensor abfragen, keinen Ultraschall-Abstandswert prüfen und nicht auf einen Stopptaster reagieren. Wenn ein fahrbarer Roboter gerade vorwärts fährt und auf eine Zwei-Sekunden-Verzögerung trifft, fährt er zwei volle Sekunden lang blind gegen eine Wand, bevor er seinen nächsten Befehl ausführt.
Um dieses Problem mit Lernenden der Klassen 7 bis 9 zu lösen, muss man weder Threading, Hardware-Timer-Interrupts noch objektorientierte Zustandsautomaten unterrichten. Man braucht ein einziges, konkretes mentales Modell: auf die Armbanduhr schauen statt ein Schläfchen halten.
Die Anatomie eines typischen Unterrichtsfehlers
In fast jedem Lehrplan für den Einstieg in die Robotik ist Lektion 1 das standardmäßige LED-Blinken:
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
delay(1000);Es funktioniert, verschafft den Lernenden ein sofortiges Erfolgserlebnis und legt eine konzeptionelle Tretmine, die drei Wochen später explodiert. Wenn die Lernenden in Lektion 4 eine Fußgängerampel bauen sollen (Licht blinken lassen und Tastendruck erfassen) oder einen Hindernisse umfahrenden Rover (Motoren drehen und Abstand messen), bricht ihr Code zusammen.
Die Lernenden schreiben eine Schleife, die den Taster prüft, einen Summer einschaltet und delay(1000) aufruft. Wenn sie die Taste drücken, ignoriert das Board die Eingabe meistens. Warum? Weil der Prozessor damit beschäftigt war, tote Zyklen innerhalb der Verzögerung herunterzuzählen. Der menschliche Finger hat den Schalter in jenen 99 % des Schleifenzyklus gedrückt und wieder losgelassen, in denen der Chip praktisch schlief.
Auf einem mit 16 MHz getakteten ATmega328P verschwendet der Aufruf von delay(1000) 16 Millionen Taktzyklen mit der Ausführung leerer Assembler-Befehle. Der Roboter betreibt kein Multitasking – er ist schlicht eingefroren.
Das Mentallmodell der Armbanduhr
Bevor Sie den Lernenden Code zeigen, holen Sie sie für eine fünfminütige Demonstration von ihren Bildschirmen weg. Bitten Sie eine freiwillige Person um eine Aufgabe: “Klatsche alle drei Sekunden in die Hände, aber falls ich diesen Stift fallen lasse, fange ihn auf, bevor er den Boden berührt.”
Lassen Sie sie zunächst delay() simulieren: Sagen Sie ihnen, dass sie zum Messen von drei Sekunden die Augen schließen und im Kopf leise bis drei zählen müssen. Lassen Sie den Stift bei Sekunde zwei fallen. Sie werden jedes Mal scheitern. Ihre Sensoren waren abgeschaltet, während sie die Zeit maßen.
Geben Sie ihnen als Nächstes das nicht-blockierende Modell an die Hand: Sagen Sie ihnen, dass sie die Augen weit geöffnet halten, auf die Wanduhr im Klassenzimmer (oder eine digitale Armbanduhr) schauen und Ihre Hand im Auge behalten sollen. Sie prüfen die Zeit: Wenn seit dem letzten Klatschen drei Sekunden vergangen sind, klatschen sie. Fällt der Stift, reagieren sie sofort.
Dadurch verschiebt sich das Konzept der Zeitmessung von einer Aktion (“zwei Sekunden warten”) zu einem Vergleich (“ist schon genug Zeit vergangen?”).
Das Grundmuster: Drei Fragen
Sobald die Lernenden die Uhr an der Wand verstanden haben, führen Sie millis() ein. Erklären Sie, dass millis() einfach eine interne Stoppuhr ist, die genau in der Millisekunde zu laufen begann, in der der Arduino an den Strom angeschlossen wurde. Sie stoppt nie und hält den Code niemals an.
Jedes nicht-blockierende Ereignis lässt sich innerhalb der Endlosschleife auf drei einfache Fragen reduzieren:
- Wie spät ist es jetzt gerade? (Stoppuhr ablesen:
currentTime = millis()) - Wann habe ich diese Aktion zuletzt ausgeführt? (Gespeicherten Notizzettel prüfen:
previousTime) - Ist die erforderliche Zeit vergangen? (Subtraktion durchführen:
currentTime - previousTime >= interval)
Lautet die Antwort auf die dritte Frage Ja, führen Sie die Aktion aus und aktualisieren Sie die Notiz: Setzen Sie previousTime = currentTime. Lautet die Antwort Nein, überspringen Sie die Aktion und fahren Sie sofort fort. Weil die Schleife in einem Bruchteil einer Millisekunde durchläuft, kann das Board problemlos Ultraschallsensoren auslesen, Endschalter prüfen und Linienverfolgungssensoren tausende Male pro Sekunde abfragen.
Die Syntax vermitteln, ohne Anfänger zu überfordern
Für Lernende der Klassen 7 und 8 führt der C++-Boilerplate-Code rund um unsigned long oft zu kognitiver Überlastung. In Schulen, die nach dem offiziellen Lehrplan für Coding und Robotik der Senior Phase arbeiten, bewegen sich die Lernenden typischerweise in blockbasierten Umgebungen oder hybriden Editoren.
Wenn Sie mit Blöcken unterrichten (wie Scratch-basierten Arduino-Umgebungen), ist die Umsetzung unkompliziert: Führen Sie einen “Stoppuhr”-Block (Timer) und eine Variable namens last_time_checked ein. Vermeiden Sie den Block “Warte 1 Sekunde” vollständig, sobald grundlegende Eingaben eingeführt sind.
Wenn Sie textbasiertes Arduino-C++ unterrichten, werfen Sie den Lernenden nicht einfach das Standardbeispiel BlinkWithoutDelay ohne didaktische Vorbereitung (Scaffolding) auf den Bildschirm. Das offizielle Arduino-Beispiel kombiniert zwei getrennte Konzepte auf einmal: nicht-blockierendes Timing und Zustandswechsel (das Invertieren einer LED-Statusvariable). Genau deshalb sind Kinder verwirrt.
Trennen Sie die Zeitprüfung von der eigentlichen Logik. Nutzen Sie stattdessen diesen Ablauf:
- Das Scheitern demonstrieren: Lassen Sie eine LED mit
delay()blinken, während versucht wird, einen Not-Aus-Taster auszulösen. Beobachten Sie die Frustration, wenn der Taster nicht reagiert. - Die Timer-Variable einführen: Zeigen Sie ihnen, wie man
millis()auf dem Seriellen Monitor ausgibt, damit sie sehen, wie die Zahlen kontinuierlich steigen. Das entzaubert die Funktion – sie ist wie ein Kilometerzähler für die Zeit. - Den Zeitsteuerungs-Wrapper schreiben: Stellen Sie eine strukturierte Vorlage bereit, in der die Subtraktionslogik vom Verhalten des Roboters getrennt ist.
| Ansatz | Prozessorstatus | Sensor-Reaktionszeit | Eignung |
|---|---|---|---|
delay(1000) | In Busy-Wait-Schleife angehalten | Vollständig blind während der Verzögerung | Single-Task-Demos, Einführung Klasse 4–6 |
millis()-Vergleich | Freilaufend bei voller Taktfrequenz | Sofort (Abfrage im Sub-Millisekundenbereich) | Robotik, Rover, interaktive Systeme |
Nachhaltige Verankerung in Unterrichtsprojekten
Wenn Lernende von blind fahrenden Rovern zu solchen übergehen, die Sensoren kontinuierlich abfragen, ändert sich ihr Debugging-Erlebnis grundlegend. Statt sich zu wundern, warum ein Kollisionstaster einen Gleichstrommotor nicht gestoppt hat, können sie die Programmausführung sauber nachvollziehen.
Wenn Ihre Schule einen mehrteiligen Übergang von blockbasierter Logik zu physischer Robotik über mehrere Schulhalbjahre hinweg aufbaut, beseitigen strukturierte Unterrichtsreihen und erprobte Hardware-Layouts das Rätselraten. Unser Team von Sheen Robotics for Schools arbeitet mit Lehrkräften zusammen, um diese Konzepte für eingebettete Systeme auf den Stundenplan abzustimmen – damit Lernende zuverlässige mentale Modelle entwickeln, bevor sich schlechte Programmiergewohnheiten festsetzen.
Sobald Lernende verstanden haben, dass ein Computer niemals mit geschlossenen Augen dasitzen und Sekunden zählen sollte, haben sie die Schwelle vom bloßen Ausführen von Skripten zum Schreiben reaktionsfähiger, praxisnaher Software überschritten.



