Saltar al contenido
Control Automático Educación

Timer Arduino

Hola controleros y controleras en el día de hoy vamos a aprender a usar el famoso TIMER de ARDUINO (o en español Temporizador Arduino) que nos dará la posibilidad de programar tareas en tiempos exactos en nuestro proyecto de automatización.

Antes de comenzar, te hago la invitación para que veas nuestro CURSO GRATIS DE ARDUINO.

Timer en Arduino – Temporizador

Es indudable que realizar una medición de tiempo precisa en un proyecto autónomo es de suma importancia por lo que todo aquel que esté aprendiendo a utilizar el Arduino, deberá entender como trabajar con los temporizadores o TIMERS del ARDUINO.

El Timer con Arduino está fuertemente relacionado con lo que vimos en la entrada pasada, de las Interrupciones con Arduino (timer arduino interrupt), y esto es dado a que como ya lo anticipábamos en ese post, los timers serán ejecutados por medio de una interrupción para atender alguna tarea en especifica.

Interrupción Arduino

Si ya has usado la instrucción delay del Arduino sabes que dicha instrucción nos permite temporizar, sin embargo, el problema de esa función es que BLOQUEA el Arduino y debemos esperar hasta que el tiempo del delay transcurra para poder continuar con el programa y esto en muchos casos es INVIABLE.

delay Arduino

La ventaja de el timer con Arduino es justamente esa, que podremos temporizar el tiempo, cuando simultáneamente estamos realizando otra tarea con la placa de desarrollo.

En resumen, el Timer del Arduino es un Temporizador que se programa en el Arduino que se dispara en un tiempo predeterminado. Y en cada momento que este temporizador se dispara, el Arduino ejecuta una función de Interrupción. Por ejemplo, se puede programar un timer que se dispare a cada segundo, o a cada 3 segundos y así sucesivamente, para que el Arduino cumpla una tarea específica.

Timer Arduino

Modos de Timers

Cuando hablamos de Timer en Arduino, podemos pensar en 2 modos de funcionamiento en los cuales se puede aplicar esta importante característica.

Entonces el timer lo podemos usar en:

  1. Una señal PWM: Es la señal que podemos controlar en los pines del Arduino con el símbolo (~). Modulación por ancho de pulsos de Arduino (también conocida como PWM, siglas en inglés de pulse-width modulation)
  2. CTC (Clear timer on compare match): Esta es la opción que vamos a usar el día de hoy y simplemente como su nombre lo indica, el sistema contabiliza un tiempo dentro de un contador y cuando este contador alcanza el valor del registro de los timers, se ejecuta la interrupción del Arduino.

A continuación se muestra los modos que pueden ser configurados en los registros del microcontrolador para configurar el Timer en Arduino. Sin embargo, si tu vas a utilizar librerías para la configuración será mucho más facil de alplicarlo.

Todo estará basado en el datasheet del ATmega328p.

Temporizador Arduino

Tipos de Timers

Dado que el timer es un recurso del microcontrolador del Arduino podremos realizar el conteo de tiempo sin la necesidad de ningún hardware externo. O sea controlaremos el Time en Arduino (Tiempo en Arduino).

Cada placa de Arduino posee un cristal de cuarzo, por ejemplo, para el caso del Arduino UNO, MEGA, Pro Mini tenemos un cristal de cuarzo de 16MHz. Ese cristal es el encargado de darle los tiempos de ejecución (ticks) del programa interno del Arduino.

Cristal Cuarzo Arduino UNO - Timer Arduino

El Timer se vale de ese cristal, donde teóricamente podríamos ejecutar una interrupción cada 1/16.000.000 segundos o lo que se conoce como 1 tick. Cada instrucción consume  “x” ciclos de reloj, entonces tenemos que  dividir este ciclo por la frecuencia de  dicho reloj. La mayoría de las instrucciones consumen un ciclo; por eso se considera que la arquitectura AVR da (casi) 1MIPS por Mhz.

Sólo los saltos y algunas instrucciones de 16 bits necesitan más ciclos; eso es algo que pasa en todas las arquitecturas

