time — funcții legate de timp

Modulul time oferă funcții pentru obținerea orei și datei curente, pentru măsurarea intervalelor de timp și pentru întârzieri.

Epoca de timp: OpenMV Cam bazate pe Alif și i.MX RT folosesc epoca POSIX de la 1970-01-01 00:00:00 UTC. OpenMV Cam bazate pe STM32 folosesc o epocă de la 2000-01-01 00:00:00 UTC. Anul epocii poate fi determinat la momentul execuției cu gmtime(0)[0].

Menținerea datei/orei calendaristice reale: Aceasta necesită un ceas de timp real (RTC). Pe OpenMV Cam, timpul sistemului este furnizat de obiectul machine.RTC. Ora calendaristică curentă poate fi setată cu machine.RTC().datetime(tuple) și este menținută prin una dintre următoarele:

  • O baterie de rezervă (o componentă opțională pe unele OpenMV Cam).

  • Un protocol de timp în rețea, cum ar fi ntptime (necesită o conexiune la rețea).

  • Setarea manuală la fiecare pornire. RTC-ul este apoi de obicei menținut între resetările soft, dar se pierde la întreruperea alimentării, cu excepția cazului în care este montată o baterie de rezervă.

Dacă ora calendaristică nu este menținută, funcțiile de mai jos care fac referire la timpul absolut curent nu se vor comporta conform așteptărilor.

Funcții

time.gmtime(secs: int | None = None) Tuple[int, int, int, int, int, int, int, int]
time.localtime(secs: int | None = None) Tuple[int, int, int, int, int, int, int, int]

Convertește timpul secs exprimat în secunde de la epocă (vezi mai sus) într-un tuplu de 8 elemente care conține: (year, month, mday, hour, minute, second, weekday, yearday). Dacă secs nu este furnizat sau este None, atunci se folosește ora curentă din RTC.

Funcția gmtime() returnează un tuplu dată-oră în UTC, iar localtime() returnează un tuplu dată-oră în ora locală.

Formatul intrărilor din tuplul de 8 elemente este:

  • year include secolul (de exemplu 2014).

  • month este 1-12

  • mday este 1-31

  • hour este 0-23

  • minute este 0-59

  • second este 0-59

  • weekday este 0-6 pentru luni-duminică

  • yearday este 1-366

time.mktime(date_time_tuple: Tuple[int, int, int, int, int, int, int, int]) int

Aceasta este funcția inversă a lui localtime. Argumentul ei este un tuplu complet de 8 elemente care exprimă un timp conform localtime. Returnează un întreg care reprezintă numărul de secunde de la epoca de timp.

time.sleep(seconds: float) None

Așteaptă (sleep) pentru numărul dat de secunde. seconds poate fi un număr în virgulă mobilă, pentru a aștepta un număr fracționar de secunde. Pentru întârzieri mai fine sau exclusiv întregi, folosiți funcțiile sleep_ms() și sleep_us().

Apelarea sleep(), inclusiv sleep(0), garantează apelarea funcțiilor de retroapelare (callback) în așteptare.

time.sleep_ms(ms: int) None

Întârzie pentru numărul dat de milisecunde, care trebuie să fie pozitiv sau 0.

Această funcție va întârzia cel puțin numărul dat de milisecunde, dar poate dura mai mult dacă trebuie să aibă loc alte procesări, de exemplu gestionarele de întreruperi sau alte fire de execuție. Transmiterea valorii 0 pentru ms va permite totuși desfășurarea acestor alte procesări. Folosiți sleep_us() pentru întârzieri mai precise.

Apelarea sleep_ms(), inclusiv sleep_ms(0), garantează apelarea funcțiilor de retroapelare (callback) în așteptare.

time.sleep_us(us: int) None

Întârzie pentru numărul dat de microsecunde, care trebuie să fie pozitiv sau 0.

Această funcție încearcă să ofere o întârziere precisă de cel puțin us microsecunde, dar poate dura mai mult dacă sistemul are alte procesări cu prioritate mai mare de efectuat.

time.ticks_ms() int

Returnează un contor de milisecunde crescător cu un punct de referință arbitrar, care se reia (wrap around) după o anumită valoare.

Valoarea de reluare (wrap-around) nu este expusă explicit, dar ne vom referi la ea ca TICKS_MAX pentru a simplifica discuția. Perioada valorilor este TICKS_PERIOD = TICKS_MAX + 1. TICKS_PERIOD este garantat a fi o putere a lui doi, dar în rest poate diferi de la port la port. Aceeași valoare a perioadei este folosită pentru toate funcțiile ticks_ms(), ticks_us(), ticks_cpu() (pentru simplitate). Astfel, aceste funcții vor returna o valoare în intervalul [0 .. TICKS_MAX], inclusiv, în total TICKS_PERIOD valori. Rețineți că se folosesc doar valori nenegative. În cea mai mare parte, ar trebui să tratați valorile returnate de aceste funcții ca fiind opace. Singurele operații disponibile pentru ele sunt funcțiile ticks_diff() și ticks_add() descrise mai jos.

