Timer Interrupts re-visited

Edit Jan 2022: Upon a review of this article, I noticed that WordPress had screwed up some of the command statements I had used, as it has some trouble using the greater and lesser than sign properly. This led to some text disappearing causing the code sometimes to become odd/unclear. It should be all OK now.

After I wrote an article on timer interrupts in the Arduino/AVR chips, I received some questions from people on how exactly to know what prescaler to use in setting timers and from some people who had problems reading the bitwise operators that are often being used, I will give some explanation here, but for a background on timers, I suggest you read my previous article on that subject:
Suppose you want your AVR to give an interrupt every second, then what is it you need to do?

Let’s first start with an AVR at 1MHz: (just as an example)
As 1MHz will create a timer interrupt every 1/1000.000 of a second, we would need to count 1.000.000 cycles to let a second pass. As the biggest timer is 16 bits, that can count to 65,535, that isn’t enough to count to 1,000,000. Therefore we have to divide the CPU frequency with a prescaler. But which one?
We can best chose that one as follows: If you look at all the prescalers (1 to 1024) you get the following table:
1,000,000 /1 = 1,000,000
1,000,000 / 8 = 125,000
1,000,000 / 64 = 15,625
1,000,000 / 256 = 3,906.25
1,000,000 / 1024 = 976.5625

We can already rule out 1 and 8 as prescaler because the resulting numbers are bigger than 16 bits (65,535).
We can also rule out 256 and 1024 because they result in a fraction and we cannot measure those and thus we would get an inaccuracy. Thus we are left with 64 as a prescaler. (I again emphasize this is for a 1MHz example, the Atmega 328 is 16 Mhz, we will get to that in a moment)

So what do we need to do to set up that prescaler. The datasheet ( “Timer/Counter1 Control Register B” (TCCR1B) Table 15-5) teaches us that we have to set bits CS10 and CS11 in the TCCR1B register.
cs-bits TCCR1B

There are various ways to set a bit in a register, but using a left shift is a very popular one:
We will do it as follows:

TCCR1B = 1<< CS11 | 1 <<CS10;

Ok so what does that mean? Well CS11 and CS10 are defined in io.h and are respectively on bit 1 and 0 in the timer register. CS11 and CS10 are therefore defined as “1” resp “0”. So if we substitute those values we will find:

1<<CS11| 1<<CS10;
1<<1 | 1<<0;
0b00000010 | 0b00000001;

or to explain: a 0 left shift of 1 will give 0b00000001 and a 1 left shift of 1 will give 0b00000010.
If you then bitwise OR those values that looks like:
__________ OR

if you then do a bitwise OR of that number with the timer register, that gives
__________ OR

How to assign values to the registers
Some care has to be taken in how you assign values  to the  various registers. If we have for instance the register TCCRB1, then on first instance we do not know what it’s register values are. So suppose they are 0bxxxxxxxx. If we then do TCCRB1= 1<<CS10;, TCCRB1 becomes 0b00000001;. That means ALL previous bits of the register have been erased and only bit 0 has been set. Normally we like preserving the previous bit states and only alter the one we are concerned with. We would do that with TCCRB1 |= 1<<CS10;.  The result would then be 0bxxxxxxx1.
The difference between  ‘|=’ and  ‘|’ is that the one is a compound OR and the other just an OR. With the compound OR we do not just do an OR, but then also  assign that value, in this case to TCCR1B.
Yet, with the TCCRB1 (and also The TCCRA1) register this is tricky , as  most of the bits in these registers serve some function  in what we are trying to do now. So suppose the register would have a content of 0b00000010; that we do not know about. If we decide that we like a prescaler of 256, so we need to set bit CS12. Now if we would  do that with TCCRB1 |=1<<CS12. But as we left the previous bits unaffected by using  a ‘compound OR’, the actual content  of the CS registers is  now 0b00000110;, which means there is no prescaler at all but the chip will be waiting for an external clock source and your program does not work.
That is why we use  the standard value assignment with ‘=’, so TCCRB1=1<<CS10;.
However, that also means that if we want to assign two registers, we have to be careful how we do that. Suppose you want to set both the CS10 and CS12 registers. The easiest then is to do that in one go: TCCRB1=1<<CS10 | 1<<CS12;.
If for reasons of say readability, you want to assign them separately, you have to do that like this:
TCCRB1 =1<<CS10;  (standard assignment).
TCCRB1 |=<<CS12; (Compound OR).