Sin embargo, para ejecutar las instrucciones propias del Arduino, muchas veces consumimos más de 1 tick. Los Timers disponibles en Arduino poseen un registro el cual nos dice cuántos ticks son necesarios para disparar el timer.

Dependiendo de la placa de Arduino que poseas, tendrás disponible para tus proyectos los siguientes Timers

Timer 0 Arduino

Es de 8bits. Usado para las funciones delay(), millis(), micros(). Es conveniente NO modificar este TIMER para evitar alterar estas funciones que son muy comunes en nuestros códigos

Timer 1 Arduino

Es de 16 bits. Usado por la librería Servo en Arduino Uno (Timer5 para Arduino Mega). Se usa principalmente para el control de Servos, sin embargo, si no estas controlado servos, puedes usar este timer 1 arduino libremente.

Timer 2 Arduino

Es de 8 bits. Usado en la función tone(). Si no usas este módulo, puedes emplear el timer 2 Arduino libremente para temporizar otra aplicación.

Timer 3, 4, 5 Arduino Mega

solo disponibles en los Mega. Todos de 16bits. Muy utilizados principalmente para el control de Servos, sin embargo también eres libre de usarlos como te convenga.

Prescaler y Registros de Comparación

Como ya lo detallamos anteriormente por causa del cristal de 16MHz los temporizadores pueden incrementar sus contadores a 16MHz, cada tick del contador representa 1 / 16,000,000 de segundo (~ 63ns), por lo que un contador, por ejemplo, tardará un incremento de10 en 625ns (muy rápido)

Vemos que la velocidad del contador a 16MHz es demasiado rápida. Y dado que el Timer0 y el timer2 son temporizadores de 8 bits, significa que pueden almacenar un valor de contador máximo de 255. El Timer1 es un temporizador de 16 bits, lo que significa que puede almacenar un valor de contador máximo de 65535. Una vez que un contador alcanza su máximo valor, este volverá a cero. (Esto se llama desbordamiento).

Esto significa que a 16MHz, incluso si configuramos el registro de comparación con el valor máximo del contador, se producirán interrupciones cada 256 / 16,000,000 segundos (~ 16us) para los contadores de 8 bits, y cada 65,536 / 16,000,000 (~ 4 ms) segundos para el Contador de 16 bits. Claramente, esto continua siendo muy rápido, y estar interrumpiendo el programa constantemente no tiene mucho sentido.

Para controlar la velocidad del incremento del temporizador utilizamos el prescaler el cual establece la veloidad de temporización con la siguiente ecuación:

\rm velocidad\ del\ temporizador\ (Hz) = \dfrac{velocidad\ del\ reloj\ Arduino\ (16MHz)}{prescaler}

Por lo tanto:

  • un preescaler de 1, incrementará el contador a 16MHz;
  • un preescaler de 8 lo incrementará a 2MHz;
  • un preescaler de 64 = 250kHz, y así sucesivamente.

El prescaler puede ser igual a 1, 8, 64, 256 y 1024.

Prescaler Arduino

La frecuencia de interrupción viene dado por la siguiente ecuación:

\rm frecuencia\ de\ interrupción\ (Hz)=\dfrac{velocidad\ de\ reloj\ Arduino\ (16,000,000Hz)}{preescaler \cdot (registro\ de\ comparación + 1)}

el +1 está ahí porque el registro de comparación está indexado a cero

Al reorganizar la ecuación anterior, se puede resolver el valor de registro de comparación que le dará la frecuencia de interrupción deseada:

\rm Registro\ de\ comparación = \left[\dfrac{16,000,000Hz}{preescalador \cdot frecuencia\ de\ interrupción\ deseada\ (Hz)}\right] – 1

recuerde que cuando usa los temporizadores 0 y 2, este número debe ser menor que 256 y menor que 65536 para el temporizador 1

así que si deseas una interrupción a cada segundo (frecuencia de 1Hz):

\rm Registro\ de\ comparación = \left[\dfrac{16,000,000Hz}{preescalador \cdot 1}\right] – 1

con un prescaler de 1024 obtienes:

