Instructables

Arduino Timer Interrupts

Featured
Picture of Arduino Timer Interrupts
Timer interrupts allow you to perform a task at very specifically timed intervals regardless of what else is going on in your code.  In this instructable I'll explain how to setup and execute an interrupt in Clear Timer on Compare Match or CTC Mode.  Jump straight to step 2 if you are looking for sample code.

Normally when you write an Arduino sketch the Arduino performs all the commands encapsulated in the loop() {} function in the order that they are written, however, it's difficult to time events in the loop().  Some commands take longer than others to execute, some depend on conditional statements (if, while...) and some Arduino library functions (like digitalWrite or analogRead) are made up of many commands.  Arduino timer interrupts allow you to momentarily pause the normal sequence of events taking place in the loop() function at precisely timed intervals, while you execute a separate set of commands.  Once these commands are done the Arduino picks up again where it was in the loop().

Interrupts are useful for:

Measuring an incoming signal at equally spaced intervals (constant sampling frequency)
Calculating the time between two events
Sending out a signal of a specific frequency
Periodically checking for incoming serial data
much more...

There are a few ways to do interrupts, for now I'll focus on the type that I find the most useful/flexible, called Clear Timer on Compare Match or CTC Mode.  Additionally, in this instructable I'll be writing specifically about the timers to the Arduino Uno (and any other Arduino with ATMEL 328/168... Lilypad, Duemilanove, Diecimila, Nano...).  The main ideas presented here apply to the Mega and older boards as well, but the setup is a little different and the table below is specific to ATMEL 328/168.
 
Remove these adsRemove these ads by Signing Up
1-40 of 53Next »

can we generate square wave with varying pulse width with this interrupt ?

yes it's possible, but probably easier to just use the analogWrite command

sir please send program for generating 15000 sample valuesin 10 sec using timer interrupt values adc values from accelometer sensor

sir please send program for generating 15000 sample values using timer interrupt values adc values from accelometer sensor

AbdulW872 months ago

i am confused about something in the code, the line

// turn on CTC mode

TCCR0A |= (1 << WGM01);

shouldnt it be TCCR0A |= (1<<WGM02); or am i understanding this wrong, i am a beginner at arduino so its still very confusing to me.

O-Zo4 months ago

Thank you for this tutorial, I'm struggling with a project and this helped me stumble at least to the right direction.

amandaghassaei (author)  O-Zo4 months ago

cool, glad to hear it!

k7thakar7 months ago
I read many doc about arduino timer and counter but this one most helpful.......thank you for making it.... :)
amandaghassaei (author)  k7thakar4 months ago

thanks!

cavemen5 months ago

65,536/15,624 = 4.19457245264

So the greatest interval we can get from such timer is a little more than 4 sec. or 0.25hz?

I am new to CPL and C++. What does if (toggle1){ } stand for? toggle1 compared to what?

Thanks.

O-Zo cavemen4 months ago

Toggle1 was declared as "boolean" which means it can have values of 1 ( meaning TRUE ) or 0 ( meaning FALSE ). These values are used for "logical" operations, such as in an if statement like you noted. Normally ( doing an if statement ), if you're comparing variable x to some defined number A, for example A = 5, the expression x > A gives you a boolean value 1 ( meaning TRUE ), if x is 6 or higher. So, declaring a if expression "if(toggle1){}" is a kind of funny way of saying if toggle 1 is true (1) you're gonna do it. So now, remembering that we defined toggle1 as 0 at first, the first time we encounter if(toggle1){}, it's not gonna get executed since toggle1 is 0. Instead, since we have declared the "else" part, that's the way we're gonna take. At the end of the "else" statement, there's the line toggle1 = 1, which means that the next time we have to choose between the if and else-statements if(toggle1){} is gonna be TRUE, and since that statement ends with toggle1 = 0, we end up switching between these two expression until the very end.

thegoodhen6 months ago
Hello... The code is very useful, however, be aware that the sketch you posted doesn't seem to ever get into the main loop!
dmeister29 months ago
Hello Amanda!! I've been reading your post! but. What if I what to use pines to get frequencies from A0 to A5 ? I have been reading your guitar tuner post. I would like to to something similar but, reading the 6 strings signals.

What could you recommend to me? :D

