Sie sind auf Seite 1von 16

ARDUINO Y LOS TIMERS

http://www.prometec.net/timers/

VUELTAS CON LAS


INTERRUPCIONES
TEMPORIZADAS
Hasta ahora, hemos medido el tiempo en milisegundos y usado el delay para
temporizar las cosas, así usábamos un delay de unos 250 ms para que el
blinking LED se encendiese y se apagase, tranquilamente.
El problema del delay () es que congela Arduino el tiempo especificado.
Mientras no sea mucho, bueno, podemos aceptarlo, pero imagínate que
queremos hacer el blinking LED para un semáforo, donde los tiempos de
espera van de digamos 30 segundos a 1 minuto.
Podemos pedirle que haga un delay de 60 segundos * 1.000 = 60.000 millis,
pero claro esto supone que no podremos hacer ninguna otra cosa hasta que no
pase un minuto, ni ver si nos pulsan un botón, o refrescar una pantalla con el
tiempo que queda de semáforo.
Así que no parece muy buena idea usar delays en muchas situaciones. No es
raro que queramos programar tareas periódicas en nuestros Arduinos en
rangos que van desde unos microsegundos hasta varios minutos, pero
queremos hacerlo de un modo que entre tanto podamos seguir trabajando.
Para eso tenemos las interrupciones programadas o Timers, para que nos
toquen el timbre cuando hay que ejecutar una función programada, sin
necesidad de estar continuamente comprobando si es la hora.
Ya vimos en una sesión anterior el concepto de interrupción hardware. Es el
equivalente a un timbre que nos avisa de que alguien está en la puerta y
debemos atenderle.
Arduino dispone además de una segunda clase de interrupciones, los Timers,
que hacen lo mismo que las interrupciones hardware, pero en lugar de
dispararse cuando se cumple un cierto proceso hardware en uno de los pines,
se dispara cuando ha transcurrido un tiempo preciso, previamente programado.
Es el equivalente del despertador, que cada mañana suena a la misma hora.

LOS CONTADORES INTERNOS DE


LOS TIMERS
Nuestros Arduinos UNOS y MEGAs tienen un cristal que bate a 16 MHz, o
16.000.00 de veces por segundo.
Teóricamente podríamos fijar una interrupción cada 1/16000000 segundos, lo
que no sería muy útil porque cada instrucción de Arduino necesita varios pulsos
de reloj para ejecutarse (y algunos muchos pulsos).
Por eso cada Timer dispone de un registro interno que indica cada cuantos
ticks del reloj debe dispararse. Básicamente el que nos interesa es un Timer
cuyo registro es un entero sin signo de 16 bits, lo que le permite contar hasta
216 = 65.536
Si este contador se disparase cada tick del cristal, no nos serviría de mucho
porque, el máximo tiempo que el contador podría abarcar sería de:

Como es muy probable que necesitemos algo más de flexibilidad en los


tiempos, los chicos que diseñaron el corazón e Arduino, el ATMEGA328,
incluyeron unos divisores de esta frecuencia básica del cristal de cuarzo., de
modo que solo salta un tick al contador cada ciertos ticks del patrón básico.
En Arduino UNO esos divisores pueden ser 1, 8, 64, 256 y 1024. De ese
modo podemos “frenar” hasta mil veces la velocidad de incremento del
contador de disparo.
Un cálculo rápido nos dice que el anterior máximo de disparo puede subir
desde los 4 ms de antes a 1024 veces más, o sea alrededor de 5 segundos.
Aunque pueda pareceros poco tiempo, ya es un margen considerable para
atender a las cuestiones urgentes con precisión.
Naturalmente existen librerías que a partir de esto van incrementando
contadores externos para multiplicar el plazo de disparo.
Como la explicación que hemos planteado para mostrar que la interrupción
programada en el Timer saltará cuando el registro interno, alcance el valor
fijado previamente (después de ralentizarlos con el divisor elegido) es algo, que
cualquier memo puede entender, necesitamos complicarlo de algún modo que
impida que esto se llene de paletos enredando con la electrónica.
Naturalmente el mejor modo de mantener este asunto entre señores, es
complicar innecesariamente los nombres de las cosas de modo que los
susodichos paletos salgan aullando nada más ver lo complicado que parece
todo.
Así pues en la jerga de Arduino, no hablamos de contadores de disparo, (Seria
una vergüenza, no), en su lugar les llamaremos Compare Match Registers o
CTRs y a los divisores les llamaremos prescalers. Chúpate esa
Además, si leéis la documentación técnica que abunda en Internet sobre los
Timer Interrupts, os hablarán inmediatamente de los registros internos del chip
y de cómo calcular la frecuencia de la interrupción en Hz y otras pavadas
parecidas.
Me han levantado un dolor de cabeza superior.
Mi consejo es que os saltéis todo esto por ahora y os centréis en el uso de
alguna librería sensata para controlar las interrupciones programadas como la
TimerOne y punto. Y a eso vamos.
No hace falta ninguna librería para programar un Timer en Arduino UNO. Basta
con programar directamente los registros internos del ATMEGA328,
Arduino soporta sus instrucciones y conoce todos los valores y funciones
precisas, pero os obliga a conocer los entresijos a nivel de hardware del
procesador y por ahora esto si que es como para salir aullando.
Así que de momento haced como todos, como que no existe y centraros en la
librería TimerOne. Ya tendremos tiempo de volver sobre el asunto en el
doctorado.