\rm Registro\ de\ comparación = \left[\dfrac{16,000,000Hz}{1024 \cdot 1}\right] – 1=15,624

desde 256 <15,624 <65,536, debe usar el TIMER1 para esta interrupción.

Registros del TIMER

Internamente, el microcontrolador del Arduino es manejado por diferentes registros. La gran ventaja de Arduino es que muchas veces nosotros como usuarios, no tenemos que entrar en detalle como configurar estos registros internos, ya que la propia interfaz de Arduino hace toda la configuración por nosotros. Sin embargo, en aplicaciones como el Timer, si no empleamos librerías, deberemos optar por modificar estos registros manualmente. Los registros de temporizador más importantes son:

Comparadores

Utilizados para comparar el estado del contador del timer, con el resultado de la configuración establecida mediante el pre-escalador (si es que lo usamos…) con el fin de ejecutar una acción si la comparación resulta en una igualdad.

Configuración de timers Arduino

Comenzaremos estableciendo el modo CTC para poder activar las interrupciones cada que ocurra un desbordamiento del TIMER. Esto sucede cuando el registro contador (TCNTn) coincida con el valor del registro de comparación de salida (OCRnA/B).

Los registros deben ser vistos en el propio datasheet del microcontrolador que estamos usando, por eso deben tener cuidado y ver cada hoja de datos. La ventaja que nos da Arduino IDE es que nos entrega ya definidos los registros correspondientes a nuestra placa.

La configuración de los timers de Arduino se hacen dentro de setup() del Sketch siempre desactivando las interrupciones antes de comenzar a configurar el/los timer/s y re-activarlas al final.

La configuración del código de la interrupción se predefine con la función:

ISR(interrupcion) {
    // Su codigo va aqui
}

y la interrupción la configuraremos usando las constantes pre-configuradas para cada placa que para nuestro caso será TIMERn_COMPA_vect

Finalmente, los registros que usaremos son:

TCCRnA/B

Registros de control para poder configurar el timer en modo CTC y el pre-escalador.

Timer0/2 (Arduino UNO y Mega 2560)

  • TCCRnA debe estar todo en 0 excepto por el bit WGM01 que debe estar en 1 para configurar el modo CTC.
  • TCCRnB debe estar todo en 0 excepto los bits que vayamos a usar en 1 para nuestro pre-escalador, si es que usaremos uno.

Timer1 (Arduino UNO y Mega 2560), Timer3/4/5 (Arduino Mega 2560)

  • TCCRnA debe estar todo en 0 para nuestro uso

  • TCCRnB debe estar todo en 0 excepto por el bit WGMn2 que debe estar en 1 para configurar el modo CTC y los bits del pre-escalador que necesitemos si es que usaremos uno

TCNTn

Registro contador. Por lo general lo inicializaremos en 0 al comenzar.

OCRnA

Registro comparador de salida. Luego de definir nuestro pre-escalador, este registro lo usaremos con un valor específico para que las interrupciones ocurran cuando el valor del contador (TCNTn) coincida con éste registro.

TIMSKn

Registro de configuración de interrupción. En nuestro caso lo usaremos con todos los bits en 0 menos el bit OCIEnA que deberá estar en 1 para indicarle a nuestro timer que usaremos el registro OCRnA para comparar.

Modo normal con interrupción por timer – desbordamiento

El siguiente ejemplo muestra cómo parpadear el LED en el pin 13 de la placa Arduino UNO a intervalos de 1 segundo y usando la interrupción de desbordamiento del temporizador:

#define ledPin 13

void setup()
{
  pinMode(ledPin, OUTPUT);

  // Configuração do timer1 
  TCCR1A = 0;                        // El registro de control A queda todo en 0, pines OC1A y OC1B deshabilitados
  TCCR1B = 0;                        //limpia el registrador
  TCCR1B |= (1<<CS10)|(1 << CS12);   // configura prescaler para 1024: CS12 = 1 e CS10 = 1

  TCNT1 = 0xC2F7;                    // inicia timer para desbordamiento 1 segundo
                                     // 65536-(16MHz/1024/1Hz) = 49911 = 0xC2F7
  
  TIMSK1 |= (1 << TOIE1);           // habilita la interrupcion del TIMER1
}


