loading

Step 2: Structuring Timer Interrupts


Timer setup code is done inside the setup(){} function in an Arduino sketch.

The code involved for setting up timer interrupts is a little daunting to look at, but it's actually not that hard.  I pretty much just copy the same main chunk of code and change the prescaler and compare match register to set the correct interrupt frequency.

The main structure of the interrupt setup looks like this:
//https://www.instructables.com/id/Arduino-Timer-Interrupts/

void setup(){

cli();//stop interrupts

//set timer0 interrupt at 2kHz
  TCCR0A = 0;// set entire TCCR0A register to 0
  TCCR0B = 0;// same for TCCR0B
  TCNT0  = 0;//initialize counter value to 0
  // set compare match register for 2khz increments
  OCR0A = 124;// = (16*10^6) / (2000*64) - 1 (must be <256)
  // turn on CTC mode
  TCCR0A |= (1 << WGM01);
  // Set CS01 and CS00 bits for 64 prescaler
  TCCR0B |= (1 << CS01) | (1 << CS00);   
  // enable timer compare interrupt
  TIMSK0 |= (1 << OCIE0A);

//set timer1 interrupt at 1Hz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler
  TCCR1B |= (1 << CS12) | (1 << CS10);  
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);

//set timer2 interrupt at 8kHz
  TCCR2A = 0;// set entire TCCR2A register to 0
  TCCR2B = 0;// same for TCCR2B
  TCNT2  = 0;//initialize counter value to 0
  // set compare match register for 8khz increments
  OCR2A = 249;// = (16*10^6) / (8000*8) - 1 (must be <256)
  // turn on CTC mode
  TCCR2A |= (1 << WGM21);
  // Set CS21 bit for 8 prescaler
  TCCR2B |= (1 << CS21);   
  // enable timer compare interrupt
  TIMSK2 |= (1 << OCIE2A);


sei();//allow interrupts

}//end setup
Notice how the value of OCR#A (the compare match value) changes for each of these timer setups.  As explained in the last step, this was calculated according to the following equation:

compare match register = [ 16,000,000Hz/ (prescaler * desired interrupt frequency) ] - 1
remember that when you use timers 0 and 2 this number must be less than 256, and less than 65536 for timer1

Also notice how the setups between the three timers differ slightly in the line which turns on CTC mode:
TCCR0A |= (1 << WGM01);//for timer0
TCCR1B |= (1 << WGM12);//for timer1
TCCR2A |= (1 << WGM21);//for timer2
This follows directly from the datasheet of the ATMEL 328/168.

Finally, notice how the setup for the prescalers follows the tables in the last step (the table for timer 0 is repeated above),
TCCR2B |= (1 << CS22);  // Set CS#2 bit for 64 prescaler for timer 2
TCCR1B |= (1 << CS11);  // Set CS#1 bit for 8 prescaler for timer 1
TCCR0B |= (1 << CS02) | (1 << CS00);  // Set CS#2 and CS#0 bits for 1024 prescaler for timer 0

Notice in the last step that there are different prescaling options for the different timers.  For example, timer2 does not have the option of 1024 prescaler.

The commands you want to execute during these timer interrupts are located in the Arduino sketch encapsulated in the following:
ISR(TIMER0_COMPA_vect){  //change the 0 to 1 for timer1 and 2 for timer2
   //interrupt commands here
}
This bit of code should be located outside the setup() and loop() functions.  Also, try to keep the interrupt routine as short as possible, especially if you are interrupting at a high frequency.  It may even be worth addressing the ports/pins of the ATMEL chip directly instead of using the digitalWrite() and digitalRead() functions.  You can find more info about that here.

Example- the following sketch sets up and executes 3 timer interrupts:

//timer interrupts
//by Amanda Ghassaei
//June 2012
//https://www.instructables.com/id/Arduino-Timer-Interrupts/

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
*/

//timer setup for timer0, timer1, and timer2.
//For arduino uno or any board with ATMEL 328/168.. diecimila, duemilanove, lilypad, nano, mini...

//this code will enable all three arduino timer interrupts.
//timer0 will interrupt at 2kHz
//timer1 will interrupt at 1Hz
//timer2 will interrupt at 8kHz