LA LIBRERÍA TIMERONE
Hay varias versiones de esta librería corriendo por ahí. Yo he elegido esta,
básicamente porque parece soportar más modelos de Arduino (Incluyendo al
MEGA) y porque parece que el código es más rápido que el original. Podéis
descargarla Aquí TimerOne.zip
La Librería está en el archivo.ZIP.
Las cosas importantes de la librería. Cuando la importéis tendréis esta línea:
#include <TimerOne.h>
Esto nos crea un objeto llamado Timer1 directamente, sin necesidad de
instanciarlos. Lo siguiente es programar el intervalo de disparo en
microsegundos:
Timer1.initialize(150000); // 150 ms
Y ya solo falta hacer el attach de la interrupción con el servicio de gestión o
ISR:
Timer1.attachInterrupt( ISR_Callback) ;
Y con esto ya habéis programado una interrupción temporizada que saltará
cada 150 ms y llamara la función ISR_Callback. ¿Fácil no?
Veamos ahora un programa que se aproveche de esto. Empecemos definiendo
cosas
#include <TimerOne.h>
const int led = 13; // the pin with a LED
int ledState = LOW; // El LED empieza apagado
volatile unsigned long blinkCount = 0; // La definimos como volatile

void setup(void)
{
pinMode(led, OUTPUT);
Timer1.initialize(250000); // Dispara cada 250 ms
Timer1.attachInterrupt(ISR_Blink); // Activa la interrupcion y la asocia a
ISR_Blink
Serial.begin(9600);
}
Y ahora veamos la Función de servicio, recordad que conviene que una ISR
sea la mínima expresion:
void ISR_Blink()
{ ledState = !ledState ;
blinkCount++ ; // Contador veces se enciende el LED
}
/*Cada vez que se invoca, invierte la situación del LED y aumenta blinkCount
en uno para llevar la cuenta de las veces que invertimos el estado. Veamos la
funcion principal:*/
void loop(void)
{
unsigned long N; // Haremos copia del blinkCount
digitalWrite(led, ledState); // Asignamos el valor del
// status a la salida
noInterrupts(); // Suspende las interrupciones
N = blinkCount;
interrupts(); // Autoriza las interrupciones

Serial.print("Ciclos = ");
Serial.println(N);
delay(100);
}
Fíjate en que desactivamos las interrupciones en el momento que vamos a
copiar el valor del contador, para evitar que entre otra interrupción a medio leer,
y las volvemos a activar al finalizar.
Después podemos seguir con el programa normal sin preocuparnos de
comprobar si toca o no toca saltar a la interrupción programada. ISR_Blink se
ejecuta limpiamente cada tanto tiempo solita. Además podemos usar delays
tranquilamente, porque las interrupciones tienen prioridad y se ejecutaran aun
cuando el delay esté activo.
¿A que parece que es demasiado bueno para ser cierto? Pues tienes razón, en
la vida no existe la felicidad completa y las interrupciones tienen ventajas e
inconvenientes.
Entre las ventajas tenemos:
Código limpio y elegante. No tenemos que calcular en el loop si estaremos
perdiéndonos algo o no. Cuando el tiempo programado se cumple la
interrupción salta y se ejecuta limpiamente.
Conceptualmente la programación orientada a eventos es la predominante en
los moderno sistemas operativos como Linux, Windows o OSX y si aprendéis a
pensar así no os resultara difícil entender el concepto bajo Visual Basic o C#.
No importa que estemos en un delay, la interrupción salta impecable.
La medida del tiempo es muy precisa.