void loop()
{
  //loop principal.
}


ISR(TIMER1_OVF_vect)                              //interrupcion del TIMER1 
{
  TCNT1 = 0xC2F7;                                 // Renicia TIMER
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1); //invierte el estado do led
}

 

En este ejemplo, el temporizador se configuró en modo normal, con los pines OC1A y OC1B desconectados (TCCR1A = 0). Se seleccionó Prescaler de 1024 a través del registro TCCR1B. Para que el temporizador se desborde cada segundo, es necesario comenzar su valor con la diferencia entre su valor máximo (65536) y el período deseado. El período se calcula teniendo en cuenta la frecuencia del oscilador y el prescaler seleccionado, además de la frecuencia de interrupción deseada. Finalmente, la interrupción del TIMER1 se habilitó a través del bit T0IE1 del registro TIMSK1. El parpadeo del LED se realiza en la rutina de interrupción donde es necesario volver a cargar el temporizador para el conteo correcto.

Interrupción del modo CTC en comparación

El siguiente ejemplo muestra cómo parpadear el LED usando el modo CTC y generando interrupción en comparación:

#define ledPin 13

void setup()
{
  pinMode(ledPin, OUTPUT);
  
  // Configuração do TIMER1
  TCCR1A = 0;                // El registro de control A queda todo en 0
  TCCR1B = 0;                //limpia registrador
  TCNT1  = 0;                //Inicializa el temporizador

  OCR1A = 0x3D09;            // carga el registrador de comparación: 16MHz/1024/1Hz = 15625 = 0X3D09
  TCCR1B |= (1 << WGM12)|(1<<CS10)|(1 << CS12);   // modo CTC, prescaler de 1024: CS12 = 1 e CS10 = 1  
  TIMSK1 |= (1 << OCIE1A);  // habilita interrupción por igualdade de comparación
}


void loop()
{
  //loop principal.
}

ISR(TIMER1_COMPA_vect)          // interrupción por igualdade de comparación en TIMER1
{
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1);   //invierte estado del LED
}

 

En este ejemplo, se utiliza el modo CTC, por lo que el valor del conteo del temporizador se compara constantemente con el registro OCR1A. Para el funcionamiento, se seleccionó el modo CTC, el bit WGM12 = 1 y el prescaler establecido en 1024. El valor de comparación se cargó en el registro OCR1A y finalmente se habilitó la interrupción de comparación. El LED se invierte en la rutina de interrupción, aquí no es necesario restablecer el temporizador con un valor, porque el modo CTC restablece el temporizador cuando se alcanza el valor de comparación.

Librería TimerOne Arduino

La librería de timerone Arduino puede ser descargada directamente del repositorio de Arduino junto con su documentación (Arduino Timer Library). Para eso abra el Sketch del Arduino, y en la propia pestaña Sketch (parte superior) diríjase a  “Include Library” y luego a “manage Libraries”, y aquí busque por TimerOne e instale.

Librerias de Arduino - TIMER

Actualmente Arduino NO tiene una librería OFICIAL para el manejo de TIMERs en Arduino debido a que estos TIMERs son usados por funciones base del arduino, como el delay, millis, micros, servo, etc. Tal y como lo detallamos en el apartado anterior. Por lo tanto, si comenzamos a modificar el timer 1 de Arduino, no podremos usar la librería Servo, pues esta presentaría inconsistencias.

SINTAXIS

Veamos como utilizar esta libería para el uso primordial de temporización, en una entrada futura, la analizaremos para el manejo de la señal PWM con Arduino.

Para comenzar procedemos llamando la librería

#include<TimerOne.h>

Esto va a crear automáticamente dentro del código un objeto llamado Timer1, el cual procedemos a configurar con las siguientes instrucciones.

Timer1.initialize(period)

La instrucción Timer1.inizialize de Arduino inicializa el timer con el valor de period, este valor es el tiempo en el que queremos que se dispare el temporizador y debe ser escrito en microsegundos.

Timer1.attachInterrupt( ISR_Callback) ;