//storage variables
boolean toggle0 = 0;
boolean toggle1 = 0;
boolean toggle2 = 0;

void setup(){
  
  //set pins as outputs
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(13, OUTPUT);

cli();//stop interrupts

//set timer0 interrupt at 2kHz
  TCCR0A = 0;// set entire TCCR2A register to 0
  TCCR0B = 0;// same for TCCR2B
  TCNT0  = 0;//initialize counter value to 0
  // set compare match register for 2khz increments
  OCR0A = 124;// = (16*10^6) / (2000*64) - 1 (must be <256)
  // turn on CTC mode
  TCCR0A |= (1 << WGM01);
  // Set CS01 and CS00 bits for 64 prescaler
  TCCR0B |= (1 << CS01) | (1 << CS00);   
  // enable timer compare interrupt
  TIMSK0 |= (1 << OCIE0A);

//set timer1 interrupt at 1Hz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS10 bits for 1024 prescaler
  TCCR1B |= (1 << CS12) | (1 << CS10);  
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);

//set timer2 interrupt at 8kHz
  TCCR2A = 0;// set entire TCCR2A register to 0
  TCCR2B = 0;// same for TCCR2B
  TCNT2  = 0;//initialize counter value to 0
  // set compare match register for 8khz increments
  OCR2A = 249;// = (16*10^6) / (8000*8) - 1 (must be <256)
  // turn on CTC mode
  TCCR2A |= (1 << WGM21);
  // Set CS21 bit for 8 prescaler
  TCCR2B |= (1 << CS21);   
  // enable timer compare interrupt
  TIMSK2 |= (1 << OCIE2A);


sei();//allow interrupts

}//end setup

ISR(TIMER0_COMPA_vect){//timer0 interrupt 2kHz toggles pin 8
//generates pulse wave of frequency 2kHz/2 = 1kHz (takes two cycles for full wave- toggle high then toggle low)
  if (toggle0){
    digitalWrite(8,HIGH);
    toggle0 = 0;
  }
  else{
    digitalWrite(8,LOW);
    toggle0 = 1;
  }
}

ISR(TIMER1_COMPA_vect){//timer1 interrupt 1Hz toggles pin 13 (LED)
//generates pulse wave of frequency 1Hz/2 = 0.5kHz (takes two cycles for full wave- toggle high then toggle low)
  if (toggle1){
    digitalWrite(13,HIGH);
    toggle1 = 0;
  }
  else{
    digitalWrite(13,LOW);
    toggle1 = 1;
  }
}
  
ISR(TIMER2_COMPA_vect){//timer1 interrupt 8kHz toggles pin 9
//generates pulse wave of frequency 8kHz/2 = 4kHz (takes two cycles for full wave- toggle high then toggle low)
  if (toggle2){
    digitalWrite(9,HIGH);
    toggle2 = 0;
  }
  else{
    digitalWrite(9,LOW);
    toggle2 = 1;
  }
}


void loop(){
  //do other things here
}