Pero como la felicidad completa no existe tenemos que hablar de los


inconvenientes:

El primero y grave, es que si jugamos con los timers, muchas de las


instrucciones que dependen de ellos dejaran de funcionar.
Entre estos están, los pines PWM y analogWrite() y la librería Servo.
Dependiendo del modelo Arduino y del Timer que usemos la cosa es grave.
Si vuestro Timer entra en conflicto con algo puede ser muy complicado
comprender el problema.
Si tu Servicio ISR tarda más en ejecutarse de lo que tarda en saltar la nueva
interrupción (Y te puede pasar por un error de cálculo) antes de acabar puede
volver a entrar porque ha disparado de nuevo el Timer. La situación alcanzara
un nivel de peligro inmediato porque tu Arduino se colgará y no sabrás porque.

RESUMEN DE LA SESIÓN
Hemos visto que además de las interrupciones por hardware podemos ejecutar
interrupciones programadas mediante Timers.
Hemos visto una librería, la TimerOne con la que resulta asquerosamente
sencillo programar una de estas interrupciones.
Hemos comentado que no conviene enredarnos por ahora en la programación
interna del procesador.
Hemos creado un pequeño ejemplo de muestra, para provocar con una
interrupción programada, un blinking LED.

(78) COMMENTS

Reply
javier
13 Mar 2017
Hola buen tut como siempre…
Bueno quiero ayuda en esto quiero hacer un generedor de ondas cuadradas
con una frecuencia mas o menos de 5 a 15khz, y si es posible variar la
frecuencia y la ancho de pulso
Alguna sugerncia??? y gracias

