time — funkcje związane z czasem

Moduł time zapewnia funkcje do pobierania bieżącej godziny i daty, mierzenia interwałów czasowych oraz do opóźnień.

Epoka czasu: Modele OpenMV Cam oparte na Alif oraz i.MX RT używają epoki POSIX 1970-01-01 00:00:00 UTC. Modele OpenMV Cam oparte na STM32 używają epoki 2000-01-01 00:00:00 UTC. Rok epoki można ustalić w czasie wykonywania za pomocą gmtime(0)[0].

Utrzymywanie rzeczywistej daty/godziny kalendarzowej: Wymaga to zegara czasu rzeczywistego (RTC). Na OpenMV Cam czas systemowy zapewnia obiekt machine.RTC. Bieżący czas kalendarzowy można ustawić za pomocą machine.RTC().datetime(tuple) i jest on utrzymywany przez jeden z poniższych mechanizmów:

  • Baterię podtrzymującą (opcjonalny element w niektórych modelach OpenMV Cam).

  • Sieciowy protokół czasu, taki jak ntptime (wymaga połączenia sieciowego).

  • Ręczne ustawianie przy każdym włączeniu zasilania. RTC jest wówczas zazwyczaj utrzymywany podczas miękkich resetów, ale jest tracony po zaniku zasilania, chyba że zamontowano baterię podtrzymującą.

Jeśli czas kalendarzowy nie jest utrzymywany, poniższe funkcje odwołujące się do bieżącego czasu bezwzględnego nie będą działać zgodnie z oczekiwaniami.

Funkcje

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]

Konwertuje czas secs wyrażony w sekundach od epoki (zobacz powyżej) na 8-elementową krotkę zawierającą: (year, month, mday, hour, minute, second, weekday, yearday). Jeśli secs nie zostanie podane lub ma wartość None, używany jest bieżący czas z RTC.

Funkcja gmtime() zwraca krotkę daty i czasu w UTC, a localtime() zwraca krotkę daty i czasu w czasie lokalnym.

Format wpisów w 8-elementowej krotce jest następujący:

  • year zawiera stulecie (na przykład 2014).

  • month ma zakres 1-12

  • mday ma zakres 1-31

  • hour ma zakres 0-23

  • minute ma zakres 0-59

  • second ma zakres 0-59

  • weekday ma zakres 0-6 dla Pon-Niedz

  • yearday ma zakres 1-366

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

Jest to funkcja odwrotna do localtime. Jej argumentem jest pełna 8-elementowa krotka wyrażająca czas zgodnie z localtime. Zwraca liczbę całkowitą będącą liczbą sekund od epoki czasu.

time.sleep(seconds: float) None

Wstrzymuje wykonywanie na podaną liczbę sekund. seconds może być liczbą zmiennoprzecinkową, aby wstrzymać na ułamkową liczbę sekund. Dla dokładniejszych lub wyłącznie całkowitoliczbowych opóźnień użyj funkcji sleep_ms() i sleep_us().

Wywołanie sleep(), w tym sleep(0), gwarantuje wywołanie oczekujących funkcji wywołań zwrotnych.

time.sleep_ms(ms: int) None

Opóźnia o podaną liczbę milisekund, która powinna być dodatnia lub równa 0.

Ta funkcja opóźni o co najmniej podaną liczbę milisekund, ale może trwać dłużej, jeśli musi zostać wykonane inne przetwarzanie, na przykład obsługa przerwań lub inne wątki. Przekazanie 0 dla ms nadal umożliwi wystąpienie tego innego przetwarzania. Dla dokładniejszych opóźnień użyj sleep_us().

Wywołanie sleep_ms(), w tym sleep_ms(0), gwarantuje wywołanie oczekujących funkcji wywołań zwrotnych.

time.sleep_us(us: int) None

Opóźnia o podaną liczbę mikrosekund, która powinna być dodatnia lub równa 0.

Ta funkcja próbuje zapewnić dokładne opóźnienie wynoszące co najmniej us mikrosekund, ale może trwać dłużej, jeśli system ma do wykonania inne przetwarzanie o wyższym priorytecie.

time.ticks_ms() int

Zwraca rosnący licznik milisekund o dowolnym punkcie odniesienia, który zawija się po pewnej wartości.

