3.2. Ajoitus

time-moduuli kokoaa yhteen funktioita nukkumiseen (skriptin keskeyttäminen tunnetuksi ajaksi) ja sen mittaamiseen, kuinka kauan jokin kestää. Mikrokontrollerilla nämä eivät ole mukavia lisiä; ne ovat tapa, jolla skripti tahdittaa vuorovaikutuksensa ulkomaailman kanssa – kuinka kauan nastaa pidetään ylhäällä, kuinka kauan odotetaan näytteiden välillä, kuinka kauan painikkeen viimeisestä painalluksesta on kulunut.

3.2.1. Nukkuminen

Kolme nukkumisfunktiota estää skriptin pyydetyksi ajaksi:

  • time.sleep(s) – tauotus s sekunnin ajaksi. Hyväksyy liukuluvun, joten time.sleep(0.5) odottaa puoli sekuntia.

  • time.sleep_ms(ms) – tauotus ms millisekunnin ajaksi. Argumentin on oltava kokonaisluku.

  • time.sleep_us(us) – tauotus us mikrosekunnin ajaksi.

import time

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

Käytä time.sleep_ms() -funktiota tyypillisiin ”odota hetki” -tarpeisiin ja time.sleep_us() -funktiota vain, kun ajoituksen on oltava tiukka. Tavallinen time.sleep() on myös kelvollinen, mutta kokonaislukuargumenttiset muunnelmat välttävät liukulukumuunnoksen ja lukeutuvat luontevammin lyhyille väleille.

Nukkuminen on estävä kutsu. Skriptin nukkuessa se ei tee mitään muuta – ei lue nastaa, ei palvele UARTia, ei päivitä LEDiä. Käytä sleep -funktiota, kun estäminen on sitä mitä haluat; käytä alla olevaa estämätöntä mallia, kun ei ole.

3.2.2. Kellon lukeminen

Mittaaksesi kuinka kauan koodinpätkä kestää, lue kello ennen ja jälkeen:

import time

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

Tämä toimii useimmiten. Tikkilaskuri kiertää ympäri (palaa takaisin nollaan) suuren mutta äärellisen tikkimäärän jälkeen, ja naiivi vähennyslasku tuon kierron yli tuottaa villisti väärän negatiivisen tai positiivisen luvun.

Lukusuora nollasta MAXiin, jossa aloitustikki on lähellä MAXia ja lopetustikki lähellä nollaa; katkoviivainen kiertonuoli osoittaa, että MAXin jälkeen laskuri palaa nollaan.

Tikkilaskuri kiertää takaisin nollaan saavuttaessaan kokonaislukurajan. Tavallinen vähennyslasku tuon kierron yli on väärin.

3.2.3. ticks_diff

Saadaksesi kuluneet tikit oikein, jopa kierron yli, käytä time.ticks_diff() -funktiota:

import time

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

Argumenttien järjestys on ticks_diff(later, earlier) – lauseke lukeutuu ”kuinka kaukana myöhempi on aiemman jälkeen”. Tulos on etumerkillinen kokonaisluku; positiivinen tarkoittaa, että later on todella myöhemmin, negatiivinen tarkoittaa, että se on menneisyydessä. Funktio käsittelee kierron sisäisesti.

Vihje

Yhdistä aina time.ticks_ms() / time.ticks_us() time.ticks_diff() -funktion kanssa. Raaka vähennyslasku on oikein useimmiten; aika jolloin se on väärin, on silloin kun skripti on ollut käynnissä pitkään – yleensä huonoin aika debugata ajoitushäiriötä.

3.2.4. Estämätön ajoitus

Mikrokontrolleriskriptillä on yleensä useampi kuin yksi asia tehtävänä ”samanaikaisesti”: lukea painiketta, vilkuttaa LEDiä, pollata sensoria, palvella UARTia. sleep ei kelpaa siihen – yhden sleep -kutsun ollessa käynnissä muut tehtävät ovat jumissa.

Vakiomalli on pitää tehtäväkohtaista määräaikaa ja tarkistaa joka silmukassa, onko määräaika ohitettu. Päätös toimia rakentuu time.ticks_diff() -funktion varaan, ei koskaan sleep -funktion varaan:

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 vaihtaa tilaa 500 ms:n välein, sensori pollataan 100 ms:n välein, eikä kumpikaan tehtävä estä toista. time.ticks_add() edistää määräaikaa tunnetulla lisäyksellä joutumatta kierron uhriksi.

Tämä muoto – yksittäinen silmukka, useita ajoitettuja tehtäviä, ei sleep -kutsua rungossa – esiintyy kaikkialla missä laitteistokoodia on: kytkimien ohjelmallinen värähtelynvaimennus, moottorin sekvenssointi, UART-lukuaikakatkaisut. Samat kolme funktiota (time.ticks_ms(), time.ticks_diff(), time.ticks_add()) kattavat jokaisen tapauksen.