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.

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.

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.

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.

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:

Por lo tanto:

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

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

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:

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):

con un prescaler de 1024 obtienes:

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

Si aún no tienes tus placas de Arduino dale un vistazo a los productos baratos de china en Aliexpress:

Quizas te interese algunos productos de Arduino en Amazon a un mu buen precio.

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)

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

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 = 0xC2F8;                    // inicia timer para desbordamiento 1 segundo
                                     // 65536-(16MHz/1024/1Hz - 1) = 49912 = 0xC2F8
  
  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.

Sensores disponibles en Amazon

Aprendiendo a utilizar la conversión ADC y la utilización de los timers, puedes integrar cualquier tipo de sensor con tu placa de desarrollo del arduino para darle vida a tus proyectos, puedes darle un vistazo a los siguientes sensores que puedes encontrar en Amazon:

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 = 0x3D08;            // carga el registrador de comparación: 16MHz/1024/1Hz -1 = 15624 = 0X3D08
  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.

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
#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);
}

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.

Salir de la versión móvil