3.2. Mjerenje vremena#

Modul time grupira funkcije za spavanje (pauziranje skripte na poznato trajanje) i za mjerenje koliko nešto traje. Na mikrokontroleru to nisu samo zgodni dodaci; to je način na koji skripta usklađuje interakcije s vanjskim svijetom – koliko dugo držati pin na visokoj razini, koliko dugo čekati između uzoraka, koliko je vremena prošlo otkad je gumb zadnji put pritisnut.

3.2.1. Spavanje#

Tri funkcije spavanja blokiraju skriptu na traženo trajanje:

import time

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

Koristite time.sleep_ms() za uobičajene potrebe „pričekaj malo”, a time.sleep_us() samo kada vrijeme mora biti precizno. Obični time.sleep() također je u redu, ali varijante s cjelobrojnim argumentom izbjegavaju pretvorbu u pomični zarez i prirodnije se čitaju za kratke intervale.

Spavanje je blokirajući poziv. Dok skripta spava, ne radi ništa drugo – ne čita pin, ne poslužuje UART, ne ažurira LED-icu. Posegnite za sleep kada je blokiranje upravo ono što želite; koristite neblokirajući obrazac u nastavku kada nije.

3.2.2. Čitanje sata#

Da biste izmjerili koliko traje neki dio koda, pročitajte sat prije i poslije:

import time

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

Ovo radi većinu vremena. Brojač otkucaja se prelijeva (vraća se na nulu) nakon velikog, ali konačnog broja otkucaja, a naivno oduzimanje preko tog prelijevanja daje potpuno pogrešan negativan ili pozitivan broj.

Number line from 0 to MAX with a start tick near MAX and an end tick near 0; a dashed wrap-around arrow shows that after MAX the counter returns to 0.

Brojač otkucaja vraća se na nulu kada dosegne cjelobrojnu granicu. Obično oduzimanje preko tog prelijevanja je pogrešno.#

3.2.3. ticks_diff#

Da biste ispravno dobili proteklo vrijeme otkucaja, čak i preko prelijevanja, koristite time.ticks_diff():

import time

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

Redoslijed argumenata je ticks_diff(later, earlier) – izraz se čita „koliko je later nakon earlier”. Rezultat je predznačeni cijeli broj; pozitivan znači da je later doista kasnije, negativan znači da je u prošlosti. Funkcija interno obrađuje prelijevanje.

Savjet

Uvijek uparite time.ticks_ms() / time.ticks_us() s time.ticks_diff(). Sirovo oduzimanje točno je većinu vremena; trenutak kada je pogrešno jest kada skripta radi već dugo – obično najgori trenutak za otklanjanje pogreške u vremenu.

3.2.4. Neblokirajuće mjerenje vremena#

Skripta za mikrokontroler obično ima više od jedne stvari koju treba obaviti „u isto vrijeme”: čitati gumb, treptati LED-icom, prozirati senzor, posluživati UART. sleep za to nije dobar – dok jedan sleep traje, ostali zadaci su zaustavljeni.

Standardni obrazac je da se za svaki zadatak drži rok, te da se u svakoj petlji provjeri je li rok prošao. Odluka o djelovanju gradi se na time.ticks_diff(), nikada 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-ica se prebacuje svakih 500 ms, senzor se prozire svakih 100 ms, i nijedan zadatak ne blokira drugi. time.ticks_add() pomiče rok za poznati prirast bez upadanja u zamku prelijevanja.

Taj oblik – jedna petlja, nekoliko vremenski raspoređenih zadataka, bez sleep u tijelu – pojavljuje se posvuda gdje ide hardverski kod: softversko uklanjanje podrhtavanja sklopki, sekvenciranje motora, istek vremena čitanja UART-a. Ista tri funkcije (time.ticks_ms(), time.ticks_diff(), time.ticks_add()) pokrivaju svaki slučaj.