Activa la función especifica que será ejecutada como interrupción, cada que el TIMER se dispare. Similar a como lo vimos en la entrada pasada.

Timer1.detachInterrupt( ISR_Callback) ;

Desactiva la función de interrupción que se ejecuta cada que el TIMER se dispara.

Timer1.read() ;

Lee el tiempo transcurrido desde la última transferencia en microsegundos.

A continuación veremos ejemplos del timerone arduino.

TimerOne Arduino Ejemplo

Una de las aplicaciones a ser utilizadas con los timers es realizar con Arduino un Temporizador o un contador de tiempo. Por lo tanto en el siguiente ejemplo haremos un temporizador con Arduino usando la librería timerone. El resultado lo visualizaremos en un LCD 20×4 con Arduino.

En el siguiente ejemplo podremos configurar bien sea el timer arduino uno, timer arduino nano, timer arduino mega o como en mi caso el timer arduino leonardo. Va a funcionar igualmente.

En este ejemplo veremos un temporizador Arduino con LCD

TimerOne

[sociallocker id=”948″]

#define LED 13 //Declara el PIN 13 como LED

//Llama las librerías
#include <LiquidCrystal.h>     
#include <TimerOne.h>    

//Variable para la interrupción
volatile long int Time=0;

//Configuración del LCD
LiquidCrystal lcd(9, 8, 5, 4, 3, 2); //(RS, E, D4,D5, D6, D7)
 
void setup()
{
   pinMode(LED,OUTPUT);          //LED como Saída
   lcd.begin(20, 4);            // Inicia el LCD 20x04 (columnas, filas)   
   lcd.setCursor(2, 0);         // Coloca el cursor en las coordenadas (2,0)   
   lcd.print("TIMER COM ARDUINO"); // Escribe no LCD   
   lcd.setCursor(0, 1);         // Coloca el cursor en las coordenadas (0,1) 
   lcd.print("Temporizador:");      // Escribe en el LCD
   Timer1.initialize(1000000);      //Configura el TIMER en 1 Segundo
   Timer1.attachInterrupt(Temporizador) ; //Configura la interrupción del Timer 1
}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(LED,HIGH);
  delay(2000);
  digitalWrite(LED,LOW);
  delay(2000);
}

//Función de la Interrupción cuando se ejecuta el TIMER
void Temporizador(void)
{
  //Incrementa el timer
  Time++;
  //Resetea el contador cuando llega a 1000 segundos
  if(Time>1000){
    Time=0;
  }
  //Muestra en el LCD el valor actual del temporizador
  lcd.setCursor(14, 2);
  lcd.print("    ");
  lcd.setCursor(14, 2);
  lcd.print(Time);
}

[/sociallocker]

Eso es todo por la entrada del dia de hoy, espero les haya gustado y hayan aprendido algo nuevo. Si te ha servido el contenido de esta entrada, de los videos y los códigos de implementación y deseas apoyar mi trabajo invitandome a un café super barato, puedes hacerlo en el siguiente link:

👉 Invitar a Sergio a un Café ☕️

Que esten muy bien, nos vemos en la siguiente entrada.

Summary
Como usar el Timer en Arduino
Article Name
Como usar el Timer en Arduino
Description
Existen várias formas de usar el Timer en Arduino. Una de ellas es modificando directamente los registros del microcontrolador. O la más fácil es a través de librerías como el TimerOne, donde simplemente la inicializas "Timer1.initialize(period);" y posteriormente activando la interrupción "Timer1.attachInterrupt( ISR_Callback) ;"
Author
Publisher Name
Control Automático Educación
Publisher Logo

Entradas relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Comentarios (14)

Wow Sergio, excelente explicación !!!
Te quiero pedir ayuda, pues tengo dos dudas:
1) cómo podría programar servomotores con temporizador, pues veo que no puedo usar la librería de TimerOne.
2) ¿Podría tener a Arduino conectado durante días o meses por medio de baterías recargables y que me esté enviando mensajes verbales en horas específicas de cada día?

Muchas gracias de antemano por tu ayuda 🙂

Responder

