Arduino timer interrupts: Timer1 on an Uno, every second
Or see every lesson.
- 455parts on the bench
- 43boards running now
- 1.00xreal time, on every board
A timer interrupt runs a function of yours at a fixed rate, whatever loop() is doing. On an Uno you set up one of the chip’s three timers to count, tell it when to stop and start again, and write the function with ISR(TIMER1_COMPA_vect). Timer 1 is the usual choice: timer 0 runs millis() and delay(), and timer 2 runs tone().
The circuit above does three jobs at three rates the other way, by checking millis() in loop(). It prints "three rates, no delay" and then how long the slowest pass through loop() took, and that number is why it works: nothing blocks. A timer interrupt is the tool for the day something must happen on time even when loop() is busy.
Below is a Timer1 interrupt that ticks once a second, the sum behind its numbers, a faster rate, the TimerOne library that does the sums for you, and the four ways it goes wrong, each run on an Uno with what it printed.
Want the step-by-step version? The lesson "Timing without delay" walks through this with checkpoints.
Open the lessonTimer1, once a second
The sketch below sets timer 1 to count at 16 MHz divided by 1024, to go back to 0 when it reaches 15624, and to call the handler each time it does. The handler counts and flips the LED on pin 13. loop() prints the count when it changes. It printed "tick 1 at 999", "tick 2 at 1999" and "tick 3 at 2999": one tick a second, to the millisecond.
The setup lines in order: clear the two control registers, start the count at 0, set the top in OCR1A, set WGM12 for CTC mode (count up to OCR1A, then back to 0), set CS12 and CS10 for the divide by 1024, and set OCIE1A in TIMSK1 to switch the interrupt on. noInterrupts() and interrupts() around them stop a half-set timer from firing.
volatile unsigned long ticks = 0;
ISR(TIMER1_COMPA_vect) {
ticks++;
digitalWrite(13, !digitalRead(13));
}
void setup() {
Serial.begin(9600);
pinMode(13, OUTPUT);
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 15624;
TCCR1B |= (1 << WGM12);
TCCR1B |= (1 << CS12) | (1 << CS10);
TIMSK1 |= (1 << OCIE1A);
interrupts();
}
void loop() {
static unsigned long shown = 0;
noInterrupts();
unsigned long now = ticks;
interrupts();
if (now != shown) {
shown = now;
Serial.print("tick ");
Serial.print(now);
Serial.print(" at ");
Serial.println(millis());
}
}The sum: where 15624 comes from
OCR1A = clock / (prescaler × rate) − 1. The Uno’s clock is 16,000,000 Hz; divided by 1024 the timer counts 15,625 times a second; for one interrupt a second it counts 15,625 steps, 0 to 15624. The −1 is because 0 is a step too.
Timer 1 is 16 bits, so OCR1A can be up to 65535. Pick the smallest prescaler (1, 8, 64, 256 or 1024) that keeps the answer under that. For 1000 interrupts a second, a prescaler of 64 gives 16,000,000 / (64 × 1000) − 1 = 249: set CS11 and CS10 instead of CS12 and CS10. Counted for one second, that sketch printed 1000.
The same with the TimerOne library
TimerOne does the sum for you: give it a period in microseconds and a function. The sketch below asks for 500,000 µs and printed "tick 1 at 499", "tick 2 at 999", "tick 3 at 1500" and "tick 4 at 1999". The function is still an interrupt handler, with the same rules. MsTimer2 is the same idea on timer 2 in milliseconds: MsTimer2::set(500, flash) called flash() three times in 1.55 seconds. Timer 2 is also tone()’s, so a sketch uses one or the other.
#include <TimerOne.h>
volatile unsigned long ticks = 0;
void tick() {
ticks++;
}
void setup() {
Serial.begin(9600);
Timer1.initialize(500000);
Timer1.attachInterrupt(tick);
}
void loop() {
static unsigned long shown = 0;
noInterrupts();
unsigned long now = ticks;
interrupts();
if (now != shown) {
shown = now;
Serial.print("tick ");
Serial.print(now);
Serial.print(" at ");
Serial.println(millis());
}
}Reading what the handler writes
ticks is volatile, because the handler can change it between any two lines of loop(). Leave volatile out and a loop that waits for it can wait for ever: while (ticks == 0) {} without it never ended, and "a second went by" never printed. The interrupts page shows the same with a button.
An unsigned long is 4 bytes and the Uno reads it one byte at a time, so the handler could change it halfway through a read. That is why loop() copies it between noInterrupts() and interrupts(), which takes a few microseconds and loses no tick. A byte-sized counter does not need it.
Four ways it goes wrong
analogWrite() on pin 9 or 10. Those two pins’ PWM comes from timer 1, and analogWrite() sets OCR1A for its duty. After one tick in the first second, analogWrite(9, 128) made the count jump: 121 more ticks in the next second, because the timer was now counting to 128. Use pins 3, 5, 6 or 11 for PWM in a sketch that owns timer 1. The Arduino Servo library also runs on timer 1 on an Uno, so do not use both.
A misspelled vector name. ISR(TIMER1_COMPA_vector) built with no error at all, and the count stayed at 0: the chip never calls a function by that name. The name ends in _vect.
Too much in the handler. While it runs, other interrupts wait, millis() among them. Do not call delay() or print from it: set a flag or bump a counter, and do the slow work in loop().
Touching timer 0. It belongs to millis(), delay() and PWM on pins 5 and 6. Change its registers and every delay in the sketch changes length.
Questions
How do I make an Arduino timer interrupt every second?
On an Uno, put timer 1 in CTC mode with a prescaler of 1024 and OCR1A = 15624, enable OCIE1A in TIMSK1 and write ISR(TIMER1_COMPA_vect). Or use the TimerOne library with Timer1.initialize(1000000).
Which timer should I use on an Arduino Uno?
Timer 1, the 16-bit one. Timer 0 runs millis() and delay(), and timer 2 runs tone(). Using timer 1 costs PWM on pins 9 and 10.
Can I use delay() or Serial.print() in a timer interrupt?
No. Both wait on other interrupts, which are held off while yours runs. Set a volatile flag in the handler and act on it in loop().
Does an ESP32 use the same timer registers?
No. TCCR1A, OCR1A and TIMSK1 belong to the Uno’s ATmega328P. ESP32 boards have their own timers, set up through the core’s timer functions rather than registers.
What is the difference between a timer interrupt and millis()?
millis() timing works only as long as loop() keeps coming around. A timer interrupt fires on time even while loop() is stuck in a slow job, at the price of the rules every interrupt handler has.
Keep going
Where the facts on this page come from
Build this for real
Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.