Monday, April 11, 2016

A good site for the three Arduino timers


//timer interrupts
//by Amanda Ghassaei
//June 2012
//http://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).

Step 3: Example 1: Bike Speedometer

Picture of Example 1: Bike Speedometer
schematic.jpg
IMG_9344 copy.jpg
In this example I made an arduino powered bike speedometer.  It works by attaching a magnet to the wheel and measuring the amount of time it takes to pass by a magnetic switch mounted on the frame- the time for one complete rotation of the wheel.

I set timer 1 to interrupt every ms (frequency of 1kHz) to measure the magnetic switch.  If the magnet is passing by the switch, the signal from the switch is high and the variable "time" gets set to zero.  If the magnet is not near the switch "time" gets incremented by 1.  This way "time" is actually just a measurement of the amount of time in milliseconds that has passed since the magnet last passed by the magnetic switch.  This info is used later in the code to calculate rpm and mph of the bike.

Here's the bit of code that sets up timer1 for 1kHz interrupts

cli();//stop interrupts
//set timer1 interrupt at 1kHz
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCNT1  = 0;//initialize counter value to 0
// set timer count for 1khz increments
OCR1A = 1999;// = (16*10^6) / (1000*8) - 1
//had to use 16 bit timer1 for this bc 1999>255, but could switch to timers 0 or 2 with larger prescaler
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS11 bit for 8 prescaler
TCCR1B |= (1 << CS11); 
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei();//allow interrupts

Here's the complete code if you want to take a look:

Step 4: Example 2: Serial Communication

Picture of Example 2: Serial Communication
sparkfun 74hc595 74hc165_schem copy.jpg
This project is a 4x4 backlit button pad.  The project connects to my computer via usb, it sends information about the buttons to the computer and receives information about how to light up the LEDs. Here is a video:



For this project, I used timer2 interrupts to periodically check if there was any incoming serial data, read it, and store it in the matrix "ledData[]".  If you take a look at the code you will see that the main loop of the sketch is what is actually responsible for using the info in ledData to light up the correct LEDs and checking on the status of the buttons (a function called "shift()").  The interrupt routine is as short as possible- just checking for incoming bytes and storing them appropriately.

Here is the setup for timer2:

cli();//stop interrupts
//set timer2 interrupt every 128us
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 7.8khz increments
OCR2A = 255;// = (16*10^6) / (7812.5*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

Here's the complete Arduino sketch:


download the MaxMSP patch below (it will run in Max Runtime as well).

Step 5: Example 3: DAC

Picture of Example 3: DAC
IMG_5499 copy.jpg
IMG_5498 copy.jpg
IMG_5520 copy.jpg
IMG_5521 copy.jpg
In this project I used a timer interrupt to output a sine wave of a specific frequency from the Arduino. I soldered a simple 8 bit R2R DAC to digital pins 0-7.  This DAC was constructed from 10k and 20k resistors arranged in a multi-leveled voltage divider.  I'll be posting more about the construction of the DAC in another instructable, for now I've included the photo's above.
I connected the output from the DAC up to an oscilloscope.  If you need help understanding how to use/read the oscilloscope check out this tutorial.  I loaded the following code onto the Arduino:

I set up a timer interrupt that increments the variable t at a frequency of 40kHz.  Once t reaches 627 it resets back to zero (this happens with a frequency of 40,000/628 = 63Hz).  Meanwhile, in the main loop the Arduino sends a value between 0 (00000000 in binary) and 255 (11111111 in binary) to digital pins 0 through 7 (PORTD).  It calculates this value with the following equation:

PORTD=byte(127+127*sin(t/100));

So as t increments from 0 to 627 the sine function moves through one complete cycle.  The value sent to PORTD is a sine wave with frequency 63Hz and amplitude 127, oscillating around 127.  When this is sent through the 8 bit resistor ladder DAC it outputs an oscillating signal around 2.5V with an amplitude of 2.5V and frequency of 63Hz.

The frequency of the sine wave can be doubled by multiplying the (t/100) term by 2, quadrupled by multiplying by 4, and so on...
Also notice that if you increase the frequency of the timer interrupt too much by decreasing the prescaler or OCR2A the sine wave will not output correctly.  This is because the sin() function is computationally expensive, and at high interrupt frequencies it does not have enough time to execute.  If you are using high frequency interrupts, instead of performing a computation during the interrupt routine, considering storing values in an array and simply calling these values using some kind of index.  You can find an example of that in my arduino waveform generator- by storing 20,000 values of sin in an array, I was able to output sine waves with a sampling frequency of 100kHz.

Step 6: Timer and Arduino Functions

Picture of Timer and Arduino Functions
One last thing to note- certain timer setups will actually disable some of the Arduino library functions.  Timer0 is used by the functions millis() and delay(), if you manually set up timer0, these functions will not work correctly.
Additionally, all three timers underwrite the function analogWrite().  Manually setting up a timer will stop analogWrite() from working.

If there is some portion of your code that you don't want interrupted, considering using cli() and sei() to globally disable and enable interrupts.

You can read more about this on the Arduino website.  
Post a comment
Be nice! 
We have a be nice comment policy.
Please be positive and constructive.
  
Brilliant! I struggled with the datasheets for a few days before finding this instructable, and now it's all clear.
Thanks for sharing.
avionics212 days ago
This is the best interrupts explanations I have come across.
Thanks !
jerrychee94a month ago
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 )