Notă: Efectuarea de operații matematice standard (+, -) sau a operatorilor relaționali (<, <=, >, >=) direct asupra acestor valori va duce la rezultate invalide. Efectuarea de operații matematice și apoi transmiterea rezultatelor lor ca argumente către ticks_diff() sau ticks_add() va duce, de asemenea, la rezultate invalide din partea acestor ultime funcții.

time.ticks_us() int

La fel ca ticks_ms() de mai sus, dar în microsecunde.

time.ticks_cpu() int

Similar cu ticks_ms() și ticks_us(), dar cu cea mai mare rezoluție posibilă din sistem. De obicei aceasta este reprezentată de ciclurile CPU, motiv pentru care funcția este denumită astfel. Dar nu trebuie neapărat să fie un ceas CPU; poate fi folosită în schimb o altă sursă de sincronizare disponibilă în sistem (de exemplu, un temporizator de înaltă rezoluție). Unitatea exactă de timp (rezoluția) a acestei funcții nu este specificată la nivelul modulului time, dar documentația pentru un anumit port poate oferi informații mai specifice. Această funcție este destinată evaluării comparative (benchmarking) foarte fine sau buclelor în timp real foarte strânse. Evitați să o folosiți în cod portabil. Este disponibilă pe toate OpenMV Cam.

time.ticks_add(ticks: int, delta: int) int

Decalează valoarea ticks cu un număr dat, care poate fi pozitiv sau negativ. Pentru o valoare ticks dată, această funcție permite calcularea valorii ticks cu delta ticks înainte sau după aceasta, conform definiției aritmeticii modulare a valorilor de tip tick (vezi ticks_ms() mai sus). Parametrul ticks trebuie să fie un rezultat direct al apelului funcțiilor ticks_ms(), ticks_us() sau ticks_cpu() (sau dintr-un apel anterior la ticks_add()). Totuși, delta poate fi un număr întreg arbitrar sau o expresie numerică. ticks_add() este utilă pentru calcularea termenelor-limită (deadline) pentru evenimente/sarcini. (Notă: trebuie să folosiți funcția ticks_diff() pentru a lucra cu termene-limită.)

Exemple:

# Find out what ticks value there was 100ms ago
print(ticks_add(time.ticks_ms(), -100))

# Calculate deadline for operation and test for it
deadline = ticks_add(time.ticks_ms(), 200)
while ticks_diff(deadline, time.ticks_ms()) > 0:
    do_a_little_of_something()

# Find out TICKS_MAX used by this port
print(ticks_add(0, -1))
time.ticks_diff(ticks1: int, ticks2: int) int

Măsoară diferența de ticks dintre valorile returnate de funcțiile ticks_ms(), ticks_us() sau ticks_cpu(), sub formă de valoare cu semn care se poate relua (wrap around).

Ordinea argumentelor este aceeași ca pentru operatorul de scădere, ticks_diff(ticks1, ticks2) are aceeași semnificație ca ticks1 - ticks2. Totuși, valorile returnate de funcțiile ticks_ms() etc. se pot relua (wrap around), așa că utilizarea directă a scăderii asupra lor va produce un rezultat incorect. De aceea este necesară ticks_diff(); ea implementează aritmetica modulară (sau mai exact, inelară) pentru a produce un rezultat corect chiar și pentru valorile reluate (atât timp cât nu sunt prea îndepărtate între ele, vezi mai jos). Funcția returnează o valoare cu semn în intervalul [-TICKS_PERIOD/2 .. TICKS_PERIOD/2-1] (aceasta este o definiție tipică de interval pentru întregi binari cu semn în complement față de doi). Dacă rezultatul este negativ, înseamnă că ticks1 a avut loc mai devreme în timp decât ticks2. În caz contrar, înseamnă că ticks1 a avut loc după ticks2. Acest lucru este valabil doar dacă ticks1 și ticks2 sunt la o distanță de cel mult TICKS_PERIOD/2-1 ticks unul de altul. Dacă acest lucru nu se respectă, va fi returnat un rezultat incorect. În mod specific, dacă două valori tick sunt la o distanță de TICKS_PERIOD/2-1 ticks, acea valoare va fi returnată de funcție. Totuși, dacă TICKS_PERIOD/2 de ticks de timp real au trecut între ele, funcția va returna în schimb -TICKS_PERIOD/2, adică valoarea rezultatului se va relua în intervalul negativ al valorilor posibile.

