Los timers en Arduino y otras formas de morir esperando
Ahoj! Dobrý den! Ay, el tiempo… es tan relativo, tan necesario para no volvernos locos. Encima pasa inexorablemente, se nos acaba cuando más lo necesitamos y nos desquicia cuando menos lo necesitamos. Pagaríamos por ganar unos segundos más para acabar ese examen y mataríamos porque se acabara el minuto que tarda la comida en calentarse en el microondas.
Esto del tiempo es complicado. Pues imagínate en Arduino, sin reloj ni nada… Hubo una vez que hablé de las interrupciones en Arduino. Hoy vuelvo a la carga con los timers, que es lo mismo pero diferente. Pero no avanzo nada más que en la entradilla no me dejan hacer spoilers. Lo sabes de sobra 😛
Descubriendo la semejanza entre los timers y las interrupciones
Los timers son como las interrupciones pero con tiempo. La interrupción ya sabes que lo que hace es ponerse en espera sin poner en espera a Arduino. Me explico. Un delay o retraso lo que hace es esperar cierto tiempo a que pase algo. Pero en este tiempo Arduino está trabajando y no puede trabajar en otra cosa.
Una interrupción es una espera que no consume recursos y no está ahí demandando la atención de Arduino. Sino que hacen un trato ella y Arduino y dicen: Mira Arduino yo no te hago esperar, pero cuando una señal me entre por este pin tu vas a perder el cul* por mi y vas a parar todo lo que estés haciendo para atenderme.
Así a lo bruto eso es lo que es una interrución. En un timer o temporizador lo que pasa es que el acuerdo es distinto: Mira Arduino yo no te hago esperar, y te dejo trabajar en lo tuyo pero cuando pase un tiempo te avisaré y entonces me atenderás como es debido. Y al resto de procesos los olvidarás porque el que importa soy yo, el temporizador (Thug life…)
Esto no es útil cuando se trata de esperar unos segundos para enviar un mensaje por el Serial y que no se monten o cuando esperamos entre paso y paso de un stepper motor. Pero si que es útil si lo que necesitas es tomar medidas de temperatura cada hora o encender o apagar una luz a una hora determinada para que no te entren a robar en casa.
Así que ya está todo claro, vamos a embarrarnos un poco, ¿no?
Cómo calcular el tiempo de los timers para los registros
Los chips utilizados en Arduino son el Atmel AVR ATmega168 o el ATmega328. Su diferencia básica es la memoria de cada uno de ellos. Tendrás que mirar según tu Arduino cuál contiene. En el caso del Arduino UNO es el segundo. En el caso del Arduino Yún (que ya sabes que es rarito pero yo lo aprecio mucho) es el ATmega32U4, que no pertenece a ninguno de los dos. Pero ya te digo, es rarito el Yún.
Estos chips contienen tres timers o temporizadores: el timer0, el timer1 y el timer2. El primero y último son de 8 bits y el timer1 es de 16bits. Que tengamos 8 bits o 16bits implica en la resolución, en cuál es el máximo que podemos contar con este contador. En el pirmer caso son 2 elevado a 8 que son 256 veces y con 16 bits se puede contar hasta 65536.
Vale, ahora viene la parte de fumada electrónica, si quieres te la puedes saltar y mirar el final del post, dónde alguien ya ha reparado esto por nosotros. Pero si te atreves, yo sigo.
Peleando con los prescalers del temporizador
Para programar los timers hay que escribir en los registros los valores adecuados. Un registro es un lugar de memoria en el que cabe un número. Ese número es el que nos permite cambiar el timer a nuestro antojo. Para ello tomamos 16MHz como la frecuencia del reloj de Arduino. Esto quiere decir que en un segundo el reloj hace tic 16.000.000 veces. Eso es un tic cada 4 milisegundos… Casi nada…
Para poder alargar estos tiempos están los prescalers, que son: 1, 8, 64, 256 y 1024. Esto significa que en lugar de 4ms puedo tener un tic cada 32ms, 256ms… Para elegir correctamente el prescaler hay que hacer unos cálculos previos. En el caso de que la frecuencia que vayas a utilizar o que quieras utilizar sean 2Hz habrá que dividir los 16000000Hz/256=62500. 256 es el prescaler que elijo y puede que acierte o puede que tenga que aumentar el prescaler porque el prescaler me dé un reloj más rápido de lo que necesito.
Es decir, que igual en lugar de poder medir 2Hz que son 500ms, igual solo me mide hasta 300ms y estoy jod***. Por eso, ahora sé la frecuencia con que mi reloj está funcionando. Al haber dividido mi reloj es más lento que antes, me da tiempos más largos. Y eso es bueno porque hacer cosas cada 4ms es un agobio… Lo que hago ahora es dividir esto entre la frecuencia que a mí me interesa que son 2Hz: 62500/2=31250. Esto son las veces que tengo que contar para llegar a los 500ms. Son muchas, ¿Puedo llegar a contarlas? Eso lo sé por el tamaño del registro que hablábamos antes.
Si es con el de 8 bits… no se puede porque 31250 es mucho más grande que 256. Tendría que modificar el prescaler y elegir uno más grande para que me diese unos tiempos más lentos y que el tic fuese mucho más lento. En el caso de 16 bits todo correcto ya que 65536 es más grande que 31250, me cabe la cuenta ahí 🙂
Información básica sobre Proteción de datos
Responsable ➥ Sergio Luján Cuenca
Finalidad ➥ Gestionar el envío de correos electrónicos con artículos, noticias y publicidad. Todo relacionado con los temas de rufianenlared.com
Legitimación ➥ Consentimiento del interesado
Destinatarios ➥ Estos datos se comunicarán a MailRelay para gestionar el envío de los correos electrónicos
Derechos ➥ Acceder, rectificar y suprimir los datos, así como otros derechos, como se explica en la política de privacidad
Plazo de conservación de los datos ➥ Hasta que se solicite la supresión por parte del interesado
Información adicional ➥ Puedes encontrarla en la política de privacidad y el aviso legal
Modos de un temporizador
Ya tienes ahí la cuenta, sabes que cabe; ahora hay que usarla. Hay dos modos de hacerlo. La primera es la que llaman CTC en la que lo que haces es utilizar el temporizador como comparador. Es decir, Arduino empieza a contar con el prescaler que le hemos dado (cada 4ms, cada 32ms…) y va sumando en un contador. Cuando suma uno compara el valor que tiene, en este caso sería 31250 .Bueno 31249 si somos exactos porque son 31250 veces pero el 0 también cuenta.
Si el número es igual a 31249 entonces se para y salta la interrupción. En la interrupción haremos aquello que queramos y automáticamente el contador de tics se pondrá a cero para volver a empezar a contar hasta el siguiente tiempo. Así, cada x tiempo (que a final el tiempo es la inversa de la frecuencia, por eso antes hablaba de 2Hz que son 500ms) podrás hacer esa actividad cíclica de revisión o de lo que sea.
Ahora entramos en el segundo modo, en el de overflow o desbordamiento. Lo que se hace es esperar a que el contador, ese lugar dónde llevamos la cuenta, llegue al tope y se desborde. Para esto la técnica es la misma o al menos similar. Si el registro es de 65536 quiere decir que caben cuentas de 0 a 65535. A estos 65536 le quitaremos nuestro valor de 31250 lo que nos dará 34286. Esto es lo que teneos que cargar en la cuenta del contador.
Así, en lugar de empezar en cero, empezará en 34286 y tras 31250 cuentas llegará al tope y se desbordará el contador (esto se produce cuando le envías una cuenta más del máximo posible y es por eso que no contamos desde 65535 para hacer la resta, porque tendremos que esperar a 65535+1 para que la interrupción surta efecto).
Es en este momento cuando deberemos poner el contador a 34286 para que no haya problemas. Eso lo haremos al final, cuando ya hayamos hecho lo que teníamos que hacer en la interrupción para evitar que siga contando mientras estamos a lo nuestro.
Para poder poner estos cálculos en Arduino hay que aprender cómo van los registros, así que se queda pendiente… pero no por mucho tiempo 😉
Librerías mágicas para los timers en Arduino
Pero bueno, volvamos a lo práctico. Esto está muy bien para un microcontrolador normal y antiguo. Pero para un Arduino siempre existe algo más sencillo. Alguien ya ha creado una función que nos permite hacer todo esto sin llorar sangre por los ojos picando código ininteligible.
Para ello necesitarás la SimpleTimer Library de Arduino. En esa página se explica cómo instalar la librería, pero no es más que copiar en la carpeta libraries dos archivos, uno termina en .h y otro en .cpp. De esta manera, podrás crear tu temporizador SimpleTimer y luego utilizar el temporizador para llamar una función cada x tiempo con la función setInterval(long tiempo, funcion).
También se puede llamar solamente una vez la función con setTimeout(long tiempo, funcion), de manera que se ejecuta la función una vez y el tiempo se borra por lo que para volver a usarla hay que volver a cargar el tiempo. Es útil por si tienes que ejecutar funciones con tiempos variables.
Por último puedes utilizar setTimer(long tiempo, funcion, int veces) que te permite lanzar una función después de un tiempo pero un número limitado de veces.
El tiempo se acaba… y tú sin darte cuenta…
Yo creo que con esto último puedes sobrevivir en el difícil mundo de los temporizadores. Espero no haberte aburrido en la parte central pero seguro que algún día te aburrirás de la librería y querrás destriparla. Y volverás aquí… o no XD
Espero tus comentarios ahí debajo, seguro que me ayudan a completar el post y a no dejarme ningún detalle en el tintero 😉