Wartość zawinięcia nie jest jawnie udostępniona, ale dla uproszczenia dyskusji będziemy nazywać ją TICKS_MAX. Okres wartości wynosi TICKS_PERIOD = TICKS_MAX + 1. TICKS_PERIOD jest gwarantowaną potęgą dwójki, ale poza tym może różnić się między portami. Ta sama wartość okresu jest używana dla wszystkich funkcji ticks_ms(), ticks_us(), ticks_cpu() (dla uproszczenia). Zatem funkcje te zwracają wartość z zakresu [0 .. TICKS_MAX] włącznie, czyli łącznie TICKS_PERIOD wartości. Należy pamiętać, że używane są tylko wartości nieujemne. W większości przypadków wartości zwracane przez te funkcje należy traktować jako nieprzejrzyste. Jedynymi dostępnymi dla nich operacjami są funkcje ticks_diff() i ticks_add() opisane poniżej.

Uwaga: Wykonywanie standardowych operacji matematycznych (+, -) lub operatorów relacyjnych (<, <=, >, >=) bezpośrednio na tych wartościach doprowadzi do nieprawidłowego wyniku. Wykonywanie operacji matematycznych, a następnie przekazywanie ich wyników jako argumentów do ticks_diff() lub ticks_add() również doprowadzi do nieprawidłowych wyników z tych funkcji.

time.ticks_us() int

Tak samo jak ticks_ms() powyżej, ale w mikrosekundach.

time.ticks_cpu() int

Podobne do ticks_ms() i ticks_us(), ale z najwyższą możliwą rozdzielczością w systemie. Zwykle są to takty zegara CPU i dlatego funkcja została tak nazwana. Nie musi to jednak być zegar CPU, można zamiast niego użyć innego źródła czasu dostępnego w systemie (np. licznika czasu o wysokiej rozdzielczości). Dokładna jednostka czasu (rozdzielczość) tej funkcji nie jest określona na poziomie modułu time, ale dokumentacja konkretnego portu może dostarczyć bardziej szczegółowych informacji. Ta funkcja jest przeznaczona do bardzo precyzyjnych testów wydajności lub bardzo ścisłych pętli czasu rzeczywistego. Unikaj używania jej w kodzie przenośnym. Jest dostępna na wszystkich modelach OpenMV Cam.

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

Przesuwa wartość ticks o podaną liczbę, która może być dodatnia lub ujemna. Mając wartość ticks, funkcja ta pozwala obliczyć wartość ticks o delta taktów przed nią lub po niej, zgodnie z definicją arytmetyki modularnej wartości taktów (zobacz ticks_ms() powyżej). Parametr ticks musi być bezpośrednim wynikiem wywołania funkcji ticks_ms(), ticks_us() lub ticks_cpu() (lub z poprzedniego wywołania ticks_add()). Natomiast delta może być dowolną liczbą całkowitą lub wyrażeniem liczbowym. ticks_add() jest przydatne do obliczania terminów dla zdarzeń/zadań. (Uwaga: aby pracować z terminami, musisz używać funkcji ticks_diff().)

Przykłady:

# 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

Mierzy różnicę taktów między wartościami zwróconymi przez funkcje ticks_ms(), ticks_us() lub ticks_cpu(), jako wartość ze znakiem, która może się zawijać.

Kolejność argumentów jest taka sama jak dla operatora odejmowania, ticks_diff(ticks1, ticks2) ma takie samo znaczenie jak ticks1 - ticks2. Jednak wartości zwracane przez funkcje ticks_ms() itp. mogą się zawijać, więc bezpośrednie użycie na nich odejmowania da nieprawidłowy wynik. Dlatego potrzebna jest funkcja ticks_diff(), która implementuje arytmetykę modularną (a dokładniej pierścieniową), aby uzyskać poprawny wynik nawet dla wartości zawijających się (o ile nie są one od siebie zbyt odległe, zobacz poniżej). Funkcja zwraca wartość ze znakiem z zakresu [-TICKS_PERIOD/2 .. TICKS_PERIOD/2-1] (to typowa definicja zakresu dla binarnych liczb całkowitych ze znakiem w kodzie uzupełnień do dwóch). Jeśli wynik jest ujemny, oznacza to, że ticks1 wystąpiło wcześniej w czasie niż ticks2. W przeciwnym razie oznacza to, że ticks1 wystąpiło po ticks2. Obowiązuje to tylko wtedy, gdy ticks1 i ticks2 są od siebie oddalone o nie więcej niż TICKS_PERIOD/2-1 taktów. Jeśli ten warunek nie jest spełniony, zostanie zwrócony nieprawidłowy wynik. W szczególności, jeśli dwie wartości taktów są oddalone o TICKS_PERIOD/2-1 taktów, funkcja zwróci tę wartość. Jeśli jednak między nimi minęło TICKS_PERIOD/2 taktów czasu rzeczywistego, funkcja zwróci zamiast tego -TICKS_PERIOD/2, tzn. wartość wyniku zawinie się do ujemnego zakresu możliwych wartości.

