3.2. Temporización#
El módulo time agrupa funciones para dormir (pausar el script durante una duración conocida) y para medir cuánto tarda algo. En un microcontrolador estas no son funciones opcionales; son la forma en que el script regula sus interacciones con el mundo exterior – cuánto tiempo mantener un pin en alto, cuánto esperar entre muestras, cuánto tiempo ha pasado desde la última vez que se pulsó un botón.
3.2.1. Dormir#
Tres funciones de dormir bloquean el script durante la duración solicitada:
time.sleep(s)– pausa durantessegundos. Acepta un valor de coma flotante, así quetime.sleep(0.5)espera medio segundo.time.sleep_ms(ms)– pausa durantemsmilisegundos. El argumento debe ser un entero.time.sleep_us(us)– pausa duranteusmicrosegundos.
import time
print("now")
time.sleep_ms(500)
print("half a second later")
Usa time.sleep_ms() para las necesidades típicas de «esperar un poco» y time.sleep_us() solo cuando la temporización deba ser ajustada. La time.sleep() simple también es válida, pero las variantes con argumento entero evitan la conversión de coma flotante y se leen de forma más natural para intervalos cortos.
Dormir es una llamada bloqueante. Mientras el script está durmiendo, no está haciendo nada más – ni leyendo un pin, ni atendiendo un UART, ni actualizando un LED. Recurre a sleep cuando bloquear sea lo que deseas; usa el patrón no bloqueante de más abajo cuando no lo sea.
3.2.2. Leer el reloj#
Para medir cuánto tarda una pieza de código, lee el reloj antes y después:
time.ticks_ms()– el valor actual de ticks en milisegundos.time.ticks_us()– lo mismo en microsegundos.
import time
start = time.ticks_ms()
do_work()
elapsed = time.ticks_ms() - start
print("took", elapsed, "ms")
Esto funciona la mayor parte del tiempo. El contador de ticks se desborda (vuelve a cero) tras un número grande pero finito de ticks, y una resta ingenua a través de ese desbordamiento produce un número negativo o positivo tremendamente erróneo.
El contador de ticks vuelve a cero cuando alcanza el límite entero. Una resta simple a través de ese desbordamiento es incorrecta.#
3.2.3. ticks_diff#
Para obtener correctamente los ticks transcurridos, incluso a través de un desbordamiento, usa time.ticks_diff():
import time
start = time.ticks_ms()
do_work()
elapsed = time.ticks_diff(time.ticks_ms(), start)
print("took", elapsed, "ms")
El orden de los argumentos es ticks_diff(later, earlier) – la expresión se lee «cuánto después está later respecto de earlier». El resultado es un entero con signo; positivo significa que later es efectivamente posterior, negativo significa que está en el pasado. La función gestiona el desbordamiento internamente.
Truco
Empareja siempre time.ticks_ms() / time.ticks_us() con time.ticks_diff(). La resta cruda es correcta la mayor parte del tiempo; el momento en que falla es cuando un script lleva mucho tiempo en ejecución – normalmente el peor momento para depurar un fallo de temporización.
3.2.4. Temporización no bloqueante#
Un script de microcontrolador suele tener más de una cosa que hacer «al mismo tiempo»: leer un botón, parpadear un LED, sondear un sensor, atender un UART. sleep no sirve para eso – mientras un sleep se está ejecutando, las demás tareas quedan paradas.
El patrón estándar es mantener un plazo límite por tarea y comprobar en cada iteración del bucle si el plazo ha pasado. La decisión de actuar se construye 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)
El LED conmuta cada 500 ms, el sensor se sondea cada 100 ms y ninguna tarea bloquea a la otra. time.ticks_add() adelanta un plazo límite en un incremento conocido sin caer en el problema del desbordamiento.
Esta forma – un único bucle, varias tareas temporizadas, sin sleep en el cuerpo – aparece en todas partes donde va el código de hardware: antirrebote por software de interruptores, secuenciación de motores, tiempos de espera de lectura de UART. Las mismas tres funciones (time.ticks_ms(), time.ticks_diff(), time.ticks_add()) cubren todos los casos.