greetings and congratulations for your excellent posts
amandaghassaei (author)  dmeister28 months ago
it's a little tricky to read from all the analog inputs. you will definitely not be able to get ~38kHz, probably more like 7kHz (or less), is that ok? The arduino is just not fast enough for this type of thing.
huytien10 months ago
hi everyone,
I have one problem is that. My goal is sending a PWM 100 kHz to pin 13 of arduino Atmega2560, and print data to serial port ("testing" string, for example as codes below). The problem is that, I can not receive the data ( that is "tesing" string). However, when I change to send PWM 1Hz instead of 100 kHz, result is OK. Could any one help me solve this problem? Thank you. Here are codes:
boolean toggle1 = 0;
void setup(){
pinMode(13, OUTPUT);
cli();//stop interrupts
//set timer1 interrupt at 100kHz
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0;//initialize counter value to 0;
// set compare match register to desired timer count:
OCR1A = 19;
TCCR1B |= (1 << WGM12);
TCCR1B |= (1 << CS10);
//TCCR1B |= (1 << CS11);
// enable timer compare interrupt:
TIMSK1 |= (1 << OCIE1A);

sei();//allow interrupts
Serial.begin(9600);

}//end setup
ISR(TIMER1_COMPA_vect){//timer1 interrupt 10kHz toggles pin 13 (LED)
if (toggle1){
digitalWrite(13,HIGH);
toggle1 = 0;
}
else{
digitalWrite(13,LOW);
toggle1 = 1;
}
}

void loop(){
while (Serial.available() > 0) {
Serial.println("testing");
delay(1000);
}

}
amandaghassaei (author)  huytien8 months ago
hmm, the higher frequency interrupt must be disrupting Serial.print. did you find a workaround? you might try using an led indicator for your "testing" message instead.
bstott9 months ago
I believe the following description is all wrong ---- > This leads to the confusion of why this topic is hard. I'm trying but can't filter through the errors. Please re-edit your tutorial to be accurate. The TCCR#B is not matched to the CS#. I will not likely be able to understand and catch other errors. And if I do it will be because I'm confused from the error not knowing what is correct. Thanks for trying....


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


amandaghassaei (author)  bstott9 months ago
thanks for finding that typo! it's fixed now
hpan11 months ago
hola, amanda,

I've been using this tutorial to set up my interrupts for a few times. It's been working great until today. I set timer1 at 2.5khz to perform the interrupt. Mainly use it as a clock and serial reading from the console. The problem is that when I use timer1, PWM on pin 9 and 10 is dead. Pin 9 is the worst one, if I try to use it as analogWrite, arduino will stall. If I use pin 10, arduino will ignore any analogWrite request. It doesn't affect pin 3 and 5. however, if I use timer0, i think it was pin 11 and 3 will be affected in the same way.

Any suggestion to get rid of the problem? or if you know the reason behind it, please do explain here. maybe PWM for PIN 3, 5, 6, 9, 10, 11 use timer0, 1, 2?

Thank you.
amandaghassaei (author)  hpan11 months ago
this is expected. if you look at the atmega 328 pin map: http://cdn3.raywenderlich.com/wp-content/uploads/2013/06/atmegaPinMap.jpg
you will see that timer 1 involves oc1A and oc1B, which are connected to pwm pins 9 and 10. timer0 involves oc0A and oc0B, tied to pins 5 and 6, and timer 2 has the same relationship to pins 3 and 11
the reason those pins are able to do pwm is because they use the timers, so you can't have both. you just have to pick which feature you want to enable.
wlf2351 year ago
Great article! I have additional question: when we modify timer interruption frequency, changing prescaller and so on, how it will affect analogWrite function call? I mean the frequency of PWM, which is "normally" 490Hz when just using arduino API and analogWrite function? In other words how to use PWM features to control external devices (like LEDs or DC engines) by analogWrite and internal interruptions together?
amandaghassaei (author)  wlf2351 year ago
using interrupts, you can essentially create your own, custom analogWrite. You can set this "analogWrite" to any frequency that you want (under 16Mhz).
lnyulak1 year ago
Awesome article!

Sorry for the total newbie question here, but really struggling to understand the following code:

TCCR0A = 0; ...This zeros out entire register including WGM01
TCCR0B = 0; ..This zeros out entire register including WGM02
.
.
TCCR0A |= (1 < < WGM01);
...since WGM01 was set to zero previously, doesn't this evaluate to TCCR0A = 1?

I thought we needed to set
WGM00 = 0
WGM01 = 1
WGM02 = 0

..to get into CTC mode?

In my thinking, this would set WGM00 = 1, WGM01 = 0, and WGM02, which is in TCCR0B is untouched since being reset in line 2.

So this should put us into "Mode 1 - PWM, Phase Correct Mode"

Cheers
maxx-on1 year ago
Oh, I see. I can't reply to a message because there is no reCAPTCHA under the reply box, not because the reCAPTCHA isn't working. It works fine if I create a new post. Someone should fix this. I'm using Firefox 19.0.2 if that make a difference.
maxx-on1 year ago
Yeah, I know I could do that. I could also put in a function pointer into my interrupt handler, I was just wondering if it were possible to drop that overhead and go directly to the interrupt handler of my choice.