my code is here..
void setup()
{
cli();
TCCR0A = 0;
TCCR0B = 0;
TCNT0 = 0;
OCR0A = 80;// = (16*10^6) / (200000*1) - 1 (must be <256) //200000hz=5microsec 
TCCR0A |= (1 << WGM01);
TCCR0B |= (0 << CS02)| (0 << CS01) | (1 << CS00);
TIMSK0 |= (1 << OCIE0A);
sei();
}
void loop()
{
if(serial.available>0)
{
//if user press something...
TIMSK0 &= ~(1 << OCIE0A);
delay(10000);
TIMSK0 |= (1 << OCIE0A);
}
}
ISR(TIMER0_COMPA_vect)
{
//code
PiraC2 months ago
Good Work. Thank you! 
sam.gwilliam3 months ago
// turn on CTC mode
TCCR0A |= (1 << WGM01);
// Set CS01 and CS00 bits for 64 prescaler
TCCR0B |= (1 << CS01) | (1 << CS00); 
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.
MichealM13 months ago
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!!
MichealM1  MichealM13 months ago
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.
Baguda made it! 3 months ago
In the code you set the timer1 register to CTC mode by "TCCR1B |= (1 << WGM12);". However, for all of the examples using timer0 and timer2, you set the CTC mode by "TCCR0B |= (1 << WGM01);" 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?
Picture of 328timeReg.PNG
AnthonyP7a year ago
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? 
sandro2204  AnthonyP73 months ago
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. 
hal45123 months ago
according to datasheet of atmega328p p106 -108 when we choose values of COM0A0 and COM0BO for timer0
we set the behavior of pins OC0A OCOB After having config them as output and hardware will proceed as its describe in the datasheet.
all modes Normal mode ,CTC mode non PWM ..ect ..are described in page 100
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 ).
hal45123 months ago
you don' need to write a code for toggling because atmega328p has 3 timers
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.
KevinK91  hal45123 months ago
could you please elaborate more on why the toggle code isn't necessary in this sketch?
hackerh3 months ago
so if you wanted an interrupt every second (frequency of 1Hz):
compare match register = [16,000,000 / (prescaler * 1) ] -1
with a prescaler of 1024 you get:
MalachiB15 months ago
Thank you for breaking this down. I've read a lot of articles about timers but only yours makes it clear!
metrog6 months ago
Hi,
Your project and explanations helped me a lot starting with my project. Thanks!
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.
I'm struggling on my next step which is introducing an offset (-200ms / +200ms) between the 2 signals using an analogRead on a knob.
Would you know how to induce such an offset for a Serial output?
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.
Well if this message finds you and you wish to reply, I'm all ears opened.
Thanks again,
Stef
tejonbiker6 months ago
Wonderful, I worked with PICs but I see the AVR work slighly different
youraagh8 months ago
Hi, great tutorial, thanks heaps.
What libraries do I need to include, I'm getting compiler errors saying it doesn't know the names of the timing registers.
PravinahS9 months ago
Hi Amanda,
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!!
SitthinutK9 months ago
Thanks!!
RosmiR10 months ago
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 <256, 1024 prescalar is not present). Could you help me with this. I am just a beginner.
RosmiR10 months ago
How could I make an interrupt of 100Hz with timer 2. Could you share the table for timer2 similar to the one for Timer0 .
ProfRobNewton2 years ago
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?? 
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.
Fardenco  andycomic11 months ago
I had the problem with a motor encoder, just put a 10k Ohms resistor to Vcc and a 1µF capacitor to GND around your interrupt pin, this will be ok !!
Pin interrupt would be more efficient because you'll never miss a change, and above that, you'll not waste time with useless interruption =)
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.
manoch_dca year ago
thank for Example interrupts that working.
!!But void loop() has not work
my increase program
void setup(){
//set pins as outputs
pinMode(7, OUTPUT); //my led
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(13, OUTPUT);
cli();//stop interrupts
same example
sei();//allow interrupts
}
void loop(){
digitalWrite(7, HIGH); // turn the LED on (HIGH is the voltage level)
delay(100); // wait for a second
digitalWrite(7, LOW); // turn the LED off by making the voltage LOW
delay(100); // wait for a second
//do other things here
}
I made a python script that walks you through setting up the code for timer interrupts.
https://gist.github.com/cltnschlosser/e747efae07a76e117e02
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.
zinedinea year ago
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?
Thanks
faizal91a year ago
Thank you... Very nice tutorial!
EnekoL2 years ago
Hei, very usefull application, but i´ve one cuestion, how can i call de interrup for timer 1 inside the loop??Thanks!
ohoilett  EnekoLa year ago
I could be wrong. You may want to check
http://arduino.cc/en/Reference/AttachInterrupt
ohoilett  EnekoLa year ago
You don't call interrupts like normal functions. An interrupt service routine (ISR) is "called" or better yet "triggered" at the specified frequency that you determined when you set up the interrupt. 
thegoodhen2 years 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!
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....
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 years 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-Zo2 years 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-Zo2 years ago
cool, glad to hear it!
k7thakar2 years ago
I read many doc about arduino timer and counter but this one most helpful.......thank you for making it.... :)
amandaghassaei (author)  k7thakar2 years ago
thanks!
cavemen2 years 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  cavemen2 years 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.
dmeister22 years 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)  dmeister22 years 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.

About This Instructable 

 633,016 views
 461 favorites
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