Counting cycles
As we picked a prescaler of 64 we  now we have to wait 1.000.000/64 =15,625 cycles to know that one second has passed (again, this is a 1MHz exaample, the 16Mhz Atmega328 is up next). How do we do that?
Well you could use a software counter in the interrupt routine that just counts to 15,625. That will work, but we can also use the hardware counter of Timer1. We do that by putting the timer in ‘Clear Timer on Compare Match’ mode or CTC mode. In this mode the Timer will compare itself with a set value and trigger an interrupt when it reaches that value.

We store that value in the OCR1A register. That is a 16 bits register
In this case we can just do:
We set that 1 less than the value we found, because microcontrollers start counting at 0 and not 1
A bitwise OR is not necessary because the entire register is reserved for the compare value.
We also will have to set the CTC mode. To set the proper bits for that we consult table 15-4, that describes the Waveform generation mode.
Obviously we need to choose Mode 4 because we want to use the value in OCR1A. The tabel shows we have to set the WGM12 bit

We do that with the following statement:
TCCR1B = 1<<WGM12
as WGM12 is defined as ‘3’
What we do is: TCCR1B =1<<3
This is 0b00001000
OR-ed withTCCR1B gives:


We are not done yet. We have now set up the timer to generate 1 sec interrupts, but we need to start the timer.
we do that with the TIMSK1 register. The datasheet tells us that we have to set the ‘Output Compare Match Interrupt Enable bit for timer 1 (OCIE1A).
We do that as follows:
as OCIE1A is defined as ‘1’, you can again do the math:
TIMSK1 = 0b00000010 i.e. bit 1 will be set

So the entire code in the setup now will be: (NB: This is an example for if we would have an 1MHz Atmega)

cli(); //Disable global interrupts
TCCR1B = ((1<< CS11) | (1<< CS10));
OCR1A = 15624; //Count 15625 cycles for 1 second interrupt
TCCR1B |= 1<<WGM12; //Put Timer/Counter1 in CTC mode
TIMSK1 = 1<<OCIE1A; //enable timer compare interrupt
sei(); //Enable global interrupts

Two statements I have not discussed yet, the cli() (clear/disable global interrupts) and sei() (set/enable global interrupts). We use those statements because we are setting up the interrupt, so just to make sure that that isn’t interrupted by a still active interrupt, we temporarily stop all interrupts and at the end enable them again..

Now for a 16 Mhz Atmega328
OK, we now know how to set it up for 1 MHz… but most arduinos do 16 MHz.
Well, that is basically the same:
16,000,000 / 1 = 16,000,000
16,000,000 / 8 = 2,000,000
16,000,000 / 64 = 25,000
16,000,000 / 256 = 62,500
16,000,000 / 1024 = 15,625
Here we could actually choose 2 prescalers: 256 or 1024.
table 15-5 teaches us that involves setting bits CS12 for 256 or CS12 and CS10 for 1024.
That would be done with the statements:

TCCR1B = 1<<WGM12 | 0b01<<CS12;
OCR1A = 62499; //Count 62499 cycles for 1 second interrupt
TCCR1B = 1<<WGM12 | 0b01 <<CS10 | 0b01<<CS12;
OCR1A = 15624; //Count 15624 cycles for 1 second interrupt

There are other ways of setting timers such as pre-loading, but for that better read my earlier article on timer interrupts
Just a word of warning: Another way of changing the frequency is done by setting fuses. The Atmega328 for example is often used with a 16 MHz crystal, but it can also be used with its internal 8MHz oscillator, additionally it already can be set to have its internal clock divided by 8, causing the CPU to go at 1 MHz and not 8 or 16.

