MicroPython: Experimente mit Timer
Ein Timer ist eine logische Instanz für einen Zeitgeber, der einen Befehl oder eine Funktion zeitabhängig ausführen kann.
- einmalig nach Zeit in Millisekunden oder
- periodisch wiederholend mit Angabe einer Frequenz in Hertz (Anzahl in der Sekunde) oder nach Zeit in Millisekunden
Hier experimentieren wir mit der Timer-Funktion von MicroPython. Probieren verschiedene Parameter bei der Initialisierung aus und versuchen herauszufinden, wofür Timer nützlich sind.
Unterschied zwischen „time.sleep“ und Timer
In einem Programmcode werden wiederholende Kommandos gerne in eine Endlos-Schleife gesetzt und mit dem Kommando „time.sleep“ eine Verzögerung oder Pause hinzugefügt, um eine Zeitabhängigkeit hinzuzufügen.
Den Unterschied zwischen „time.sleep“ und einem Timer wollen wir mit folgender Aufgabe ergründen. Wir wollen die Sekunden zählen und ausgeben, die ein Programm läuft. Dafür brauchen wir einen Zähler, eine Datenausgabe und eine wiederholende Ausführung.
Eine typische Lösung ist, eine Endlos-Schleife laufen zu lassen und darin zu zählen, die Sekunden auszugeben und am Schleifenbeginn eine Sekunden zu warten.
import time count = 0 while True: time.sleep(1) count += 1 print(count)
Es gibt noch eine zweite Lösung mit einem Timer, der so initialisiert wird, dass er jede Sekunde hochzählt und den Wert ausgibt.
from machine import Timer count = 0 def counter(value): global count count += 1 print(count) timer = Timer(period=1000, mode=Timer.PERIODIC, callback=counter)
Funktional sind beide Lösungen völlig identisch. Der Unterschied liegt im Detail. Und die Frage lautet, wenn beide Programmcodes gleichzeitig gestartet werden, ob sie dann auch gleich zählen. Was die Genauigkeit angeht, wird die Timer-Lösung präziser sein.
Die Timer-Lösung hat noch einen zweiten Vorteil, wenn eine Funktion dem Programmcode hinzugefügt werden soll, dann kann man das ohne große Änderung einfach ergänzen. Und der Sekundenzähler bleibt davon unberührt. In der Schleifen-Lösung müsste die Schleife ergänzt oder umgebaut werden.
Hier wird beispielhaft das Blinken einer LED der Schleife hinzugefügt.
import time from machine import Pin led = Pin(25, Pin.OUT, value=0) count = 0 while True: led.off() time.sleep(0.5) led.on() time.sleep(0.5) count += 1 print(count)
Bei der Timer-Lösung wird einfach ein Timer ergänzt, der nur für das Blinken der LED zuständig ist.
from machine import Timer, Pin led = Pin(25, Pin.OUT, value=0) count = 0 def counter(value): global count count += 1 print(count) timer = Timer(period=1000, mode=Timer.PERIODIC, callback=counter) blink = Timer(period=500, mode=Timer.PERIODIC, callback=lambda t:led.value(not led.value()))
Das Problem mit der Schleife ist, dass wir nicht wissen können, wie lange es wirklich dauert, bis die Schleife durchlaufen wird. Dazu bauen wir in die Schleife eine Zeitmessung ein:
import time from machine import Pin led = Pin(25, Pin.OUT, value=0) count = 0 diff = 0 while True: start = time.ticks_ms() led.off() time.sleep(0.5) led.on() time.sleep(0.5) count += 1 print(count, 'Sekunden') stop = time.ticks_ms() diff += time.ticks_diff(stop, start) print(diff/1000, 'Sekunden')
Das Ergebnis wird sein, dass der Sekundenzähler und der Zähler auf Basis vergangener Millisekunden irgendwann anfangen voneinander abzuweisen. Selbst auf Basis mehrerer Stunden liegen wir nur bei eine paar Sekunden. Aber was ist, wenn das Programm mehrere Tage läuft. Dann ist die Differenz zu groß. Damit ist die Schleifen-Lösung mit „sleep“ zu ungenau.
Wenn eine Funktion zeitabhängig ist und präzise (also Echtzeit) sein soll, dann sollte man die Timer-Lösung bevorzugen.
In einer while-Schleife mit sleep-Pausen sind zeitabhängige Funktionen nicht genau genug realisierbar.
Wenn es also wichtig ist, dass eine Funktion oder ein Kommando nach einer bestimmten Zeit ausgeführt werden soll, dann sollte man das mit einem Timer realisieren. Der arbeitet unabhängig vom Hauptprogramm.
Experiment mit Parameter „mode=Timer.PERIODIC“
Im folgenden Programmcode wird die Onboard-LED initialisiert. Außerdem wird ein periodischer Timer initialisiert, der den aktuellen Wert des GPIO 25 toggelt. Diese Funktion ist im Parameter „callback“ definiert.
from machine import Pin, Timer led = Pin(25, Pin.OUT, value=0) timer = Timer(period=1000, mode=Timer.PERIODIC, callback=lambda t:led.toggle())
Der Parameter „mode=Timer.PERIODIC“ führt dazu, dass die Funktion im Parameter „callback“ jede Sekunde (1000 ms) ausgeführt wird.
Experiment mit Parameter „mode=Timer.ONE_SHOT“
Im folgenden Programmcode wird die Onboard-LED initialisiert. Außerdem wird ein einmalig auszuführender Timer initialisiert, der den aktuellen Wert des GPIO 25 toggelt. Diese Funktion ist im Parameter „callback“ definiert.
from machine import Pin, Timer led = Pin(25, Pin.OUT, value=0) timer = Timer(period=1000, mode=Timer.ONE_SHOT, callback=lambda t:led.toggle())
Der Parameter „mode=Timer.ONE_SHOT“ führt dazu, dass die Funktion im Parameter „callback“ ein einziges Mal nach einer Sekunde (1000 ms) ausgeführt wird.
Experimente mit Parameter „period“
Im folgenden Programmcode wird die Onboard-LED initialisiert. Außerdem wird ein periodischer Timer initialisiert, der den aktuellen Wert des GPIO 25 negiert. Diese Funktion ist im Parameter „callback“ definiert.
from machine import Pin, Timer led = Pin(25, Pin.OUT, value=0) timer = Timer(period=1000, mode=Timer.PERIODIC, callback=lambda t:led.value(not led.value()))
Der Parameter „mode=Timer.PERIODIC“ führt dazu, dass die Funktion im Parameter „callback“ jede Sekunde (1000 ms) ausgeführt wird.
Der Parameter „period“ gibt die Wiederholung in Millisekunden (ms) an. Oder anders ausgedrückt, wie lange es dauert, bis der Timer auslöst. 1000 ms entspricht einer Sekunde.
- Erhöhe den Wert von „period“ auf 2000. Die LED blinkt langsamer.
- Verringere den Wert von „period“ auf 100. Die LED blinkt deutlich schneller.
- Verringere den Wert von „period“ auf 20. Die LED flackert.
- Verringere den Wert von „period“ so weit, dass die LED nicht mehr flackert, sondern dauerhaft zu leuchten scheint.
Experimente mit Parameter „freq“
Im folgenden Programmcode wird die Onboard-LED initialisiert. Außerdem wird ein periodischer Timer initialisiert, der den aktuellen Wert des GPIO 25 negiert. Diese Funktion ist im Parameter „callback“ definiert.
from machine import Pin, Timer led = Pin(25, Pin.OUT, value=0) timer = Timer(freq=1, mode=Timer.PERIODIC, callback=lambda t:led.value(not led.value()))
Der Parameter „mode=Timer.PERIODIC“ führt dazu, dass die Funktion im Parameter „callback“ ein Mal in der Sekunde ausgeführt wird.
Der Parameter „freq“ gibt die Frequenz der Wiederholung in Hertz (Hz) an. 1 Hz bedeutet eine Wiederholung in der Sekunde. Mit dem Parameter „freq“ kann man also angeben, wie oft in der Sekunde der Timer ausgelöst werden soll.
- Verringere den Wert von „freq“ auf 0.5. Die LED blinkt langsamer.
- Erhöhe den Wert von „freq“ auf 10. Die LED blinkt deutlich schneller.
- Erhöhe den Wert von „freq“ auf 20. Die LED flackert.
- Erhöhe den Wert von „freq“ so weit, dass die LED nicht mehr flackert, sondern dauerhaft zu leuchten scheint.
Wann nimmt man den Parameter „period“ und wann „freq“?
Den Parameter „freq“ zu verwenden macht dann Sinn, wenn die Zeiteinheit oder der Bezug zu einer Sekunde gegeben ist. Wenn also etwas innerhalb einer Sekunde X mal erfolgen soll. Dann beträgt die Frequenz X Hz. Das macht also nur dann Sinn, wenn X 1 oder größer ist. Man kann auch mit kleineren Werten als 1 arbeiten. Dann muss man aber mit Gleitkommazahlen rechnen.
Den Parameter „period“ zu verwenden macht dann Sinn, wenn der Wert selber eine Zeit ist. Zum Beispiel Sekunden oder Millisekunden. Wenn also etwas nach einer bestimmten Zeit ausgelöst werden soll.
Mit dem Parameter „period“ zu arbeiten macht auch dann Sinn, wenn der Wert des Parameters „freq“ kleiner als 1 ist.
Der Parameter erwartet eine Zeit in Millisekunden. Wenn der Wert nicht in Millisekunden vorliegt, kann er auch umgerechnet werden.
- 1 Sekunde = 1000 Millisekunden
- 0,5 Sekunden = 500 Millisekunden
- 5 Sekunden = 5000 Millisekunden
- 60 Sekunden = 60000 Millisekunden
Anwendungen mit Timer
Anwendungen mit einem Timer sind immer dort zu finden, wo etwas wiederholt werden soll. In der Regel abhängig von einer Zeit.
- Raspberry Pi Pico: Onboard-LED blinken lassen
- Raspberry Pi Pico: Digitale Uhr mit Anzeige (TM1637)
- Raspberry Pi Pico: Stoppuhr mit Anzeige (TM1637)
- Raspberry Pi Pico: Countdown mit Zeitanzeige (TM1637)
- Raspberry Pi Pico: Blink-Geschwindigkeit einer LED mit einem Rotary Encoder einstellen (KY-040)
Weitere verwandte Themen:
- MicroPython: Grundlagen zum Timer
- Raspberry Pi Pico: Grundlagen zur Echtzeituhr (Real-time Clock, RTC)
- Raspberry Pi Pico: Experimente mit RTC
- Raspberry Pi Pico: MicroPython
- Raspberry Pi Pico: Grundlegende Befehle von MicroPython
Teilen:
Hardware-nahes Programmieren mit dem Raspberry Pi Pico und MicroPython
Das Elektronik-Set Pico Edition ist ein Bauteile-Sortiment mit Anleitung zum Experimentieren und Programmieren mit MicroPython.
- LED: Einschalten, ausschalten, blinken und Helligkeit steuern
- Taster: Entprellen und Zustände anzeigen
- LED mit Taster einschalten und ausschalten
- Ampel- und Lauflicht-Steuerung
- Elektronischer Würfel
- Eigene Steuerungen programmieren
Online-Workshop: Programmieren mit dem Raspberry Pi Pico
Gemeinsam mit anderen und unter Anleitung experimentieren? Wir bieten unterschiedliche Online-Workshops zum Raspberry Pi Pico und MicroPython an. Einführung in die Programmierung, Sensoren programmieren und kalibrieren, sowie Internet of Things und Smart Home über WLAN und MQTT.
Für Ihre Fragen zu unseren Online-Workshops mit dem Raspberry Pi Pico besuchen Sie unseren PicoTalk (Online-Meeting). (Headset empfohlen)