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.

  1. Erhöhe den Wert von „period“ auf 2000. Die LED blinkt langsamer.
  2. Verringere den Wert von „period“ auf 100. Die LED blinkt deutlich schneller.
  3. Verringere den Wert von „period“ auf 20. Die LED flackert.
  4. 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.

  1. Verringere den Wert von „freq“ auf 0.5. Die LED blinkt langsamer.
  2. Erhöhe den Wert von „freq“ auf 10. Die LED blinkt deutlich schneller.
  3. Erhöhe den Wert von „freq“ auf 20. Die LED flackert.
  4. 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.

Weitere verwandte Themen:

Frag Elektronik-Kompendium.de

Hardware-nahes Programmieren mit dem Raspberry Pi Pico und MicroPython

Elektronik-Set Pico Edition

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

Elektronik-Set jetzt bestellen Online-Workshop buchen

Online-Workshop: Programmieren mit dem Raspberry Pi Pico

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.

Online-Workshop buchen

Besuchen Sie unser fast monatlich stattfindendes Online-Meeting PicoTalk und lernen Sie uns kennen. Die Teilnahme ist kostenfrei.

Termine und Newsletter-Anmeldung

 

Elektronik-Sets für das Hardware-nahe Programmieren