Introduction: Arduino: Pushing the Limits || Arduino Timers.

About: motaz bany-amer!! jordan 2/7/1994 Yarmouk university - jordan work at Genotronex lab, IEEE YU Robotics Team, YES yarmouk engineering students, hijjawy art engineers. =-=-=-=-=-=-=-=-=-=-=-=-=-=-= facebookhtt…

the arduino has great abilities and features indeed, the language, the speed, the easy to use, the great development board, the documentation, the price, and the interfacing ability to a lot of devices and programs. you will not get to know how great these features are, until you use the Arduino with the max ability. In the series : "Arduino: pushing the limits" i will try to show how you can maximize the abilities of the arduino, and use it with a better and smarter ways, increasing the abilities, flexibility, reliability of your projects, and make them easy to remake.

this is the first instructable in the series, it talks about the Arduino Timers feature.

In this instructable, I will talk about the Arduino timers, what are they, how they work, and how to use them; giving some simple examples and demonstrating some benefits to use them.

after this instructable you should be able to make a greater projects with more flixibe code and details, and you will have more abilities to add to your project.

one example I made using the Timers feature in the arduino, the "Timed Plug-In" it is a project of asimple electricity plug that can be timed to some specific duration (in my project the durations are 1,2,..6 hours and it can be set to any durations you want) after the duration passed the plug will not supply any power through it. which should be useful thing to be used to charge a phone while sleeping for two hours for example. the details of this project will be show in next instructable. [see Update]

*I will suppose you have a good knowledge with arduino basics and concepts, and how to use them, so I can go further to how to improve them.

*I will quote some information in this instructable from the this article : Arduino 101: Timers and Interrupts

UPDATE :

check out the next tutorial, a project based on arduino timers, Arduino: Pushing the Limits || Power-plugin timer.

Step 1: What Is Arduino Timer

have you ever think how arduino get to know the time! I mean, how the arduino knows how much it should wait to delay for 100 ms for example, or how the it have to chop the 5V signal to output a specific PWM signal!

the answer to this lies in knowing the architecture of the MCUs, I will not talk about the architecture here, it's enough to mention that the arduino have something like the heart! it generate pulses(a pulse in the arduino means something like a step that is taken by the arduino to do a task), with specific speed, its the crystal and its speed is 16 MHz. from this fact we can tell that the pulse come with specific time = (1/16M)s. that means there is a constant duration between every two pulses. depending on this, if calculated the pulses with a counter, we can get real time, by knowing the counter counts.

the hardware part that does the counting task in the arduino called Timer. its a counter increase with a specific rate, in such a way that every count gives a time, knowing the counter value let you know how much time has passed.

the details will be explained in the next steps. for know i have just explained how timer work and how the arduino use it to know the time.

in the next step i will talk about the timer in the arduino.

Step 2: Arduino Timer

the timer in an MCU is a register, consist of specific number of bits, in the arduino, and I will take the arduino uno as an example here, there is a 3 timers called: timer0 , timer1, timer2. they are extended to timer 3,4, and 5 with mega.

Timer0:
Timer0 is a 8bit timer.
In the Arduino world timer0 is been used for the timer functions, like delay(), millis() and micros(). If you change timer0 registers, this may influence the Arduino timer function. So you should know what you are doing.
Timer1:
Timer1 is a 16bit timer.
In the Arduino world the Servo library uses timer1 on Arduino Uno (timer5 on Arduino Mega).
Timer2:
Timer2 is a 8bit timer like timer0.
In the Arduino work the tone() function uses timer2.
Timer3, Timer4, Timer5:
Timer 3,4,5 are only available on Arduino Mega boards. These timers are all 16bit timers.

in this instructable I will talk about the use of timer 1 and 2 as an example for 16 bits and 8 bits timers.

you should know that, the basically is a register, the timer system consists of multiple registers, ones that hold the counter and ones that hold the settings and the functions.

you can change the Timer behavior through the timer register. The most important timer registers are:
TCCRx - Timer/Counter Control Register. The prescaler can be configured here.

TCNTx- Timer/Counter Register. The actual timer value is stored here.
OCRx - Output Compare Register
ICRx - Input Capture Register (only for 16bit timer)
TIMSKx - Timer/Counter Interrupt Mask Register. To enable/disable timer interrupts.
TIFRx - Timer/Counter Interrupt Flag Register. Indicates a pending timer interrupt.