The images above show the outputs from these timer interrupts.  Fig 1 shows a square wave oscillating between 0 and 5V at 1kHz (timer0 interrupt), fig 2 shows the LED attached to pin 13 turning on for one second then turning off for one second (timer1 interrupt),  fig 3 shows a pulse wave oscillating between 0 and 5V at a frequency of 4khz (timer2 interrupt).
<p>thank u sir </p>
<p>Great instructable! Thank you very much!</p>
<p>Thank you for breaking this down. I've read a lot of articles about timers but only yours makes it clear!</p>
<p>how exactly this is working for you all ?</p><p>For me while compiling in arduino 1.6.10 it is showing </p><p><strong>error: 'TIMSK1' was not declared in this scope</strong> which is same for all above registers. do we need any #include header file here?</p>
<p>Should also mention that the clock prescaler bit names CSX0, CSX1, CSX2 has the first number as 'X'. That number 'X' is linked to the timer number. So if 'X' is 0, then CS00, CS01, CS02 are prescaler bit names for timer 0; and the second value represents the bit position. So C00 means bit 0 (right-most-bit) of the 8-bit register TCCR0B, which is for timer 0.</p><p>The reason why I'm indicating this is because the tables (diagram) that go with &quot;prescalers and compare match register&quot; is confusing - since there's no mention about what CS10, CS11, CS12 etc are actually related to.</p>
<p>&quot;so a counter will take 10/16,000,000 seconds to reach a value of 9 (counters are 0 indexed)&quot;</p><p>Do you actually mean it takes 10/16000000 seconds to begin (initial state) from index 0 and get back to a 0 index again? That is, initial index of 0. Then first increment is 1, second increment is 2, third increment is 3, all the way to 9th increment to index 9, and then one extra increment to get back to index 0 again. Altogether 10 increments to 'get back to 0'.</p>
<p>The comment for the line containing &quot;ISR(TIMER2_COMPA_vect)&quot; is confusing. &quot;<em><strong>timer1</strong></em>&quot; should probably be &quot;<strong><em>timer2</em></strong>&quot;.</p>
<p>my signal is in the frequency range between 20Hz and 500Hz, so i am taking the sampling frequency as 5000Hz (sampling time will be .2ms), after sampling i need to store the sampled values in the SD card and so i need to use spi. i want to know how much time will spi take to store in SD card and will i be able to sample my signal at this rate? kindly help</p>
<p>Can anyone please explain the connections to arduino in example 1 ? <br>I want to know how is the signal generator and Oscilloscope is connected to the Arduino ?</p><p>Thanks</p>
<p>Brilliant! I struggled with the datasheets for a few days before finding this instructable, and now it's all clear.</p><p>Thanks for sharing.</p>
<p>This is the best interrupts explanations I have come across.</p><p>Thanks !</p>
<p>Hi, currently im doing project where it prompt user in serial communication and doing interrupt ISR at the same time. So , when user enter a specific value , it will stop the interrupt for few seconds and then restart the interrupt again. However , when restart the interrupt , the timing is out.(expected interrupt time : 5 microsec per interrupt , actual interrupt time : higher than 5 microsec ) <br><br>my code is here..<br>void setup()</p><p>{</p><p>cli();</p><p> TCCR0A = 0;</p><p> TCCR0B = 0;</p><p> TCNT0 = 0;</p><p> OCR0A = 80;// = (16*10^6) / (200000*1) - 1 (must be &lt;256) //200000hz=5microsec </p><p> TCCR0A |= (1 &lt;&lt; WGM01);</p><p> TCCR0B |= (0 &lt;&lt; CS02)| (0 &lt;&lt; CS01) | (1 &lt;&lt; CS00);</p><p> TIMSK0 |= (1 &lt;&lt; OCIE0A);</p><p> sei();</p><p>}</p><p>void loop()<br>{</p><p>if(serial.available&gt;0)</p><p>{</p><p>//if user press something...</p><p>TIMSK0 &amp;= ~(1 &lt;&lt; OCIE0A);</p><p>delay(10000);</p><p>TIMSK0 |= (1 &lt;&lt; OCIE0A);</p><p>}</p><p>}</p><p>ISR(TIMER0_COMPA_vect)</p><p>{</p><p>//code</p><p>} </p>
<p>Good Work. Thank you! </p>
<p> // turn on CTC mode<br> TCCR0A |= (1 &lt;&lt; WGM01);<br> // Set CS01 and CS00 bits for 64 prescaler<br> TCCR0B |= (1 &lt;&lt; CS01) | (1 &lt;&lt; CS00); </p><p>What is the TCCR0A register? TCCR0B must be the 3-bit one as illustrated (where you set the prescaler) but I don't recall any mention of the other one.</p>
<p>This made it much clearer than other reads I have been to. Based on this explanation, I was able to devise a routine to discipline my software clock based on the 16MHz crystal. One of my units (Uno) is ticking at a very wrong speed. Gaining about 30 seconds per day. That's a LOT! But the software can now take care of it and any other errant crystal it encounters. Thanks!!</p>
<p>Sorry. Left out that I am getting NTP time hacks once per day but losing 30 seconds per day is way overboard. Maybe I will replace the crystal and see but as long as I can correct for it, it's not so bad.</p>
<p>In the code you set the timer1 register to CTC mode by &quot;TCCR1B |= (1 &lt;&lt; WGM12);&quot;. However, for all of the examples using timer0 and timer2, you set the CTC mode by &quot;TCCR0B |= (1 &lt;&lt; WGM01);&quot; why do you set bit1 high instead of bit2 for timers 0 and 2 to put them into CTC mode? I found this table online that lists the mode settings(see attached), and it states that (100) is CTC mode. However, it is only for timer1... Is it different for timers 0 and 2?</p>
<p>If the Arduino is executing some code within an interrupt does the counter continue to count up so that the next interrupt is correctly timed? </p>
<p>Yes it does. But you should keep your interupt service routine (ISR) as short as possible. Store a variable, set a flag and that's it. Do time consuming stuff in your main loop. </p>
<p>according to datasheet of atmega328p p106 -108 when we choose values of COM0A0 and COM0BO for timer0</p><p>we set the behavior of pins OC0A OCOB After having config them as output and hardware will proceed as its describe in the datasheet.</p><p>all modes Normal mode ,CTC mode non PWM ..ect ..are described in page 100</p><p>when you'll read:For generating a waveform output in CTC mode the OC0A output can be set to toggle each logical level on each compare match ( you don't have to toggle it by soft ).</p>
<p>you don' need to write a code for toggling because atmega328p has 3 timers</p><p>and every timer has 2 output pins ex: timer2 has OC2A pin 11 and OC2B pin3 and in isr routine u can do other thing.</p>
<p>could you please elaborate more on why the toggle code isn't necessary in this sketch?</p>
<p>so if you wanted an interrupt every second (frequency of 1Hz):</p><p>compare match register = [16,000,000 / (prescaler * 1) ] -1<br>with a prescaler of 1024 you get:</p>
<p>Hi,</p><p>Your project and explanations helped me a lot starting with my project. Thanks!</p><p>I'm using Arduino uno timer 0 and 2 to output 2 distinct (in sync) MIDI Clock signal and it works like charm. I can change BPM with a knob going from 30 to 250.</p><p>I'm struggling on my next step which is introducing an offset (-200ms / +200ms) between the 2 signals using an analogRead on a knob.</p><p>Would you know how to induce such an offset for a Serial output?</p><p>Timr0 and Timer2 doesnt have much room to change start point and end point and the induced delay would only be a few milliseconds maybe.</p><p>Well if this message finds you and you wish to reply, I'm all ears opened.</p><p>Thanks again,</p><p>Stef</p>
<p>Wonderful, I worked with PICs but I see the AVR work slighly different</p>
<p>Hi, great tutorial, thanks heaps.</p><p>What libraries do I need to include, I'm getting compiler errors saying it doesn't know the names of the timing registers.</p>
<p>Hi Amanda,</p><p>I found these article very informative. I'm designing a card reader and i have included these timer interrupts in my programs.I have several confusions to use these timer interrupts on Arduino Leonardo.I have attached pins on pin 3 and pin 2 for D0 and D1 from my Mifare card reader.My card is a Mifare (32bits) type, so when i batch these card,i'm getting the extra bit of 33,so i decided to use timer interrupts just to execute exact 32 bits,but still i'm getting these extra bit.Please help me..Im lost!!</p>
Thanks!!
<p>In an Arduino code for pulse sensor 256 prescalar is activated by TCCR2b=0x06 . Why is it so ? Why is it not 0x04 as per the table for Timer0. Is it possible to make an interrupt of 100 Hz using Timer 2. (ocr2a &lt;256, 1024 prescalar is not present). Could you help me with this. I am just a beginner.</p>
<p>How could I make an interrupt of 100Hz with timer 2. Could you share the table for timer2 similar to the one for Timer0 .</p>
<p>Just wondering if it would not be easier and more accurate to generate an interupt when a switch change is registered and use millis() to determine the time since the last switch change? Sampling every 1ms using the method above may miss a switch change?? </p>
<p>I am no expert but to my knowledge the problem with switch state interrupts is that they bounce and your can't denounce a switch using software on an interrupt routine as its already been triggered (as in the interrupt routine is already done before you have a chance to de-bounce.). The other way is to use a hardware based button debounce switch which just uses a capacitor. This will solve the problem. However unless your project is huge, polling a switch every x cycles doesn't really make any difference to any project.</p>
<p>I had the problem with a motor encoder, just put a 10k Ohms resistor to Vcc and a 1&micro;F capacitor to GND around your interrupt pin, this will be ok !!<br>Pin interrupt would be more efficient because you'll never miss a change, and above that, you'll not waste time with useless interruption =)</p>
<p>While I don't think sampling every 1ms may miss a switch change (think about it, 1000 times a second???) I too would like to know if the more efficient way would be to make an interrupt for the switch change. I have a project that would use something similar and I'm trying to determine the most efficient course of action.</p>
<p>thank for Example interrupts that working.</p><p>!!But void loop() has not work</p><p>my increase program</p><p>void setup(){</p><p> //set pins as outputs</p><p> pinMode(7, OUTPUT); //my led</p><p> pinMode(8, OUTPUT);</p><p> pinMode(9, OUTPUT);</p><p> pinMode(13, OUTPUT);</p><p>cli();//stop interrupts</p><p>same example</p><p>sei();//allow interrupts</p><p>}</p><p>void loop(){</p><p> digitalWrite(7, HIGH); // turn the LED on (HIGH is the voltage level)</p><p> delay(100); // wait for a second</p><p> digitalWrite(7, LOW); // turn the LED off by making the voltage LOW</p><p> delay(100); // wait for a second</p><p> //do other things here</p><p>}</p>
<p>I made a python script that walks you through setting up the code for timer interrupts.<br>https://gist.github.com/cltnschlosser/e747efae07a76e117e02</p>
<p>Could this be used for a 2 player reflex timer game? Trying to push your players button on multiples of 5 seconds and getting a point when you do.</p>
<p>Good job, I want to import 200khz frequency, it's about 5us, but I only have 13.6us with every OCRnA that I used to change from 0 to 80. I'm using 2560. How can I do that?</p><p>Thanks</p>
<p>Thank you... Very nice tutorial!</p>
<p>Hei, very usefull application, but i&acute;ve one cuestion, how can i call de interrup for timer 1 inside the loop??Thanks!</p>
<p>I could be wrong. You may want to check</p><p>http://arduino.cc/en/Reference/AttachInterrupt</p>
You don't call interrupts like normal functions. An interrupt service routine (ISR) is &quot;called&quot; or better yet &quot;triggered&quot; at the specified frequency that you determined when you set up the interrupt.
Hello... The code is very useful, however, be aware that the sketch you posted doesn't seem to ever get into the main loop!
<p>I'm kind of a noob about all this, but unless I'm mistaken the point of interupts is that you don't NEED a main loop. The main loop just runs forever and everything is done when interupts happen. It is an extremely efficient way to code....</p>
<p>can we generate square wave with varying pulse width with this interrupt ?</p>
yes it's possible, but probably easier to just use the analogWrite command
<p>sir please send program for generating 15000 sample valuesin 10 sec using timer interrupt values adc values from accelometer sensor</p>
<p>sir please send program for generating 15000 sample values using timer interrupt values adc values from accelometer sensor</p>
<p>i am confused about something in the code, the line</p><p>// turn on CTC mode </p><p> TCCR0A |= (1 &lt;&lt; WGM01);</p><p>shouldnt it be TCCR0A |= (1&lt;&lt;WGM02); or am i understanding this wrong, i am a beginner at arduino so its still very confusing to me. </p>
<p>Thank you for this tutorial, I'm struggling with a project and this helped me stumble at least to the right direction. </p>

About This Instructable

777,308views

535favorites

License:

Bio: I'm a grad student at the Center for Bits and Atoms at MIT Media Lab. Before that I worked at Instructables, writing code for ... More »
More by amandaghassaei:OTCA Metapixel - Conway's Game of Life "9 Degrees of Freedom" IMU Twitter Controlled Pet Feeder 
Add instructable to: