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 leva. Em um microcontrolador, isso não são recursos opcionais; é como o script ritma as interações com o mundo externo – por quanto tempo manter um pino em nível alto, quanto esperar entre amostras, quanto tempo se passou desde que um botão foi pressionado pela última vez.

3.2.1. Dormindo#

Três funções de dormir bloqueiam o script pela duração solicitada:

import time

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

Use time.sleep_ms() para as necessidades típicas de “esperar um pouco” e time.sleep_us() apenas quando a temporização precisar ser precisa. O simples time.sleep() também serve, mas as variantes com argumento inteiro evitam a conversão de ponto flutuante e se leem de forma mais natural para intervalos curtos.

Dormir é uma chamada bloqueante. Enquanto o script está dormindo, ele não faz mais nada – não lê um pino, não atende uma UART, não atualiza um LED. Recorra a sleep quando bloquear for o que você deseja; use o padrão não bloqueante abaixo quando não for.

3.2.2. Lendo o relógio#

Para medir quanto tempo um trecho de código leva, leia o relógio antes e depois:

import time

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

Isso funciona na maioria das vezes. O contador de ticks transborda (volta a zero) após um número grande, porém finito, de ticks, e uma subtração ingênua através desse transbordo produz um número negativo ou positivo absurdamente errado.

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.

O contador de ticks volta a zero quando atinge o limite do inteiro. Uma subtração simples através desse transbordo está errada.#

3.2.3. ticks_diff#

Para obter os ticks decorridos corretamente, mesmo através de um transbordo, 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 se lê “quão depois later está de earlier“. O resultado é um inteiro com sinal; positivo significa que later é de fato posterior, negativo significa que está no passado. A função trata o transbordo internamente.

Dica

Sempre combine time.ticks_ms() / time.ticks_us() com time.ticks_diff(). A subtração crua está correta na maioria das vezes; a hora em que ela erra é quando um script está em execução há muito tempo – normalmente o pior momento para depurar uma falha de temporização.

3.2.4. Temporização não bloqueante#

Um script de microcontrolador normalmente tem mais de uma coisa para fazer “ao mesmo tempo”: ler um botão, piscar um LED, consultar um sensor, atender uma UART. sleep não serve para isso – enquanto um sleep está em execução, as outras tarefas ficam paradas.

O padrão usual é manter um prazo (deadline) por tarefa e verificar a cada laço se o prazo já passou. A decisão de agir é construída sobre time.ticks_diff(), nunca sobre 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 é consultado a cada 100 ms, e nenhuma das tarefas bloqueia a outra. time.ticks_add() avança um prazo por um incremento conhecido sem cair na armadilha do transbordo.

Esse formato – um único laço, várias tarefas temporizadas, nenhum sleep no corpo – aparece em todo lugar onde código de hardware existe: debounce de chaves por software, sequenciamento de motores, timeouts de leitura de UART. As mesmas três funções (time.ticks_ms(), time.ticks_diff(), time.ticks_add()) cobrem todos os casos.