now I will describe the process the timer will be setup with.

first you should note that:

the first register, TCNTx is the register that handle the real timer value, when we want to know what timer value has been reached we will read that register . also we can use this register to preload the timer with some value, for a simple reason! to ensure that the timer interrupt duration is set to specific value that we can deal with, you'll see that with the examples.

note that "x" notation refer to the number of timer used, (if we work with timer 0 then x is 0 : TCNT0)

TIMSKx register will be used to enable or disable timer interrupts, the interrupts definition will be illustrated in the next step.

TCCRx this register will be used to set the prescaler, the prescaler can be illustrated some how with a number of selected counts that the timer have to make to increase its value by 1. so if the prescaler is set to 10 for example, then every 10 timer clocks the timer counter value will increase by 1. a larger prescaler value, the longer time the timer counter can achieve before over flow.

Clock select and timer frequency
Different clock sources can be selected for each timer independently. To calculate the timer frequency (for example 2Hz using timer1) you will need:
1. CPU frequency 16Mhz for Arduino
2. maximum timer counter value (256 for 8bit, 65536 for 16bit timer)
3. Divide CPU frequency through the chosen prescaler (16000000 / 256 = 62500)
4. Divide result through the desired frequency (62500 / 2Hz = 31250)
5. Verify the result against the maximum timer counter value (31250 < 65536 success) if fail, choose bigger prescaler.

with these steps you can calculate the timer frequency for any frequency you want, of curse you can change the prescaler to any value you want.

for an 8bit timer, the process is the same, the only restriction is that the value have to be less the 256. so you should use large prescaler, and high frequency. usually its better to use 16bit timer, in arduino mega there is no problem with that, there are 4 timers with 16bits, the problem appears with arduino uno, there is only timer1 comes with 16 bit, if you are using Servo library or any library that based on timer1 you will not be able to use it, and the functions will interface each other, so sometimes you will have to use an 8 bit timer.

in this instructble there will be an example for using 8 bit timer with low frequencies.

Step 3: Arduino Interrupt

What is an interrupt?
The program running on a controller is normally running sequentially instruction by instruction. An interrupt is an external event that interrupts the running program and runs a special interrupt service routine (ISR). After the ISR has been finished, the running program is continued with the next instruction. Instruction means a single machine instruction, not a line of C or C++ code.
Before an pending interrupt will be able to call a ISR the following conditions must be true:
· Interrupts must be generally enabled
· the according Interrupt mask must be enabled
Interrupts can generally enabled / disabled with the function interrupts() / noInterrupts(). By default in the Arduino firmware interrupts are enabled. Interrupt masks are enabled / disabled by setting / clearing bits in the Interrupt mask register (TIMSKx).
When an interrupt occurs, a flag in the interrupt flag register (TIFRx) is been set. This interrupt will be automatically cleared when entering the ISR or by manually clearing the bit in the interrupt flag register.
The Arduino functions attachInterrupt() and detachInterrupt() can only be used for external interrupt pins. These are different interrupt sources, not discussed here.
Timer interrupts
A timer can generate different types of interrupts. The register and bit definitions can be found in the processor data sheet (Atmega328 or Atmega2560) and in the I/O definition header file (iomx8.h for Arduino, iomxx0_1.h for Arduino Mega in the hardware/tools/avr/include/avr folder). The suffix x stands for the timer number (0..5), the suffix y stands for the output number (A,B,C), for example TIMSK1 (timer1 interrupt mask register) or OCR2A (timer2 output compare register A).
Timer Overflow:
Timer overflow means the timer has reached is limit value. When a timer overflow interrupt occurs, the timer overflow bit TOVx will be set in the interrupt flag register TIFRx. When the timer overflow interrupt enable bit TOIEx in the interrupt mask register TIMSKx is set, the timer overflow interrupt service routine ISR(TIMERx_OVF_vect) will be called.
Output Compare Match:
When a output compare match interrupt occurs, the OCFxy flag will be set in the interrupt flag register TIFRx . When the output compare interrupt enable bit OCIExy in the interrupt mask register TIMSKx is set, the output compare match interrupt service ISR(TIMERx_COMPy_vect) routine will be called.
Timer Input Capture:
When a timer input capture interrupt occurs, the input capture flag bit ICFx will be set in the interrupt flag register TIFRx. When the input capture interrupt enable bit ICIEx in the interrupt mask register TIMSKx is set, the timer input capture interrupt service routine ISR(TIMERx_CAPT_vect) will be called.

