Haben Sie sich jemals gefragt, warum Ihr Arduino Nano beim Ausführen einfacher Aufgaben so langsam wirkt? Oder warum Ihr Programm scheinbar „einfriert”, wenn es auf etwas wartet? Die Antwort liegt oft in der Verwendung der delay()
-Funktion. Obwohl sie einfach zu verstehen und zu verwenden ist, kann sie in komplexeren Projekten ein echter Flaschenhals sein. In diesem Artikel werden wir untersuchen, warum delay()
problematisch ist und wie die millis()
-Funktion eine viel effizientere und flexiblere Alternative bietet.
Das Problem mit delay()
Die delay()
-Funktion tut genau das, was ihr Name vermuten lässt: Sie pausiert die Ausführung Ihres Programms für eine bestimmte Anzahl von Millisekunden. Während dieser Zeit tut der Arduino nichts anderes, als zu warten. Dies mag für einfache Anwendungen in Ordnung sein, aber in komplexeren Projekten, die mehrere Aufgaben gleichzeitig erledigen müssen (z. B. Sensoren lesen, LEDs steuern und serielle Kommunikation abwickeln), wird die Verwendung von delay()
schnell unpraktisch.
Hier sind einige der Hauptprobleme mit der delay()
-Funktion:
- Blockierender Code:
delay()
blockiert die Ausführung aller anderen Funktionen im Programm. Das bedeutet, dass der Arduino in dieser Zeit nicht auf Eingaben reagieren, Daten verarbeiten oder andere Aufgaben erledigen kann. - Ineffizienz: Die Zeit, die mit
delay()
verbracht wird, ist verschwendete Rechenleistung. Der Arduino könnte stattdessen andere nützliche Dinge tun. - Begrenzte Parallelität: Es ist unmöglich, mehrere Aufgaben gleichzeitig auszuführen, wenn Sie sich auf
delay()
verlassen. - Schwierige Echtzeit-Anwendungen: In Anwendungen, die präzise Zeitsteuerung und Echtzeit-Reaktion erfordern, ist
delay()
ungeeignet.
Stellen Sie sich vor, Sie möchten eine LED blinken lassen und gleichzeitig die Temperatur mit einem Sensor messen. Wenn Sie delay()
verwenden, um die LED ein- und auszuschalten, kann der Arduino während dieser Verzögerung keine Temperaturdaten lesen. Dies führt zu einer ungenauen oder verzögerten Temperaturmessung. Genau hier kommt die millis()
-Funktion ins Spiel.
Die Lösung: Die millis()-Funktion
Die millis()
-Funktion gibt die Anzahl der Millisekunden zurück, seit der Arduino mit der Ausführung des aktuellen Programms begonnen hat. Im Gegensatz zu delay()
blockiert millis()
die Ausführung des Programms nicht. Stattdessen können Sie den Wert von millis()
verwenden, um die Zeit zu messen und Aktionen basierend auf vergangenen Zeitintervallen auszuführen.
Der Schlüssel zur Verwendung von millis()
liegt darin, den aktuellen Wert mit einem zuvor gespeicherten Wert zu vergleichen. Auf diese Weise können Sie feststellen, ob eine bestimmte Zeitspanne vergangen ist, ohne die Ausführung des restlichen Programms zu blockieren.
Wie funktioniert millis()?
Im Grunde zählt die millis()
Funktion die Millisekunden seit dem Start des Arduino. Dieser Zähler läuft kontinuierlich im Hintergrund, unabhängig davon, was Ihr Programm sonst noch tut. Daher kann Ihr Programm jederzeit den aktuellen Wert dieses Zählers abrufen, ohne die Ausführung zu unterbrechen.
Der millis() Überlauf
Es ist wichtig zu beachten, dass der von millis()
zurückgegebene Wert ein unsigned long
ist, was bedeutet, dass er einen Wert zwischen 0 und 4.294.967.295 speichern kann. Daher läuft millis()
nach etwa 50 Tagen (4.294.967.295 Millisekunden) über und beginnt wieder bei 0. Dies kann zu unerwarteten Ergebnissen führen, wenn Sie nicht vorsichtig sind. Um dies zu verhindern, sollten Sie immer die Differenz zwischen zwei millis()
Werten berechnen, anstatt absolute Werte zu verwenden. Dies funktioniert, weil die Subtraktion von `unsigned long` automatisch den Überlauf berücksichtigt.
Verwendung von millis() für nicht-blockierende Verzögerungen
Hier ist ein einfaches Beispiel, wie Sie millis()
verwenden können, um eine LED ohne delay()
blinken zu lassen:
„`c++
const int ledPin = 13;
unsigned long previousMillis = 0;
const long interval = 1000; // Blinkintervall in Millisekunden
int ledState = LOW;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis – previousMillis >= interval) {
// Speichere die letzte Blinkzeit
previousMillis = currentMillis;
// LED Zustand wechseln:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// Setze die LED:
digitalWrite(ledPin, ledState);
}
}
„`
In diesem Beispiel:
ledPin
ist der Pin, an dem die LED angeschlossen ist.previousMillis
speichert den Zeitpunkt der letzten LED-Änderung.interval
ist die Zeit in Millisekunden, die zwischen den LED-Änderungen vergehen soll.ledState
speichert den aktuellen Zustand der LED (HIGH oder LOW).
Die loop()
-Funktion macht Folgendes:
- Liest den aktuellen Wert von
millis()
. - Prüft, ob die Differenz zwischen dem aktuellen Wert und dem gespeicherten Wert (
previousMillis
) größer oder gleich dem gewünschten Intervall ist. - Wenn ja, aktualisiert sie
previousMillis
auf den aktuellen Wert, wechselt den Zustand der LED und schreibt den neuen Zustand auf den LED-Pin.
Der große Vorteil hier ist, dass der Arduino während der „Wartezeit” zwischen den LED-Änderungen andere Aufgaben erledigen kann, da die loop()
Funktion immer wieder durchlaufen wird und die Zeit prüft. Das Programm wird nicht durch eine delay()
-Anweisung blockiert.
Erweiterte Anwendungen von millis()
Die millis()
-Funktion ist nicht nur für einfache Blinkmuster geeignet. Sie kann für eine Vielzahl komplexerer Anwendungen eingesetzt werden, wie z. B.:
- Mehrere Ereignisse mit unterschiedlichen Timings: Sie können
millis()
verwenden, um mehrere Ereignisse zu steuern, die in unterschiedlichen Zeitabständen stattfinden. Beispielsweise könnten Sie eine LED alle 500 Millisekunden, eine andere LED alle 1000 Millisekunden und einen Sensor alle 2000 Millisekunden auslesen. - Software PWM (Pulsweitenmodulation): Sie können
millis()
verwenden, um PWM-Signale zu erzeugen, ohne die hardwareseitige PWM zu nutzen. Dies kann nützlich sein, wenn Sie mehr PWM-Ausgänge benötigen, als Ihr Arduino Nano bietet. - Zeitgesteuerte Aktionen: Sie können
millis()
verwenden, um Aktionen zu einem bestimmten Zeitpunkt auszuführen, z. B. das Starten oder Stoppen einer Aufgabe zu einem bestimmten Zeitpunkt. - Überwachung der Reaktionszeit: Sie können
millis()
verwenden, um die Zeit zu messen, die für die Reaktion auf ein Ereignis benötigt wird, z. B. das Drücken einer Taste oder das Auslösen eines Sensors.
Vorteile der Verwendung von millis() gegenüber delay()
Zusammenfassend sind hier die wichtigsten Vorteile der Verwendung von millis()
anstelle von delay()
:
- Nicht-blockierender Code: Ihr Programm kann weiterhin andere Aufgaben ausführen, während es auf das Vergehen einer bestimmten Zeitspanne wartet.
- Erhöhte Effizienz: Der Arduino kann seine Rechenleistung optimal nutzen.
- Ermöglicht Parallelität: Sie können mehrere Aufgaben gleichzeitig ausführen.
- Bessere Echtzeit-Performance:
millis()
ist besser geeignet für Anwendungen, die präzise Zeitsteuerung und Echtzeit-Reaktion erfordern.
Fazit
Obwohl die delay()
-Funktion für einfache Projekte nützlich sein kann, ist sie für komplexere Anwendungen oft ungeeignet. Die millis()
-Funktion bietet eine viel effizientere und flexiblere Möglichkeit, zeitgesteuerte Aktionen in Ihrem Arduino Nano auszuführen. Durch das Verständnis und die Implementierung von millis()
können Sie die Leistung Ihrer Projekte erheblich verbessern und Ihre Möglichkeiten erweitern. Experimentieren Sie mit den Beispielen in diesem Artikel und entdecken Sie die Macht der nicht-blockierenden Programmierung!