Temporizadores por Hardware (Hardware Timers) y Modo CTC
El microcontrolador ATmega328P de Arduino Uno contiene módulos de hardware dedicados denominados Temporizadores (Timers/Counters) que funcionan de forma totalmente autónoma e independiente de la CPU.
A diferencia del bucle loop(), donde la cadencia puede verse afectada por llamadas lentas a sensores o cálculos matemáticos, un Timer por Hardware permite ejecutar código con precisión determinista de microsegundos mediante interrupciones periódicas.
1. Los Tres Timers de Arduino Uno #
| Timer | Resolución | Usos por defecto en el framework de Arduino | Pines PWM asociados |
|---|---|---|---|
| Timer0 | 8 bits (0-255) | Funciones de tiempo millis(), micros() y delay() | Pines 5 y 6 |
| Timer1 | 16 bits (0-65.535) | Librería Servo y control de tiempos de alta precisión | Pines 9 y 10 |
| Timer2 | 8 bits (0-255) | Función tone() | Pines 3 y 11 |
2. Prescaler y Modo CTC (Clear Timer on Compare Match) #
El reloj base de Arduino funciona a (). Para generar intervalos más largos:
- Prescaler (Divisor de reloj): Reduce la frecuencia del reloj alimentando el timer a través de factores como 1, 8, 64, 256 o 1024.
- Modo CTC: El contador se incrementa con cada pulso de reloj hasta igualar el valor almacenado en el registro de comparación
OCR1A. En ese instante exacto, el timer se pone a 0 y dispara la interrupciónISR(TIMER1_COMPA_vect).
- Para una interrupción a (1 segundo) con Prescaler de 1024:
3. Ejemplo Práctico: Interrupción de Timer1 a 1 Hz (1 Segundo) #
1#include <avr/io.h> 2#include <avr/interrupt.h> 3 4const int pinLED = 13; 5volatile bool estadoLED = false; 6 7void setup() { 8 pinMode(pinLED, OUTPUT); 9 10 // 1. Deshabilitar interrupciones globales mientras configuramos registros 11 cli(); 12 13 // 2. Reiniciar registros de control de Timer1 14 TCCR1A = 0; 15 TCCR1B = 0; 16 TCNT1 = 0; // Poner el contador a 0 17 18 // 3. Fijar valor de comparación OCR1A para 1 Hz (15624) 19 OCR1A = 15624; 20 21 // 4. Activar modo CTC (WGM12 = 1) 22 TCCR1B |= (1 << WGM12); 23 24 // 5. Configurar Prescaler a 1024 (CS12 = 1 y CS10 = 1) 25 TCCR1B |= (1 << CS12) | (1 << CS10); 26 27 // 6. Habilitar la interrupción por comparación de Timer1 28 TIMSK1 |= (1 << OCIE1A); 29 30 // 7. Habilitar interrupciones globales 31 sei(); 32} 33 34// Rutina de Servicio de Interrupción (ISR) ejecutada cada 1 segundo exacto 35ISR(TIMER1_COMPA_vect) { 36 estadoLED = !estadoLED; 37 digitalWrite(pinLED, estadoLED); 38} 39 40void loop() { 41 // El loop() está completamente libre para otras tareas sin retrasos 42}
Resumen del tema
Conceptos clave #
- Hardware Timers: periféricos independientes que cuentan pulsos de reloj para generar interrupciones periódicas exactas sin consumir ciclos en
loop(). - Timer1 (16 bits): permite contar hasta 65.535, ideal para temporizaciones de segundos completos con resolución fina.
- Prescaler: divisor de frecuencia (1 a 1024) para escalar el reloj de 16 MHz a frecuencias manejables.
- Modo CTC: reinicia el contador al alcanzar el valor de
OCR1A, garantizando un periodo constante sin deriva temporal (Clock Drift). - Vector
TIMER1_COMPA_vect: ISR que atiende el evento de comparación del temporizador.
Qué debes recordar #
Usa millis() para tareas cooperativas estándar; recurre a Timers por Hardware e interrupciones CTC cuando requieras muestreo de señales o control de motores con precisión de microsegundos estricta.