personally, I like to use the overflow ISR, so the most examples will be on using it, with good notation and illustraions. of cures I will mention the compare match ISR but it will be quoted from the original article mentioned earlier.

*** please refer to the original article where there is extra notes about "PWM and timer" and"pitFalls" that can have good information for you.

.

Step 4: Blinking LED With Compare Match Interrupt

***this example is quoted from Arduino 101: timer and interrupts

The first example uses the timer1 in CTC mode and the compare match interrupt to toggle a LED. The timer is configured for a frequency of 2Hz. The LED is toggled in the interrupt service routine.

<br><p>/* Arduino 101: timer and interrupts<br>   1: Timer1 compare match interrupt example 
   more infos: http://www.letmakerobots.com/node/28278
   created by RobotFreak 
*/</p><p>#define ledPin 13</p><p>void setup()
{
  pinMode(ledPin, OUTPUT);
  
  // initialize timer1 
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;</p><p>  OCR1A = 31250;            // compare match register 16MHz/256/2Hz
  TCCR1B |= (1 << WGM12);   // CTC mode
  TCCR1B |= (1 << CS12);    // 256 prescaler 
  TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
  interrupts();             // enable all interrupts
}</p><p>ISR(TIMER1_COMPA_vect)          // timer compare interrupt service routine
{
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1);   // toggle LED pin
}</p><p>void loop()
{
  // your program here...
}</p>

Step 5: Blinking LED With Timer Overflow Interrupt

***this example is quoted from Arduino 101: timer and interrupts....

***I will add some notes in the next step to make things clear.

.......................................

same example like before but now we use the timer overflow interrupt. In this case timer1 is running in normal mode.
The timer must be preloaded every time in the interrupt service routine.

<p>/* <br> * Arduino 101: timer and interrupts
 * 2: Timer1 overflow interrupt example 
 * more infos: http://www.letmakerobots.com/node/28278
 * created by RobotFreak 
 */</p><p>#define ledPin 13</p><p>void setup()
{
  pinMode(ledPin, OUTPUT);</p><p>  // initialize timer1 
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;</p><p>  TCNT1 = 34286;            // preload timer 65536-16MHz/256/2Hz
  TCCR1B |= (1 << CS12);    // 256 prescaler 
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts
}</p><p>ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  TCNT1 = 34286;            // preload timer
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1);
}</p><p>void loop()
{
  // your program here...
}</p>

Step 6: Blinking LED With Timer Overflow Interrupt Notes

first we set up the timer, there are main registers will be used,

TCCRx, to set up prescaler.

TCNTx, to preload timer counter

TIMSKx,to enable timer interrupt you want.

then you write the interrupt ISR code to be called.

in this example the prescaler is set to 256. first of all, the code calls :

TCCR1A = 0;
TCCR1B = 0;

will this simply clear the presacler register.

then you are ready to set it up. with this line :

TCCR1B |= (1 << CS12);

refere to the table, if you set the bit "CS12" to 1 and the others are 0 , the the prescaler is set to 256.

here you should note:

  • in this way the prescaler is been set to a value, you refer to the table to the configuration of CS12,11,10 , and set it up.
  • filling the register with values can be done with two ways :
    *by give it a direct value like : "TCCR1A = 0;" in this way you have to know the register bit number and know how you want to fill it then convert the bits to decimal or HEX then set it to the register.
    *the other way is to fill the a single bit at once. this can be done with bitwise math.
    to read about bitwise math : Bitwise operation
    to learn about bitwise in arduino : Bitwise
  • we can do this by do mathematical bitwise operation to change the digital state of the bit to 0 or 1, using the bitwise operators.
  • the operator ( | ) means "or", in digital m any thing compared with "or" operator with "1" the result is 1 , so we will use this to change the digital state of a bit to 1. of curse the process (|=) is just like the process of addition or subtraction when we say (x +=1 as example).
  • the operator (<<) shift a given value by a given number to the left, like this (1<<5 : the value 1 will be shifted by 5 bits)
  • so the process TCCR1B |= (1 << CS12); set the CS12 bit in the TCCR1B register to digital 1 .
  • if you want to clear a bit (fill 0) the process little bit defiant,
  • we will use the operator & not | , if we use ( | ) , any thing is compared with "or" with 0 , is not affected , but and thing compared with "and" with 0 is cleared to 0 .
  • so the process will be : TCCR1B &= (0 << CS12);

