Módulo Timer
Timer llama a una función tuya pasado un tiempo (after) o cada cierto tiempo (every): para un aviso, un parpadeo, leer un sensor de vez en cuando. El tiempo lo cuenta el sistema por su cuenta, pero la función la ejecuta tu programa, entre una instrucción y otra: no corre en paralelo con él (ver Cuándo se ejecuta).

use Timer
Plataformas
Funciona igual en Windows y en todas las placas. Hay hasta 32 timers a la vez: con los 32 en uso, after() y every() devuelven un valor de error y no crean nada.
Funciones
| Función | Qué hace | Devuelve |
|---|---|---|
after(ms, función, dato) | Llama a la función una vez, pasados ms milisegundos. | El número del timer |
every(ms, función, dato) | Llama a la función cada ms milisegundos. | El número del timer |
clear(id) | Para un timer. | true |
Los errores no se lanzan: se devuelven, como valor:
- con un número de argumentos que no es el suyo,
ERR_INVALID_ARG_NUMBER; - con un tiempo que no es un número, algo que no es una función o un dato que no es un número,
ERR_TYPE_MISMATCH; - sin sitio para otro timer:
after()devuelveERR_INDEX_OUT_OF_RANGE, yevery(),ERR_OUT_OF_MEMORY.
try no captura esos errores, y en un if un valor de error cuenta como verdadero. Un número de timer siempre es mayor que 0: compruébalo con id > 0. Más sobre los valores de error en Errores y excepciones.
after
after(ms, función, dato) llama a la función una vez, pasados ms milisegundos. Devuelve el número del timer.
use Timer
var hecho = false
func aviso(id, periodico, dato)
println("Ya: timer ", id, ", periódico ", periodico, ", dato ", dato)
hecho = true
end
var id = Timer.after(500, aviso, 7)
println("Creado el timer ", id)
// El programa tiene que seguir vivo para que salte
while (not hecho)
pause(10)
end
Lo que escribe:
Creado el timer 1
Ya: timer 1, periódico false, dato 7
| Parámetro | Qué es |
|---|---|
ms | Los milisegundos que espera. Admite decimales, pero cuenta la parte entera. |
función | La función a la que llama: ver La función del timer. |
dato | Opcional: un número que recibe la función. Con decimales, se queda la parte entera (2.7 llega como 2). De serie, 0. |
Después de llamar a la función, el timer se borra solo: no hace falta clear().
every
every(ms, función, dato) llama a la función cada ms milisegundos, hasta que la paras con clear(). Los parámetros son los de after(). Devuelve el número del timer.
use Timer
var veces = 0
func tic(id, periodico, dato)
veces = veces + 1
println("Tic ", veces)
if (veces == 3) then
Timer.clear(id) // se para a sí mismo
end
end
Timer.every(200, tic)
while (veces < 3)
pause(10)
end
Lo que escribe:
Tic 1
Tic 2
Tic 3
Usa un intervalo de 1 ms o más: con 0, en Windows salta una sola vez.
clear
clear(id) para el timer y lo borra: su función ya no se llama, aunque tuviera un disparo esperando. Devuelve true, también si el timer no existe o ya había terminado. Un id que no es un entero devuelve ERR_TYPE_MISMATCH.
use Timer
func nunca(id, periodico, dato)
println("Esto no sale")
end
var id = Timer.after(1000, nunca)
println(Timer.clear(id)) // true
println(Timer.clear(id)) // true: ya no existe, y no pasa nada
La función del timer
La función recibe tres parámetros, siempre:
| Parámetro | Qué es |
|---|---|
id | El número del timer que la llama. |
periodico | true si es de every(), false si es de after(). |
dato | El número que pasaste al crear el timer, o 0. |
Si la función no tiene exactamente tres parámetros, el timer no la llama, y no avisa: parece que no salta. Aunque no uses los tres, decláralos.
Cómo se pasa la función
use Timer
var hecho = false
func miAviso(id, periodico, dato)
println("Función")
end
class Semaforo
def init()
this.estado = 0
end
def cambiar(id, periodico, dato)
this.estado = (this.estado + 1) % 3
end
end
var cruce = Semaforo()
// 1) La función, por su nombre, sin comillas
Timer.after(100, miAviso)
// 2) Una lambda, sin declarar ninguna función aparte
Timer.after(200, fn(id, p, d):
println("Lambda")
end)
// 3) Un método de un objeto: se ejecuta con su this
Timer.every(100, cruce.cambiar)
// 4) El nombre de una función global, entre comillas
Timer.after(300, "miAviso")
Timer.after(400, fn(id, p, d):
hecho = true
end)
while (not hecho)
pause(10)
end
- Con un método (
cruce.cambiar), el timer mantiene vivo el objeto mientras exista el timer: no hace falta guardarlo en otra variable. Se suelta al hacerclear(), o al saltar un timer deafter(). - Con el nombre entre comillas, la función se busca al saltar el timer, entre las funciones globales: no vale para métodos. Si no existe, no pasa nada. Las otras tres formas se comprueban al crear el timer.
Cuándo se ejecuta
El timer mide el tiempo por su cuenta, pero la función la ejecuta la VM dentro de tu programa:
- Solo mientras el programa sigue vivo. Al terminar el programa se borran sus timers, y lo que faltaba por saltar ya no salta. Por eso los ejemplos acaban en un bucle.
- En los puntos seguros de la VM: al dar la vuelta un bucle, y al llamar a una función o volver de ella. Nunca dentro de
pause(): lo que salte durante una pausa espera a que acabe. Por eso la función puede llegar algo más tarde de lo pedido. - De una en una. Mientras corre una función de un timer no empieza otra: las que faltan esperan su turno.
Una función de timer tiene que ser corta: mientras corre, tu programa espera, y los demás timers también.
Ejemplo completo
Tres LED que se encienden por turnos cada medio segundo, y un segundo timer que lo apaga todo a los 3 segundos. Los LED van en los pines 2, 4 y 5: cámbialos por los de tu placa.
use Timer, GPIO
const LED_ROJO = 2
const LED_VERDE = 4
const LED_AZUL = 5
var estado = 0
var encendido = true
func cicloLuces(id, periodico, dato)
GPIO.write(LED_ROJO, 0)
GPIO.write(LED_VERDE, 0)
GPIO.write(LED_AZUL, 0)
if (estado == 0) then
GPIO.write(LED_ROJO, 1)
elsif (estado == 1) then
GPIO.write(LED_VERDE, 1)
else
GPIO.write(LED_AZUL, 1)
end
estado = (estado + 1) % 3
end
// El dato es el número del timer del ciclo, para pararlo
func apagarTodo(id, periodico, cicloId)
Timer.clear(cicloId)
GPIO.write(LED_ROJO, 0)
GPIO.write(LED_VERDE, 0)
GPIO.write(LED_AZUL, 0)
encendido = false
end
GPIO.pinmode(LED_ROJO, GPIO.OUTPUT)
GPIO.pinmode(LED_VERDE, GPIO.OUTPUT)
GPIO.pinmode(LED_AZUL, GPIO.OUTPUT)
var ciclo = Timer.every(500, cicloLuces)
Timer.after(3000, apagarTodo, ciclo)
while (encendido)
pause(10)
end
println("Sistema apagado")
Trampas y problemas conocidos
- El programa tiene que seguir vivo. Si termina, sus timers se borran sin saltar.
- Nada salta dentro de
pause(). Una pausa larga retrasa todas las funciones de timer hasta que acaba. - La función tiene que tener tres parámetros. Con otro número, el timer no la llama y no avisa.
- Los errores se devuelven, no se lanzan. Comprueba el número del timer con
id > 0. - Como mucho 32 timers. Si pides uno más, te devuelve un valor de error y no lo crea. Si necesitas muchos, usa un solo timer de
every()que se ocupe de varias tareas. - El dato solo puede ser un número, y llega sin decimales.
every()con 0 ms salta una sola vez en Windows: usa 1 ms o más.
Todos los problemas conocidos de JARU, juntos, están en Problemas conocidos.