Nieformalne uzasadnienie powyższych ograniczeń: Załóżmy, że jesteś zamknięty w pokoju bez możliwości śledzenia upływu czasu poza standardowym 12-godzinnym zegarem z 12 podziałkami. Wtedy, jeśli spojrzysz na tarczę teraz, a następnie nie spojrzysz ponownie przez kolejne 13 godzin (np. jeśli zapadniesz w długi sen), to gdy w końcu spojrzysz ponownie, może ci się wydawać, że minęła tylko 1 godzina. Aby uniknąć tego błędu, po prostu patrz na zegar regularnie. Twoja aplikacja powinna robić to samo. Metafora „zbyt długiego snu” odwzorowuje się również bezpośrednio na zachowanie aplikacji: nie pozwól, aby Twoja aplikacja wykonywała jakiekolwiek pojedyncze zadanie zbyt długo. Wykonuj zadania w krokach i mierz czas pomiędzy nimi.

ticks_diff() zostało zaprojektowane tak, aby obsługiwać różne wzorce użycia, między innymi:

  • Odpytywanie z limitem czasu. W tym przypadku kolejność zdarzeń jest znana i będziesz mieć do czynienia tylko z dodatnimi wynikami 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
    
  • Planowanie zdarzeń. W tym przypadku wynik ticks_diff() może być ujemny, jeśli zdarzenie jest spóźnione:

    # 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)
    

Uwaga: Nie przekazuj wartości time() do ticks_diff(), powinieneś używać na nich normalnych operacji matematycznych. Pamiętaj jednak, że time() może (i będzie) również się przepełniać. Jest to znane jako https://en.wikipedia.org/wiki/Year_2038_problem .

time.time() int

Zwraca liczbę sekund, jako liczbę całkowitą, od epoki, zakładając, że bazowy RTC jest ustawiony i utrzymywany w sposób opisany powyżej. Jeśli RTC nie jest ustawiony, funkcja ta zwraca liczbę sekund od specyficznego dla portu punktu odniesienia w czasie (w przypadku płytek wbudowanych bez RTC z podtrzymaniem bateryjnym zwykle od włączenia zasilania lub resetu). Jeśli chcesz tworzyć przenośną aplikację MicroPython, nie powinieneś polegać na tej funkcji w celu uzyskania precyzji wyższej niż jedna sekunda. Jeśli potrzebujesz wyższej precyzji, bezwzględnych znaczników czasu, użyj time_ns(). Jeśli akceptowalne są czasy względne, użyj funkcji ticks_ms() i ticks_us(). Jeśli potrzebujesz czasu kalendarzowego, lepszym wyborem jest gmtime() lub localtime() bez argumentu.

Różnica względem CPython

W CPython funkcja ta zwraca liczbę sekund od epoki Unix (1970-01-01 00:00 UTC) jako wartość zmiennoprzecinkową, zwykle z precyzją mikrosekundową. Na OpenMV Cam zwraca liczbę całkowitą z precyzją jednosekundową – sprzęt nie jest w stanie reprezentować jednocześnie szerokiego zakresu czasu i precyzji poniżej sekundy w liczbie zmiennoprzecinkowej – a epoka różni się w zależności od płytki (zobacz Epoka czasu powyżej). Bez ustawionego RTC z podtrzymaniem bateryjnym funkcja zamiast tego zlicza sekundy od włączenia zasilania/resetu.

time.time_ns() int

Podobne do time(), ale zwraca nanosekundy od epoki, jako liczbę całkowitą (zwykle dużą liczbę całkowitą, więc nastąpi alokacja na stercie).

Konstruktory

class time.clock

Zwraca obiekt zegara.

Metody

tick() None

Rozpoczyna śledzenie upływającego czasu.

fps() float

Zatrzymuje śledzenie upływającego czasu i zwraca bieżącą wartość FPS (klatek na sekundę).

Zawsze wywołuj najpierw tick przed wywołaniem tej funkcji.

avg() float

Zatrzymuje śledzenie upływającego czasu i zwraca bieżący średni upływający czas w milisekundach.

Zawsze wywołuj najpierw tick przed wywołaniem tej funkcji.

reset() None

Resetuje obiekt zegara.