A practical example
In my earlier article on Timer Interrupts, I gave a practicle example of a flashing LED, still using “digitalWrite()” for that.
As we are using a lot of registers for the timer, why not go into using Registers for the LED function as well:
There are three registers for each pin that that are important for us: Data Direction Register (DDR), Port register (PORT) and Pin register (PIN). Each of these will be suffixed with a letter corresponding to which set of pins we are working with. If the LED is connected to pin D13, that means it is connected to Port B bit 5 so we need to work with DDRB, PORTB, and if we was using inputs, PINB.

//Setup the I/O for the LED
DDRB |= (1<<5); //Set PortB Pin5 as an output
PORTB |= (1<<5); //Set PortB Pin5 high to turn on LED

Handling the interrupt
We have now set up everything: an interrupt will be generated every second, but we still have to tel the Arduino what to do with the interrupt. We do that in an Interrupt Service Routine (ISR). The rest of the code is halted and this routine is run. It is best to keep interrupt routines as short as possible: not a problem in this case as we just need to toggle the LED:

ISR(TIMER1_COMPA_vect) //Interrupt Service Routine
PORTB ^= (1<<5); //Use xor to toggle the LED

The name of the interrupt routine is not random: The datasheet defines the interrupt source for Timer/Counter1 Compare A match as “TIMER1 COMPA”. We use that name while replacing spaces with underscores and adding a lower case “vect” at the end. This is how the compiler knows which ISR belongs to different interrupt sources. We toggle the LED with the XOR operator and a bitmask. The bitmask ensures that only bit 5 will be changed. The XOR is a function that renders ‘0’  for bits that are the same and ‘1’ for bits that are different.
That goes as follows:
suppose at a certain moment Port B = 0b00100000 (LED on)

__________ XOR
and at the next interrupt:

__________ XOR

The entire code will thus be:

void setup() {
  TCCR1A = 0b01 << COM1B0 | 0b00 << WGM10 ;
  TCCR1B = 1 << WGM12 | 0b101 << CS10;
  OCR1A = 15624; // count 15625 cycles for 1 second
  //Put timer Counter in CTC mode
  TIMSK1 = 1 << OCIE1A; //Enable timer compare interrupt
  sei();// Enable Global interrupt //-----------------------
  DDRB |= (1 << 5); //Set PortB Pin5 as an output
void loop()
//other code

ISR(TIMER1_COMPA_vect) //Interrupt Service Routine
  PORTB ^= (1 << 5); //Use xor to toggle the LED
//PORTB = PORTB ^ B00100000;//as above, leaving the other bits intact

As website can easily screw up computer codes, here is a screenshot of what it should look like:

Let’s quickly walk through that code again:
Stops the interrupts, just to make sure the setup isn’t disturbed.


Actually you do not need this statement, the program will be fine without it. I included it for the following reason: When it is set, the OC1B output overrides the normal port functionality of the I/O pin it is connected to. OK, what pin is it ‘connected to’?


It is connected to PB2 which is digital I/O pin 10 on the UNO. That means that if we would have chosen D10 to flash the LED rather than D13, we would not have needed any code in the interrupt vector to flash an LED but just let the hardware timer do its work directly. The entire code would then have been only 4 lines:

void setup() {
  DDRB = DDRB | 1<<DDB2;               // Make D10 (PB2) an output
  TCCR1A = 0b01<<COM1B0 | 0b00<<WGM10; // Toggle OC1B on match, CTC mode
  TCCR1B = 0b01<<WGM12 | 0b101<<CS10;   // CTC mode, prescaler 1024
  OCR1A = 15624;                       // number of cycles 15625

One can do something similar with D9 that is connected to OC1A and D11 that is connected to OC2A.

TCR1B=0b01 <<WGM12;
Puts a ‘1’ in the WGM12 register, choosing CTC mode

TCCR1B = 0b01 << WGM12 | 0b101 << CS10;
This is a short way of putting a 1 in both the CS10 as well as the CS12 register of TCCR1B, choosing a prescaler of 1024.

OCR1A = 15624;
This sets the amount of cycles that needs to be counted minus 1 (since microcontrollers start counting at 0).

This sets bit 1 of the Timer/counter interrupt mask register. Bit 1 is called OCIEA which is the “Output Compare A Match Interrupt Enable” It enables the TIMER1 COMPA interrupt.


This  enables all the interrupts again that were previously silenced with cli();

DDRB |= (1 << 5); //Set PortB Pin5 as an output
It puts a ‘1’ in bit 5 of the datadirection register. bit 5 corresponds with digital pin 13, so in fact this is a quick way of writing “pinMode(13,OUTPUT);” As I am using a compound OR statement (|=), the status of any other pin remains unchanged.


PORTB ^= (1 << 5);
This toggles bit 5 of the PORTB register, which is akin to pin D13. In fact it says: digitalWrite(13,HIGH); if  D13 was ‘LOW’ and digitalWrite(13,LOW); if pin D13 was previously HIGH.

Should you change the code into only making CS12 HIGH rather than CS12 and CS10 (i.e. prescaler=256) and  make the OCR1A into (16.000.000/256)-1=62500-1=62499, that the code works as well.

Some handy website are here:
Fuse calculator
Bitwise calculator
Timer calculator


8 thoughts on “Timer Interrupts re-visited”

  1. Just a heads up: Websites are notoriously bad at displaying computercodes that carry ‘fishooks’ (the greater than and smaller than characters). This article contains a number of those and the code got screwed up quite some times. I did my best to make sure it is all correct, but as everytime I open up the article for editing, something might get screwed up again.
    Therefore on places that seemed to be specifically susceptible to repeated corruption, I used the “«” symbol if it called for ‘<<'
    That also means that if you copy and paste those codes, you need to correct that in your IDE

    1. Thank you for your kind words. The entire thought behind the arduino is that also non-technical people can make great things. Goodluck!!

  2. Just a general comment: the greater than and smaller than signs always create havoc on wordpress as it interprets them as html tags, even when they are in between the ‘pre -/pre html tags.
    Therefore, check the code you see her before using. I have tried to correct it as much as possible but every time I correct something, the problem appears somewhere else

  3. I just found this post a few days ago and have started working with timers on an ATTiny45. I have the basic code running on the chip. Thank you for posting this. The issue I have is the ATTiny45 has 8bit registers so my OCR0A can only be up to 255. What is the best way to time 1 second on this chip? (I am using CKDIV8 so the F_CPU is 1000000) Thanks!

    1. frankly I think the easiest way is to set a counter in yr timer interrupt till u get to 1 sec or close enough

      1. Yes, but due to the 8bit chip, I cannot use the 64 prescaler you use here. If I use a prescalerof 1024, it is not accurate as you stated. This will cause a drift over time and I need it to be accurate. How can I get an accurate timing on this chip?

      2. We may have a disconnect here as I didnt specifically suggest any particular prescaler.
        Now I cannot guarantee that you will be able to get a timing of exactly 1 second, but let me explain how you can get very close. Whether that is close enough for you is up to you to decide.
        I will give you the calculations as it is easy to make a mistake here so you can check what I did (and if I am correct)
        You are using 1Mhz. Suppose you use a 1024 precaler. that gives you 1000.000/1024=976.5625 Hz
        Counting to 255 at this speed thus takes 0,26112 sec (255/976.5625)

        As such 0.25 secs takes 0.25*255/0.26112 increments =244.14 (ofcourse I immediately could have used the frequency here)
        Thus set the timer compare register to 244. That will generate an interrupt every 0.25 secs (well almost, it is 0,249855974). Then put a counter in your interrupt that counts to 4. (that gives you 0,999423898 sec)

        Now suppose you do not use a prescaler without prescaler counting to 255 would take 255/1000000=0,000255sec

        Thus in 0.000250 secs the counter will be at 250,
        So if you use 250 in your timer compare register you get an interrupt every 0.00025secs
        So if you then put a counter in your interrupt routine that counts to 4000, in theory you have 1 sec
        The only drawback ofcourse is that an interrupt every 0.00025 secs might be a lot of interruption. Whether your program can take that I do not know

        Edit: my bad. ofcourse you have to put one count less in the compare register as the ‘0’is already 1 count

        You may find this program helpful with various AVR calculations

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: