Timers are a vital part of working with microcontrollers. Here I look at types of timers used with Arduino.

Timers are a vital part of working with microcontrollers, continuing the "Improving Arduino Skills" series, I will show you how to work with them in order to unleash the power of timers and counters!

What are Timers used for?

Timers play a vital role in controlling various aspects of the microcontroller, in our case, the Arduino, some of the applications are as follows:

1.) PWM

PWM or Pulse Width Modulation is a method well known and has a wide range of applications, from motor control to dim an LED.

Modulation of the width of a pulse is all about controlling the Duty Cycle, that is, to control how much time the digital output remains high or low, precise control over the time is needed to make PWM work, and for this, we need to use the inbuilt timer that exists inside our Arduino.

2.) Timer Interrupts

There are a lot of use-cases where we need to count the time after an event happens or we want to turn the output of a particular pin high or low after some time, for this we need to use the timers.

Things Required: 

Arduino Uno

LEDs

BreadBoard

Jumper wires

Timers in Arduino

There is a 16Mhz clock that acts as a base clock in Arduino Uno, generally, 16Mhz is too fast for our application so we have to divide it by some number in order to make it useful for our day-to-day applications, that number which we use to divide is known as Prescaler, it helps us in bringing the high-frequency base clock down to match our application.

There are three counter registers in Arduino Uno, namely,  Timer0, Timer1, and Timer2.

Timer0 and timer2 are 8 bit timers, meaning they can store a maximum counter value of 255. Timer1 is a 16 bit timer, meaning it can store a maximum counter value of 65535. Once a counter reaches its maximum, it will tick back to zero (this is called overflow). This means at 16MHz, even if we set the compare match register to the max counter value, interrupts will occur every 256/16,000,000 seconds (~16us) for the 8 bit counters, and every 65,536/16,000,000 (~4 ms) seconds for the 16 bit counter. Clearly, this is not very useful if you only want to interrupt once a second.

Instead you can control the speed of the timer counter incrementation by using something called a prescaler. A prescaler dictates the speed of your timer according the the following equation:

(timer speed (Hz)) = (Arduino clock speed (16MHz)) / prescaler

So a 1 prescaler will increment the counter at 16MHz, an 8 prescaler will increment it at 2MHz, a 64 prescaler = 250kHz, and so on. As indicated in the tables above, the prescaler can equal 1, 8, 64, 256, and 1024. (I'll explain the meaning of CS12, CS11, and CS10 in the next step.)

Now you can calculate the interrupt frequency with the following equation:

interrupt frequency (Hz) = (Arduino clock speed 16,000,000Hz) / (prescaler * (compare match register + 1))

the +1 is in there because the compare match register is zero indexed

rearranging the equation above, you can solve for the compare match register value that will give your desired interrupt frequency:

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

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:

compare match register = [16,000,000 / (1024 * 1) ] -1

= 15,624

since 256 < 15,624 < 65,536, you must use timer1 for this interrupt.

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

}

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


        //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
}
    


Utsource Parts
share how to, diy, homemade, circuit design and new project ideas.