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í nassekund. Přijímá float, takžetime.sleep(0.5)čeká půl sekundy.time.sleep_ms(ms)– pozastaví namsmilisekund. Argument musí být celé číslo.time.sleep_us(us)– pozastaví nausmikrosekund.
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:
time.ticks_ms()– aktuální hodnota tiků v milisekundách.time.ticks_us()– totéž v mikrosekundách.
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.
Čí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.