3.2. Zeitmessung

Das time-Modul fasst Funktionen zum Schlafen (Anhalten des Skripts für eine bekannte Dauer) und zum Messen der Dauer von Vorgängen zusammen. Auf einem Mikrocontroller sind diese nicht nur nettes Beiwerk; sie sind die Art und Weise, wie das Skript die Interaktionen mit der Außenwelt taktet – wie lange ein Pin auf High gehalten wird, wie lange zwischen Abtastungen gewartet wird, wie lange ein Knopfdruck zurückliegt.

3.2.1. Schlafen

Drei Sleep-Funktionen blockieren das Skript für die angeforderte Dauer:

  • time.sleep(s) – pausiert für s Sekunden. Akzeptiert eine Gleitkommazahl, sodass time.sleep(0.5) eine halbe Sekunde wartet.

  • time.sleep_ms(ms) – pausiert für ms Millisekunden. Das Argument muss eine Ganzzahl sein.

  • time.sleep_us(us) – pausiert für us Mikrosekunden.

import time

print("now")
time.sleep_ms(500)
print("half a second later")

Verwenden Sie time.sleep_ms() für typische „kurz warten“-Bedürfnisse und time.sleep_us() nur, wenn das Timing eng sein muss. Auch das einfache time.sleep() ist in Ordnung, aber die Varianten mit Ganzzahl-Argument vermeiden die Gleitkomma-Umwandlung und lesen sich bei kurzen Intervallen natürlicher.

Sleep ist ein blockierender Aufruf. Während das Skript schläft, tut es nichts anderes – es liest keinen Pin, bedient keinen UART, aktualisiert keine LED. Greifen Sie zu sleep, wenn Blockieren genau das ist, was Sie wollen; verwenden Sie das nicht-blockierende Muster unten, wenn nicht.

3.2.2. Die Uhr auslesen

Um zu messen, wie lange ein Codeabschnitt dauert, lesen Sie die Uhr davor und danach aus:

import time

start = time.ticks_ms()
do_work()
elapsed = time.ticks_ms() - start
print("took", elapsed, "ms")

Das funktioniert meistens. Der Tick-Zähler läuft über (springt zurück auf null) nach einer großen, aber endlichen Anzahl von Ticks, und eine naive Subtraktion über diesen Überlauf hinweg erzeugt eine völlig falsche negative oder positive Zahl.

Zahlenstrahl von 0 bis MAX mit einem Start-Tick nahe MAX und einem End-Tick nahe 0; ein gestrichelter Umlauf-Pfeil zeigt, dass der Zähler nach MAX auf 0 zurückkehrt.

Der Tick-Zähler springt zurück auf null, wenn er das Ganzzahl-Limit erreicht. Eine einfache Subtraktion über diesen Überlauf hinweg ist falsch.

3.2.3. ticks_diff

Um die verstrichenen Ticks korrekt zu erhalten, sogar über einen Überlauf hinweg, verwenden Sie time.ticks_diff():

import time

start = time.ticks_ms()
do_work()
elapsed = time.ticks_diff(time.ticks_ms(), start)
print("took", elapsed, "ms")

Die Argumentreihenfolge ist ticks_diff(later, earlier) – der Ausdruck liest sich als „wie weit liegt later nach earlier“. Das Ergebnis ist eine vorzeichenbehaftete Ganzzahl; positiv bedeutet, dass later tatsächlich später ist, negativ bedeutet, dass es in der Vergangenheit liegt. Die Funktion behandelt den Überlauf intern.

Tipp

Paaren Sie time.ticks_ms() / time.ticks_us() immer mit time.ticks_diff(). Die rohe Subtraktion ist meistens korrekt; der Zeitpunkt, zu dem sie falsch ist, ist, wenn ein Skript lange Zeit gelaufen ist – normalerweise der schlechteste Zeitpunkt, um eine Timing-Störung zu debuggen.

3.2.4. Nicht-blockierende Zeitmessung

Ein Mikrocontroller-Skript hat normalerweise mehr als eine Sache „gleichzeitig“ zu erledigen: einen Knopf lesen, eine LED blinken lassen, einen Sensor abfragen, einen UART bedienen. sleep taugt dafür nichts – während ein sleep läuft, stehen die anderen Aufgaben still.

Das Standardmuster besteht darin, pro Aufgabe eine Deadline zu führen und in jeder Schleife zu prüfen, ob die Deadline überschritten wurde. Die Entscheidung zu handeln baut auf time.ticks_diff() auf, niemals auf sleep:

import time

next_blink = time.ticks_ms()
next_poll  = time.ticks_ms()
state = False

while True:
    now = time.ticks_ms()

    if time.ticks_diff(now, next_blink) >= 0:
        state = not state
        # update LED here
        next_blink = time.ticks_add(next_blink, 500)

    if time.ticks_diff(now, next_poll) >= 0:
        # read sensor here
        next_poll = time.ticks_add(next_poll, 100)

Die LED schaltet alle 500 ms um, der Sensor wird alle 100 ms abgefragt, und keine der Aufgaben blockiert die andere. time.ticks_add() verschiebt eine Deadline um ein bekanntes Inkrement, ohne in die Falle des Überlaufs zu tappen.

Diese Struktur – eine einzige Schleife, mehrere zeitgesteuerte Aufgaben, kein sleep im Rumpf – taucht überall dort auf, wo Hardware-Code verwendet wird: Software-Entprellen von Schaltern, Motorsequenzierung, UART-Lese-Timeouts. Dieselben drei Funktionen (time.ticks_ms(), time.ticks_diff(), time.ticks_add()) decken jeden Fall ab.