now we preload the timer if we want to, preloading timer give you the ability to control the timer will over flow, so you control the frequency of the ISR.

to preload the frequency for an overflow ISR , we fill the TCNTx reg directly with the value . the value is calculated with the the mathematical equation :

65536-16MHz/prescaler/Hz

for 16bit timer, and :

256-16MHz/prescaler/Hz

for 8 bit timer.

in this example the prescaler is 256, and the frequency is 2Hz . divide 16MHz by 256

then divide the result by the frequency. then fill in the result in the register.

the last thing to do is to enable the overflow interrupt. now you are ready to write you ISR.

the ISR is a special type of function that is called with interrupt routine, the timer interrupt name should have right name and (x) number : TIMERx_OVF_vect , in this example we use timer 1 so TIMER1_OVF_vect.

the ISR function should be short and simple, you cant use "delay()" inside it, you can call a function or use any library member just like the other functions, of curse any thing you will use inside it have to be declared within its scope. HOWEVER, if you called a function or a library member that uses delay with its procedure (like dht11 library) the delay inside the called function will not be executed and the function will be called without it, the result most often will not be logical (in dht11 case the readings will be very wrong and random).

notice that there are "noInterrupts" and "interrupts" functions called before and after the setting up procedure of the timer, he just dead that to make sure that all unneeded interrupts are off, and then he enable all interrupts that has been set up.

...........

in the original article, there are more exmple you can return to it and read them.

in the next steps i will give more examples I made my self that can help you to improve your coding, they are just like some methods and tricks that you can use with timers to improve your coding and projects.

Step 7: Seconds Counter

in some projects, you might want to make a counter that calculate the time from the start of an event. the seconds from the start of the program for example. of curse there are (millis()) function in the arduino language that get the time im ms from the start of the project, but some times we cant use it in our procedure and some times it is hard to use it in right way. this is an alternative way to calculate the seconds from the start of the program or any event.

actual you will be able to calculate any rate of time not just seconds, just by manipulating the code parameters with the right way, i will use seconds just as example.

in this example i will use timer1 (16Bits) to generate an interrupt with 1Hz frequency(1 second duration). in the ISR there will be a global counter variable, that will be used to count the seconds in the ISR then to use it in the main code.

the procedure is simple, and the preload timer calculation is very simple.

<p>int secondCounter = 0;<br>void setup() 
{
  //  **Inturrubts**
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 3036;            // preload timer 65536-16MHz/256/1Hz
  TCCR1B |= (1 << CS12);
  TCCR1B |= (1 << CS10);    // 1024 prescaler
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts
  //*****
}
ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  TCNT1 = 3036;            // preload timer
  secondCounter++;
}
void loop() 
{
}</p>

Step 8: Second Counter

I will show here some uses of the second counter made by timer.

  • one usage is to run another code in the background that needs to be called with specific frequency.
    you just add your functions in the ISR, one example is blink a LED, or you can use Serial.println function to print the seconds from the start of the code as background function.
  • with this counter you can make a procedure, that makes your code repeat it self with specific duration.
    see the next code , please read the notes carefully.
int secondCounter = 0;
int duration = 5; // you can set any duration you want.
//of curse it's logical to set a duration larger than your "code", or the technique will not work as it should
void setup() 
{
  //  **Inturrubts**
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 3036;            // preload timer 65536-16MHz/256/1Hz
  TCCR1B |= (1 << CS12);
  TCCR1B |= (1 << CS10);    // 1024 prescaler
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts
  //*****
}
ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  TCNT1 = 3036;            // preload timer
  secondCounter++;
  if(secondCounter == duration)
  {
    secondCounter = 0;
  }

