Lesson 20 / 25
Hardware Timers Overview
Counting clock ticks in hardware.
Timers, prescalers and compare matches
A hardware timer is a counter driven by the system clock through a prescaler (a divider). When the counter matches a compare value or overflows, it can toggle a pin, generate PWM or fire an interrupt, all without CPU effort. The ATmega328P has Timer0 and Timer2 (8-bit) and Timer1 (16-bit). The Arduino core uses Timer0 for millis(), micros() and delay() plus PWM on pins 5 and 6, Timer1 for PWM on pins 9 and 10 (and the Servo library), and Timer2 for pins 3 and 11 (and tone()). Reconfiguring a timer yourself breaks whatever relied on it. For a periodic interrupt in CTC mode: compare value = F_CPU / (prescaler × frequency) − 1, so 16 MHz / (1024 × 1 Hz) − 1 = 15624.
1 Hz interrupt with Timer1 (ATmega328P, 16 MHz)
Register names from the ATmega328P datasheet; this disables PWM on pins 9 and 10 and conflicts with the Servo library.
volatile bool tick = false;
ISR(TIMER1_COMPA_vect) {
tick = true; // keep it short
}
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
noInterrupts();
TCCR1A = 0; // normal port operation
TCCR1B = (1 << WGM12) // CTC mode, TOP = OCR1A
| (1 << CS12) | (1 << CS10); // prescaler 1024
OCR1A = 15624; // 16 MHz / 1024 / 1 Hz - 1
TCNT1 = 0;
TIMSK1 = (1 << OCIE1A); // enable compare-match A interrupt
interrupts();
}
void loop() {
if (tick) {
tick = false;
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
}Check what the core already uses
Before taking over a timer, check which libraries (Servo, tone, IR receivers) and PWM pins depend on it for your board. Conflicts show up as mysteriously broken features.
Quick check: On an Arduino Uno R3, which timer does millis() rely on?
- Timer1
- Timer0
- Timer2
- The watchdog timer
Answer
Timer0 — Changing Timer0 settings would break millis(), micros() and delay().