Reply
Julio
09 Feb 2017
Perdón
Me equivoque, este es el correcto.
void loop(){
if(analogRead(PIN_G) = 256){
digitalWrite(pinPiezo, HIGH);
t=t+1;
}
if (t>5 && analogRead(PIN_G) >= 256){
digitalWrite(pinPiezo, LOW); Aquí es cuando empieza a hacer el cri,cri etc
}
if (t>15 && analogRead(PIN_G) >= 256){
digitalWrite(pinPiezo, HIGH);
t=0;
}
Gracias

Reply
Julio
09 Feb 2017
Hola
Al final lo hice con un contador, pero tanto con el contador como con millis(),
cuando esta el piezo en low y esta contando el tiempo se escucha muy bajo un
cri,cri,cri hasta que se pone en HIGH.
hay alguna forma de hacerlo para que mientras que este activo el contador y en
low el piezo no se escuche nada?
void loop(){
if(analogRead(PIN_G) = 256){
digitalWrite(pinPiezo, HIGH);
t=t+1;
}
if (t>5 && analogRead(PIN_G) >= 256){
digitalWrite(pinPiezo, LOW); Aquí es cuando empieza a hacer el cri,cri etc
}
if (t>15 && analogRead(PIN_G) >= 256){
digitalWrite(pinPiezo, HIGH);
t=0;
}
Gracias

Reply
Julio
07 Feb 2017
Gracias por responder
Lo de las variables lo tengo claro y estuve haciendo algunas pruebas, pero el
problema es que no se manejar bien el tema del tiempo.
No llevo mucho tiempo con arduino

Reply
admin
07 Feb 2017
Hola Julio,
La idea es que tu programa haga algo asi: EN algun momento que quieres
determinar haces T0 = millis(); y en el loop puedes hacer
if (millis -T0 > 5000) // Para 5 segundos
lineas1;
lineas2;
……..
SIgues el curso normal
De este modo haces algo parecido a un delay, ya que el codigo dentro del if
solo se ejecuta cata 5 segundos en este caso mientras permite seguir
normalmente el resto del programa

Reply
Fulco
06 Feb 2017
hola,estoy haciendo estos
teatros,https://www.facebook.com/daniel.fulco.7/videos/10211157489273728/…
bueno el inconveniente es que desearia que al encenderse el mp3 siempre me
pasa la misma cancion a pesar de estar grabadas mas de 50 arduino puede
hacer el cambio de cancion cada vez que se encienda?desde ya gracias
Reply
admin
07 Feb 2017
No se si entiendo tu pregunta fulco, pero naturalmente tu arduino puede elegir
la cancion a reproducir cunado arrancas e incluso que sea aleatorio si es lo que
deseas

Reply
Julio
06 Feb 2017
Hola no se si alguien pudiera echarme una mano. Quisiera que cuando se
cumpla una condición suene un piezo eléctrico 15 segundos y se apague,
cuando pasen 5 minutos y si sigue la condición cumpliéndose vuelva a sonar
15 segundos. Esto son los IF:
void loop(){
if(analogRead(PIN_G) = 256){
digitalWrite(pinPiezo, HIGH);
lcd.setCursor(14,0);
lcd.print(” “);
}

Reply
admin
07 Feb 2017
Hola Julio,
Es un programa sencillo pero que te obligara a medir el tiempo y sobre todo a
plantear correctamente la logica del programa
Te recominedo que empieces con un par de variables glbales para que midas el
valor del reloj interno cuando empiezas los 15 segundos del buzzer y otra para
controlar el transcurso de los 5 minutos
No use delays simplemente controla el paso del tiempo en elloop comparando
los valores almacenados en las variables de arriba con el tiempo que mide el
reloj interno

Reply
Carlos
17 Ene 2017
Buen dia… excelentes sus tutoriales….
Puedo utilizar mas de un timer en un mismo programa…?

Reply
Ivan
19 Ene 2017
Hola Carlos, el microcontrolador que usa Arduino UNO dispone de 3 Timers
pero se usan para funciones del core de Arduino. Los Timer son 0,1 y 2.
El Timer 0 es utilizado,por ejemplo, por la función millis().
El Timer 1 y 2 es usado para PWM (si no estás utilizando PWM, pues puedes
usarlo).
A parte hay otras librerías que también lo usan. librerías que también los usan.

Reply
diego
16 Ene 2017
Buenas,
Con un arduino Mega estoy controlando la velocidad de 2 motores dc. Es un
control PID( de velocidad) y la alimentacion con PWM, 2 encoders para medir
la velocidad. Cada pulso que envía el encoder lo recibe el arduino con una
interrupcion. El problema viene cuando pongo a correr el programa los motores
se activan un par de segundos y se desactivan. Mi pregunta es:¿las
interrupciones pueden estar pausando la alimentacion PWM de los motores? si
es asi,¿como puedo solucionar eso?
Desde ya, muchas gracias

Reply
admin
17 Ene 2017
Hola DIego,
Ten en cuenta que los PWM usan interrupciones y hay limitaciones en cuanto a
que pines puedes usar con PWM si estas usando interrupciones aparte. Echa
una ojeada aqui:
https://arduino-info.wikispaces.com/Timers-Arduino
https://oscarliang.com/arduino-timer-and-interrupt-tutorial/

Reply
LEONARDO
12 Ene 2017
Buen dia
Buenos comentarios
Tengo un problema, a ver que solución tienen para mi Proyecto “Microrobot
Explorador”
Tengo 8 sensores ultrasonicos Hcr04 funcionando.conectado a dos servos con
las siguientes función de “robot adelante” funcionando, cuando detecta un
obstáculo va a la función “robot parado” y retrocede con la función “robot atras”
funcionando con delay, pero como hago para quitar la función delay ya que los
8 sensores se cuelga al ,momento de sensor la distancia. la idea es generar un
tiempo independiente de parado por lo menos de 2 segundos, un tiempo de
retroceso de 4 segundos y un tiempo de 2 segundos para girar derecha o
izquierda dependiendo de la lógica de los sensores
Muchas gracias

Reply
Ivan
13 Ene 2017
Hola Leonardo, la manera más sencilla de evitar delays es usar la función
milis(); que cuenta el tiempo transcurrido en milisegundos desde que se ejecuto
el programa. Así puedes compararlo en cada ejecución con el valor que quieras
y calcular tiempos sin usar los delays. Un saludo.

Reply
Toño
10 Ene 2017
Vaya columpiada, Juan. Hay que leer con más detenimiento para no meter la
pata así. Y no estar a la que salta tampoco está mal. Por mi parte os agradezco
todos estos tutoriales, a mi me han sido muy útiles.

Reply
Juan
30 Dic 2016
No me parece bien que llames paletos a gente que empezando con la
electrónica intente resolver sus dudas buscando en Internet en páginas como
esta. Igualmente que intentes premeditadamente complicarles las cosas para
que: “los susodichos paletos salgan aullando nada más ver lo complicado que
parece todo”. Un poco de respeto a los lectores que son lo primero, por favor
revisa tu pedagogía. Una cosita más, los cristales de cuarzo oscilan no baten,
la que bate es la batidora que tenemos todos en casa para hacer mayonesa. Y
ademas 16 MHz es igual a 16 seguido de seis ceros, no de cinco.
Un saludo.
Juan

Reply
admin
02 Ene 2017
Juan, Siento que creas que me burlaba de los novatos que se acercan a
internet buscando resolver sus dudas. Muy al contrario todo el escrito esta
pensado para riciculizar el intento de complicarle las cosas al novato y mas
porque no lo considero necesario. Nuestro intento ha sido siempre simplificar
en lo posible todo el acceso a unas cuestiones que son sencillas a poco bien
que te las presenten y te recuerdo que novatos hemos sido todos en un
momento dado.
Por eso me gustaria insistri en que lamento si el tono usado te parece
desafortunado por la intencion nunca fue ridiculizar a los nuevos sino todo lo
contrario: ridiculizar a los que llevando ya mucho tiempo complican sin
necesidad las cosas.
Por eso te pido disculpas si te hemos ofendido, pero te pediria si te parece, que
leas el tema de nuevo teniendo claro cual era nuestra intencion desd el
principio y creo que nos entenderas un poquito mejor
Un saludo

Reply
Luis Angel Ponce
19 Dic 2016
Que tal amable gente de Prometec, esperando a resolver mi problema dejo
aquí la siguiente cuestión. He combinado una serie de tutoriales para Sensar
temperatura con un LM35DZ y que me lo muestre por el puerto Serial. Cuando
esa temperatura es mayor que; 15 grados, mi sistema es estable y no pasa
nada, pero si la temperatura es igual o menor a 15 grados entonces me mande
un mensaje de alerta. Despues de este primer mensaje quisiera que esperará 1
min y entonces si la temperatura sigue igual o bajo 15 grados que me vuelva a
mandar el mensaje de alerta, si la temperatura está por encima de lo
establecido entonces solo sigue trabajando (sensando).
Dejo aquí el programa y lo que me hace hasta este momento el programa es
que una vez que detecta que la temperatura es igual o menor que 15 grados,
no deja de mandarme los mensajes. Sé que me llevaré más conocimiento
después e esto, así que les agradezco de antemano.
#define pin3 3
float aux;
float temp;
int valor2; // Esto es una variable entera
int contador=0; // Variable contador igual a cero en el inicio.
int activado=0; // Al principio no ha sido activado.
long inicio, final, actual; // Tiempos.
void setup()
{
pinMode(pin3, INPUT);
pinMode(8, OUTPUT); //temperatura baja
pinMode(7, OUTPUT); //temperatura estable
Serial.begin(9600); //Configura velocidad del puerto serie del Arduino
Serial.println(“LISTO”);
delay (1000);
}
void loop()
{
aux = ((analogRead(0)-analogRead(1))*500.0)/1023.0;
if (temp != aux)
temp = aux;
Serial.print(” Temp: “);
Serial.print(temp);
Serial.println(” Grados Celsius”);
if (temp>=16){
digitalWrite(7, HIGH);
digitalWrite(8, LOW);
}
if (temp final) ) { // Si fue activado=1 y el tiempo actual es mayor que el final….
loop(); // haz un parpadeo.
}
}
Nota: He puesto un puente del pin 8 al pin 3 para que cuando la temperatura
sea baja ponga en 1 el pin 3 y haga la instrucción tiempo, dado que el pin debe
estar en HIGH, esta rutina ya la he probado encendiendo un LED, despues de
un pulso, espera el tiempo que en este caso declaré como 1min = 60000ms, y
si detecta que sigue presionado repite el proceso.

Reply
Marcos
18 Oct 2016
Hola, podria usar esta libreria en el mismo sketch con la libreria de IRLremote ?
quiero hacer que a traves de un control pueda encender Lamparas y utilizaria la
libreria Timer para enceder cierto tiempo una tira Led.
Saludos
Reply
admin
19 Oct 2016
Hola Marcos no parece que deberias tener ningun problema pero no saldremos
de dudas hasta que lo pruebes

Reply
Michelle
14 Oct 2016
Hola gracias por contestar,soy Michelle ( me equivoque con la a) no entendí
bien lo del reloj me podrías explicar mas a detalle, lo siento pero soy nueva en
esto, estoy estudiando carrera técnica en mecatronica pero no se trabar mucho
con el arduino. E Ivan lo de restar el valor…… ?

Reply
Ivan
14 Oct 2016
Hola Michelle, yo creo que la forma más sencilla de hacerlo es usar la función
millis() como te dije. Esta función te da el tiempo transcurrido en milisegundos
desde que empezó el programa, pero puedes reiniciarlo cada 15 segundos
junto con el contador en el que cuentes las pulsaciones.
Echa un ojo a la función millis() y a la sesión dedicada a los pulsadores y si
tienes alguna duda me dices y te echamos una mano. Un saludo!

Reply
Michella
06 Oct 2016
Hola, necesito programar un proyecto que consiste en contar las pulsaciones
durante 15s y las compare para ver si están dentro del rango establecidos, si
no lo están, sonara una alarma. como podría programarlo? Gracias!!!

Reply
Ivan
07 Oct 2016
Hola Michella, creo que la forma más sencilla sería utilizar la función milis()
para guardar el tiempo que ha pasado en una variable, y que resetees su valor
y el de las pulsaciones cada 15 segundos. Si las pulsaciones no superan el
límite en ese tiempo, haces sonar la alarma.
Un saludo.

Reply
admin
07 Oct 2016
Hola Michella, 15 segundos e smucho tiempo para un procesador. Yo probaria
con un reloj RTC para medir el tiempo

Reply
Jordan
06 Oct 2016
Hola, me podrían ayudar, necesito un programa que con un pulso en una
entrada digital me entregue 6 pulsos de salida, que esto ocurra cada vez que
se le entregue el pulso de entrada, creo que es bastante simple pero soy
nuevo, muchas gracias.

Reply
admin
06 Oct 2016
Hola Jordan, no nos das muchas pistas

Reply
Bruno
18 Ago 2016
Hola, alguien sabe como hacer que al leer una entrada digital, se active una
salida, pero esta salida me debe entregar 6 pulsos con intervalos de medio
segundo aproximadamente

Reply
admin
20 Ago 2016
hola bruno. puedes escribir una funcion que envie esos pulsos con los
intervalos que necesites usando el reloj interno sin necesidad del timer y sera
bastante mas sensillo

Reply
JOnathan Rivera
01 Ago 2016
Hola me puedes ayudar con un proyecto que quiero realizar quiero hacer una
alarma para mi colegio que suene cada 45 min

Reply
Ivan
01 Ago 2016
Hola Jonathan! Supongo que necesitas que la alarma suene a horas concretas.
Mira te dejo un enlace a una sesión que te puede ayudar, donde usamos un
reloj en tiempo real (módulo rtc) para saber la hora y la fecha en todo momento.
Y además al final tienes una librería que precisamente sirve para manejar
alarmas. Espero que te sirva.http://www.prometec.net/relojes-rtc/
Un saludote!

Reply
admin
02 Ago 2016
Buenos dias jonathan
Sera un plcer ayudarte con tu proyecto. Basta con que lo postees en el foro y
asi entre todos vamos echandole una ojeada y ayudando en lo que podamos ,
vale?

Reply
Rene Gonzalez
22 Jul 2016
Hola, muy buen articulo. Solo una duda, no se cuan descabellada, puedo
reconfigurar un timer dentro del mismo? O sea modificarle la base de tiempo.
Saludos y desde ya gracias por su respuesta.
Reply
admin
23 Jul 2016
Hola Rene, No se muy bien lo que quieres decir, pero siempre puedes
reprogramar los timers cuando lo necistes

GIVE A REPLY

Das könnte Ihnen auch gefallen