//its not the only way to do this, you can use the operator %(mod) and let the time counter increase normally, with mode you can do the condition (secondCounter%duration == 0) 
}
void loop() 
{
  if(secondCounter == 0) // every time the counter reaches duration (5) it return to 0 and the condition is true.
  {
    //code
  }
}
  • you can use it to make a procedure of code, that will make your project works within specific duration of starting the code, or from some event. for example, you can make a code to light up the house at night and turn it off at day, representing the day time in seconds, you turn off the light from the 6th second (6 AM) to the 18th second(6 PM), and repeat the procedure. see the next code:
<p>int secondCounter = 0;<br>int duration = 24; // you can set any duration you want.
int time1 = 6;
int time2 = 18;
boolean flag1 = 0;
boolean flag2 = 0;
int lightPin = 13;
void setup()
{
  //  **Inturrubts**
  noInterrupts();           // disable all interrupts
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 3036;            // preload timer 65536-16MHz/256/1Hz
  TCCR1B |= (1 << CS12);
  TCCR1B |= (1 << CS10);    // 1024 prescaler
  TIMSK1 |= (1 << TOIE1);   // enable timer overflow interrupt
  interrupts();             // enable all interrupts
  //*****
}
ISR(TIMER1_OVF_vect)        // interrupt service routine that wraps a user defined function supplied by attachInterrupt
{
  TCNT1 = 3036;            // preload timer
  secondCounter++;
  if (secondCounter == duration) // when the day is over, start over the timer counter from zero.
  {
    secondCounter = 0;
  }
  if (secondCounter >= time1 && secondCounter <= time2) //day time
  {
    flag1 = 1;  // activate the condition of task 1 (day time)
    flag2 = 0;
  }
  else //night time
  {
    flag1 = 0;
    flag2 = 1;  // activate the condition of task 2 (night time)
  }
}
void loop()
{
  //flag1, and 2 will be changed in the background, when a flag is set true/1 its(while) runs.
  while (flag1) // day time -- turn off the lights
  {
    digitalWrite(lightPin, 0);
  }
  while (flag2) // night time -- turn on the lights
  {
    digitalWrite(lightPin, 1);
  }
}</p>

Step 9: Setting Up 8 Bit Timer.

the 8 bit timer max value is 255(0-255), you cant exceed that value, and if you do, the register will make an overflow( if you give it value equal to 256 for example, it will over flow and the actual value inside it will be 0)

to handle such small value we have to use suitable prescaler and frequency, and use small trick!

the max prescaler that can be used is 1024, if the frequency is high enough to make te result < 255, then it's OK, but what about if we want to achieve small frequency! we have to increase our prescaler. the thing we can do to increase this value, is increase it manually!

in the ISR, you can add sub counter, when the counter reach some value, the main counter increase. see the next example .

int secondCounter = 0;
int timerCounter = 0; int duration = 24; // you can set any duration you want. int time1 = 6; int time2 = 18; boolean flag1 = 0; boolean flag2 = 0; int lightPin = 13; void setup() { // **Inturrubts** noInterrupts(); // disable all interrupts TCCR2A = 0; TCCR2B = 0; TCNT2 = 101; // preload timer 256- 16MHz/(1024*100Hz) //timer frequancy is 100Hz TCCR2B |= (1 << CS12); TCCR2B |= (1 << CS10); // 1024 prescaler TIMSK2 |= (1 << TOIE2); // enable timer overflow interrupt interrupts(); // enable all interrupts //***** } ISR(TIMER2_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt { TCNT2 = 101; // preload timer timerCounter++; if (timerCounter == 1000)//every 1000 timer counts gives 1 secound increase.. { secondCounter++; timerCounter = 0; Serial.println(secondCounter);//to show the time on the serial monitor if (secondCounter == 24) { secondCounter = 0; } if (secondCounter >= 7 && secondCounter <= 20) //activate system // if you want defirant times change 7 and 20 . { flag1 = 1; flag2 = 0; } else //deactivate system { flag1 = 0; flag2 = 1; } } } void loop() { //flag1, and 2 will be changed in the background, when a flag is set true/1 its(while) runs. while (flag1) // day time -- turn off the lights { digitalWrite(lightPin, 0); } while (flag2) // night time -- turn on the lights { digitalWrite(lightPin, 1); } }