Justificarea informală a constrângerilor de mai sus: Să presupunem că sunteți închis într-o cameră fără niciun mijloc de a monitoriza trecerea timpului, cu excepția unui ceas standard cu 12 diviziuni. Atunci, dacă vă uitați la cadran acum și nu vă mai uitați timp de încă 13 ore (de exemplu, dacă adormiți pentru un somn lung), atunci când în sfârșit vă uitați din nou, vi se poate părea că a trecut doar 1 oră. Pentru a evita această greșeală, uitați-vă la ceas în mod regulat. Aplicația dvs. ar trebui să facă același lucru. Metafora „somn prea lung” se aplică direct și comportamentului aplicației: nu lăsați aplicația să ruleze nicio sarcină individuală prea mult timp. Rulați sarcinile în pași și efectuați evidența timpului între ei.

ticks_diff() este concepută pentru a se adapta la diverse tipare de utilizare, printre care:

  • Interogare (polling) cu timeout. În acest caz, ordinea evenimentelor este cunoscută și veți avea de-a face doar cu rezultate pozitive ale ticks_diff()

    # Wait for GPIO pin to be asserted, but at most 500us
    start = time.ticks_us()
    while pin.value() == 0:
        if time.ticks_diff(time.ticks_us(), start) > 500:
            raise TimeoutError
    
  • Programarea evenimentelor. În acest caz, rezultatul ticks_diff() poate fi negativ dacă un eveniment este întârziat:

    # This code snippet is not optimized
    now = time.ticks_ms()
    scheduled_time = task.scheduled_time()
    if ticks_diff(scheduled_time, now) > 0:
        print("Too early, let's nap")
        sleep_ms(ticks_diff(scheduled_time, now))
        task.run()
    elif ticks_diff(scheduled_time, now) == 0:
        print("Right at time!")
        task.run()
    elif ticks_diff(scheduled_time, now) < 0:
        print("Oops, running late, tell task to run faster!")
        task.run(run_faster=true)
    

Notă: Nu transmiteți valori time() către ticks_diff(), ci ar trebui să folosiți operații matematice normale asupra lor. Dar rețineți că time() poate (și va) depăși (overflow). Acest lucru este cunoscut sub numele de https://en.wikipedia.org/wiki/Year_2038_problem .

time.time() int

Returnează numărul de secunde, sub formă de întreg, de la epocă, presupunând că RTC-ul subiacent este setat și menținut conform descrierii de mai sus. Dacă un RTC nu este setat, această funcție returnează numărul de secunde de la un punct de referință în timp specific portului (pentru plăcile încorporate fără un RTC cu baterie de rezervă, de obicei de la pornire sau resetare). Dacă doriți să dezvoltați o aplicație MicroPython portabilă, nu ar trebui să vă bazați pe această funcție pentru a oferi o precizie mai mare de o secundă. Dacă aveți nevoie de precizie mai mare, marcaje de timp absolute, folosiți time_ns(). Dacă timpii relativi sunt acceptabili, atunci folosiți funcțiile ticks_ms() și ticks_us(). Dacă aveți nevoie de timp calendaristic, gmtime() sau localtime() fără argument este o alegere mai bună.

Diferență față de CPython

În CPython această funcție returnează numărul de secunde de la epoca Unix (1970-01-01 00:00 UTC) sub formă de valoare în virgulă mobilă, de obicei cu precizie de microsecunde. Pe OpenMV Cam returnează un întreg cu precizie de o secundă – hardware-ul nu poate reprezenta simultan un interval de timp mare și o precizie sub-secundă într-un float – iar epoca diferă în funcție de placă (vezi Epoca de timp de mai sus). Fără un RTC cu baterie de rezervă care a fost setat, numără în schimb secundele de la pornire/resetare.

time.time_ns() int

Similar cu time(), dar returnează nanosecunde de la epocă, sub formă de întreg (de obicei un întreg mare, deci va aloca pe heap).

Constructori

class time.clock

Returnează un obiect clock.

Metode

tick() None

Începe urmărirea timpului scurs.

fps() float

Oprește urmărirea timpului scurs și returnează valoarea FPS curentă (cadre pe secundă).

Apelați întotdeauna mai întâi tick înainte de a apela această funcție.

avg() float

Oprește urmărirea timpului scurs și returnează timpul mediu scurs curent în milisecunde.

Apelați întotdeauna mai întâi tick înainte de a apela această funcție.

reset() None

Resetează obiectul clock.