P.S. This reCAPTCHA stuff is garbage.:( I've put in several words that I'm absolutely sure are what they should be and it keeps saying "Please type the two words as seen on image"
maxx-on1 year ago
Can you only define one interrupt handler per interrupt? Can you not define multiple ones and switch it from one to another depending on circumstance?
amandaghassaei (author)  maxx-on1 year ago
put and if then statement inside the interrupt
mertg1 year ago
Awesome. Thanks. This helped me a lot. I was struggling to understand timers in pic. This instructable made my mind clear. Also with arduino.
amandaghassaei (author)  mertg1 year ago
thanks!
A nice overview of timer interrupts, thank you for taking the time to write the article. And thank you to those who commented with helpful feedback.
rsellens1 year ago
Nice work! One detail:

timer2 uses a prescale that runs 1, 8, 32, 64, 128, 256, 1024 for the 001 through 111 bit settings. This is different from the 1, 8, 64, 256, 1024, Ext Falling, Ext Rising prescale values for timer0 and timer1 from the table you showed.

All three work the same for 010 giving a prescale of 8, as used in your examples, but slower timer2 interrupt frequencies will give different results.
amandaghassaei (author)  rsellens1 year ago
that's interesting, I didn't know that. I'll update that step. thanks for the tip!
kbeharee1 year ago
Awesome instructable! I have one question though.. You use CS10 CS11 CS12 for timer 1 thats okay but for the other timers eg timer 2 should we use CS20 CS21 CS22 for prescalers rather than CS10 11 12 ?

Thanks.
amandaghassaei (author)  kbeharee1 year ago
good question! no it's always cs10 cs11 cs12. In the code in step 2 you can find an example of how to set up each timer interrupt, they all use cs10 cs11 and/or cs12. to decide which bits you need to set for a certain presclaer (all of them, one or two of them, etc) you use the table in step 2 (fig 4).
Thanks alot for your prompt reply!
bilbolodz1 year ago
Hi,

My problem is:
External signal (via interrupt) after 6ms delay should trigger some actions (call procedure). Each external signal during "counting delay" should reset counting to start. I've already INT0 procedure but now I've program "delay counter". I thing that best idea is to use timers but how to do it? I've Arduino Mego so I've plenty of "free timers" ;-)

{optr
amandaghassaei (author)  bilbolodz1 year ago
can you post your code? at least the interrupt routine and the timer setup. Are you using the delay() function? because it might act strangely depending on how you've set up your timers.
It's quite big program so it's hard to post all code but "main function" are like this:

#define IRQ_1 19
volatile boolean interrupt_1=false;

void irq1_proc(void)
{
interrupt_1=true;
//Serve time critical interrupt stuff
//reset timer (hot do to it?)
}

void timer_proc()
{
//delay passed do something because there wasn't interrupt longer then 6ms
}

void setup()
{
[..]
pinMode (IRQ_1,INPUT);
digitalWrite (IRQ_1,HIGH);
attachInterrupt(4,irq1_proc,FALLING) ;

//Timer setup (how to do it)
}

void loop(void)
{
//Do some usual stuff
if (interrupt_1 == true) {
interrupt_1 = false;
//do some staff when was interrupt but not time critical
}
}

I'm not using delay() because it's real time system it has external time critical devices.
OK, If someone interested I've found solution:
delays longer than 9ms between pulses on pin 19 release timer interrupt,
----
#define IRQ_1 19

volatile boolean interrupt_1=false;

void irq1_proc(void)
{
interrupt_1=true;
//Serve time critical interrupt stuff

//reset timer
reset_timer();
}

ISR(TIMER5_COMPA_vect)
{
//delay passed do something because there wasn't pulse longer then 9ms}
}

void init_timer()
{
  cli();          // disable global interrupts
  TCCR5A = 0;     // set entire TCCR1A register to 0
  TCCR5B = 0;     // same for TCCR1B

  // set compare match register to desired timer count:
  OCR5A = 624; //10 ms
  // turn on CTC mode:
  TCCR5B |= (1 << WGM12);
  // Set CS12 bits for 256 prescaler:
  TCCR5B |= (1 << CS12);
  // enable timer compare interrupt:
  TIMSK5 |= (1 << OCIE5A);
  // enable global interrupts:
  sei();
}
void reset_timer()
{
  cli();          // disable global interrupts - probably not needed because we are in IRQ1 procedure so interrupts are already disabled????
  TCNT5=0;
  sei();        // enable global interrupts:
}

void setup() {
[..] pinMode (IRQ_1,INPUT);
digitalWrite (IRQ_1,HIGH);
attachInterrupt(4,irq1_proc,FALLING) ;
//Initialize timer5
init_timer();
}
void loop(void)
{
//Do some usual stuff
if (interrupt_1 == true)
{
interrupt_1 = false;
//do some staff when was interrupt but not time critical
}
}
halamka2 years ago
sounds like another episode of my name is earl. can you help build a commodore computer. wait a second . well get someone who does not complicate things.
1-40 of 53Next »
Pro

Get More Out of Instructables

Already have an Account?

close

PDF Downloads
As a Pro member, you will gain access to download any Instructable in the PDF format. You also have the ability to customize your PDF download.

Upgrade to Pro today!