3.2. Časování

Modul time sdružuje funkce pro spánek (pozastavení skriptu na známou dobu) a pro měření, jak dlouho něco trvá. Na mikrokontroléru to nejsou nepovinné vymoženosti; jsou způsobem, jakým skript řídí tempo interakcí s okolním světem – jak dlouho držet pin ve vysoké úrovni, jak dlouho čekat mezi vzorky, jak dlouho uplynulo od posledního stisku tlačítka.

3.2.1. Spánek

Tři funkce spánku blokují skript po požadovanou dobu:

  • time.sleep(s) – pozastaví na s sekund. Přijímá float, takže time.sleep(0.5) čeká půl sekundy.

  • time.sleep_ms(ms) – pozastaví na ms milisekund. Argument musí být celé číslo.

  • time.sleep_us(us) – pozastaví na us mikrosekund.

import time

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

Pro typické potřeby „chvíli počkat“ použijte time.sleep_ms() a time.sleep_us() jen tehdy, když časování musí být přesné. Obyčejná funkce time.sleep() je také v pořádku, ale varianty s celočíselným argumentem se vyhýbají převodu na pohyblivou řádovou čárku a pro krátké intervaly se čtou přirozeněji.

Spánek je blokující volání. Zatímco skript spí, nedělá nic jiného – nečte pin, neobsluhuje UART, neaktualizuje LED. Sáhněte po sleep, když je blokování to, co chcete; pokud ne, použijte neblokující vzorec níže.

3.2.2. Čtení hodin

Chcete-li změřit, jak dlouho trvá nějaký úsek kódu, přečtěte hodiny před ním a po něm:

import time

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

Toto funguje většinu času. Čítač tiků přeteče (vrátí se zpět na nulu) po velkém, ale konečném počtu tiků a naivní odečtení přes tento přechod produkuje divoce nesprávné záporné nebo kladné číslo.

Číselná osa od 0 do MAX se startovním tikem poblíž MAX a koncovým tikem poblíž 0; přerušovaná šipka přetečení ukazuje, že po MAX se čítač vrátí na 0.

Čítač tiků se po dosažení celočíselného limitu vrátí zpět na nulu. Obyčejné odečtení přes tento přechod je nesprávné.

3.2.3. ticks_diff

Pro správné získání uplynulých tiků, i přes přetečení, použijte time.ticks_diff():

import time

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

Pořadí argumentů je ticks_diff(later, earlier) – výraz se čte jako „jak daleko je later po earlier“. Výsledkem je celé číslo se znaménkem; kladné znamená, že later je skutečně později, záporné znamená, že je v minulosti. Funkce přetečení zpracovává interně.

Tip

time.ticks_ms() / time.ticks_us() vždy párujte s time.ticks_diff(). Surové odečtení je správné většinu času; kdy je nesprávné, je tehdy, když skript běží dlouhou dobu – obvykle ve chvíli, kdy je ladění chyby časování nejhorší.

3.2.4. Neblokující časování

Skript pro mikrokontrolér obvykle musí dělat více než jednu věc „současně“: číst tlačítko, blikat LED, dotazovat senzor, obsluhovat UART. sleep k tomu není dobrý – zatímco běží jeden sleep, ostatní úlohy jsou zastavené.

Standardním vzorcem je udržovat termín (deadline) pro každou úlohu a v každé smyčce kontrolovat, zda termín uplynul. Rozhodnutí jednat je postaveno na time.ticks_diff(), nikdy na 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)

LED se přepíná každých 500 ms, senzor se dotazuje každých 100 ms a žádná úloha neblokuje druhou. time.ticks_add() posune termín o známý přírůstek, aniž by narazila na problém s přetečením.

Tento tvar – jediná smyčka, několik časovaných úloh, žádný sleep v těle – se objevuje všude, kde se vyskytuje hardwarový kód: softwarové potlačení zákmitů spínačů (debouncing), sekvencování motorů, časové limity čtení z UART. Stejné tři funkce (time.ticks_ms(), time.ticks_diff(), time.ticks_add()) pokrývají každý případ.