3.2. Temporização¶
O módulo time agrupa funções para dormir (pausar o script por uma duração conhecida) e para medir quanto tempo algo demora. Num microcontrolador, estas não são conveniências; são a forma como o script cadencia as interações com o mundo exterior – quanto tempo manter um pino a alto, quanto tempo esperar entre amostras, quanto tempo desde que um botão foi premido pela última vez.
3.2.1. Dormir¶
Três funções de sleep bloqueiam o script pela duração solicitada:
time.sleep(s)– pausar porssegundos. Aceita um float, por issotime.sleep(0.5)aguarda meio segundo.time.sleep_ms(ms)– pausar pormsmilissegundos. O argumento tem de ser um inteiro.time.sleep_us(us)– pausar porusmicrossegundos.
import time
print("now")
time.sleep_ms(500)
print("half a second later")
Use time.sleep_ms() para necessidades típicas de «aguardar um pouco» e time.sleep_us() apenas quando a temporização tem de ser precisa. O time.sleep() simples também funciona, mas as variantes com argumento inteiro evitam a conversão de vírgula flutuante e ficam mais naturais para intervalos curtos.
Sleep é uma chamada bloqueante. Enquanto o script está a dormir, não faz mais nada – não lê um pino, não serve um UART, não atualiza um LED. Recorra a sleep quando o bloqueio é o comportamento desejado; use o padrão não bloqueante abaixo quando não é.
3.2.2. Ler o relógio¶
Para medir quanto tempo um pedaço de código demora, leia o relógio antes e depois:
time.ticks_ms()– o valor atual do contador em milissegundos.time.ticks_us()– o mesmo em microssegundos.
import time
start = time.ticks_ms()
do_work()
elapsed = time.ticks_ms() - start
print("took", elapsed, "ms")
Isto funciona na maior parte das vezes. O contador de ticks faz rollover (volta a zero) após um número grande mas finito de ticks, e a subtração simples ao atravessar esse rollover produz um número negativo ou positivo completamente errado.
O contador de ticks volta a zero quando atinge o limite do inteiro. Uma subtração simples ao atravessar esse rollover é incorreta.¶
3.2.3. ticks_diff¶
Para obter os ticks decorridos corretamente, mesmo num rollover, use time.ticks_diff():
import time
start = time.ticks_ms()
do_work()
elapsed = time.ticks_diff(time.ticks_ms(), start)
print("took", elapsed, "ms")
A ordem dos argumentos é ticks_diff(later, earlier) – a expressão lê-se «quão longe está later depois de earlier«. O resultado é um inteiro com sinal; positivo significa que later é de facto posterior, negativo significa que está no passado. A função trata o rollover internamente.
Dica
Associe sempre time.ticks_ms() / time.ticks_us() com time.ticks_diff(). A subtração simples está correta na maior parte das vezes; a vez em que está errada é quando um script está a funcionar há muito tempo – geralmente o pior momento para depurar um problema de temporização.
3.2.4. Temporização não bloqueante¶
Um script de microcontrolador normalmente tem mais de uma coisa a fazer «ao mesmo tempo»: ler um botão, piscar um LED, fazer polling a um sensor, servir um UART. O sleep não serve para isso – enquanto um sleep está a funcionar, as outras tarefas estão paradas.
O padrão standard é manter um prazo por tarefa e verificar a cada iteração do ciclo se o prazo passou. A decisão de agir é baseada em time.ticks_diff(), nunca em 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)
O LED alterna a cada 500 ms, o sensor é amostrado a cada 100 ms e nenhuma tarefa bloqueia a outra. time.ticks_add() avança um prazo por um incremento conhecido sem problemas com o rollover.
Esta estrutura – um único ciclo, várias tarefas temporizadas, sem sleep no corpo – aparece em todo o lado no código de hardware: remoção de bouncing de interruptores por software, sequenciamento de motores, timeouts de leitura UART. As mesmas três funções (time.ticks_ms(), time.ticks_diff(), time.ticks_add()) cobrem todos os casos.