Hola Bárbara,
1) Puedes usar cualquier otro temporizador excepto el 1. O sea puedes emplear el Timer 0 o el Timer 2, si estas usando el Arduino UNO claro. Para eso puedes buscar otras librerías que te ayuden a usar esos dos timers.
2) Si puedes hacer eso, si lo que deseas es usar el timer para contar la hora, te recomiendo mucho mejor usar un módulo RTC (Real Time Clock) por ejemplo el DS1307. Ese es un reloj calendario, en el cual configuras la hora y la fecha, de esa forma puedes saber el momento exacto y mandar tus mensajes. Busca también como usar el modo SLEEP del arduino, pues todavía no he hecho una entrada al respecto. Con ese modo vas a economizar más energia pues tu arduino va a dormir y solo despertará al momento de enviar los datos, economizando energía de las baterías. Saludos.

Responder

Saludos Sergio, excelente explicación sobre el uso de los timers de arduino, me queda claro entonces, que para procesos que necesiten un muestreo a baja frecuencia, no sera posible utilizar los timers 0 o 2, excepto para análisis con frecuencias muchos más altas.

Responder

Dentro de ese ámbito, como podría hacer para que la interrupción suceda cada 8 segundos modificando los registros ? , te pregunto porque, si el tiempo deseado en este caso, 8s lo multiplico por el cociente de 16M/1024, el resultado es 125K, que es un numero que sale de los limites de cualquier otro timer. Como podría implementar eso a nivel de código ? Gracias ingeniero.

Responder

8s puedes conseguirlo con el Timer1 sin problemas. Si necesitas tiempo mayor lo que haces es incluir un contador. Suponiendo, necesitas 24s, configuras el Timer1 para 8s y cada que entre a la interrupción incrementas un contador. Cuando el contador llegue a 3 indicará que ya han pasado 24s (8*3=24) y con un condicional en el loop if(contador==3) puedes aplicar las instrucciones que necesites. y reinicias el contador.

Responder

Gracias por la respuesta ingeniero, eso pensé al ver el ejemplo con la librería de timer1, gracias por todos tus conocimientos eres un crack! mis respetos y cuídese mucho del coronavirus, mentes así tienen que cuidarse bien. Éxitos!

Responder

Hola Sergio! como siempre excelente video y explicación del uso de los timers. Quería hacerte una pregunta. Si en vez de utilizar los timers internos del atmega328p por medio de la configuración de los registros, utilizo la función millis() dentro de una ISR. El resultado de encender y apagar un led de tu ejemplo seria el mismo ?

Responder

No entiendo como Emmanuel, si quieres usar la función millis() para encender y apagar el led no sería necesario usar el ISR. Saludos.

Responder

De acuerdo contigo, solo quería saber si pudiera ser una alternativa más fácil usar la función millis() para contabilizar un evento que trabajar con los registros internos del micro. Ya que la función millis() me permite trabajar con el micro si tener que dejarlo inactivo como lo hace la función delay().

Responder

excelente, super buena la explicación.

Responder

Muchas Gracias Emerson, el Timer es super importante en todo microcontrolador!

Responder

Muy buenos esta clase de videos, mi pregunta es: Con respecto al ejemplo 3 de timer donde emplea la librería del timer_1 ¿como seria solo con los registros del timer?. Tengo la inquietud porque debo hacer un trabajo y no esta permitido utilizar la librerías de los timers. Gracias por la atención prestada !!!

Responder

Debes usar lo mostrado en el segundo video de esta entrada, ahi se explicó como usar y configurar el Timer1 usando los registros.

Responder

Buenas tardes ingeniero Sergio C, debido a la atención prestada le presento una inquietud sobre el tema de los temporizadores (timers), resulta que se me pide no solo una interrupción sino muchas y que se efectúen desde un teclado blando (digitar) y que la acción a realizar dependiendo de lo introducido ¿como es posible efectuar la operación?

ejemplo: una serie de leds donde el usuario introduzca un valor por teclado que sea en mili-segundos (12, 234, 45, 500, etc) los valores que desee y la velocidad de los leds cambie.

Responder