How to Use Timers of AVR Microcontroller with Code

In this tutorial, we will see how we use timers on AVR microcontrollers. A Timer is actually a counter that counts every time the microcontroller executes an instruction. There are one to six timers in AVR microcontrollers, depending on their family architecture. The AVR timers are 8 bits and 16 bits. The 8-bit timers are termed TCNTn, while the 16-bit timers are termed two 8-bit registers (TCNTnH and TCNTnL). Generally, AVRs like the ATmega32 consist of three timers: Timer0, Timer1, and Timer2, respectively. The timer0 and timer2 are 8-bit registers, whereas the timer1 is a 16-bit register. Every timer has its own TCCR (Timer/Counter Control Register) register that is responsible for choosing different operational modes.

AVR Microcontroller Timers

Timers are useful for generating time delays or as counters to count events. If we want to use the timer as a counter, then we can connect the external source to the clock pin of the counter register. The content of the counter increments when an event occurs. This increment shows how many times an event has occurred. Now, if we want to generate time delays, we can connect the oscillator to the clock pin of the counter register. This results in an increment in the content of the counter when an oscillator ticks. This indicates how many ticks occurred when the counter was cleared. We can easily calculate the tick period as we are familiar with the speed of the oscillator and can recognize how much time has passed since the content of the register.

There is also a flag for each counter on the microcontrollers. When the counter overflows, it sets the flag. The other technique to generate time delays is to load the counter register, wait for the time when the overflow of the counter takes place, and set the flag. For example, in a microcontroller with a frequency of 1 MHz and an 8-bit counter register, if we need a time delay of 2 seconds, we just have to load the counter register with $FE and wait until the microcontroller sets the flag. In this case, after the first tick, the content of the clock register increases to $FF, and after the second tick, it overflows. In other words, the content of the register becomes $00, and the flag is set. We can understand this concept better from the following diagram:

how to user timers of avr microcontroller

Basic Registers of Timers

There is a TCNTn in the AVR microcontrollers; we call this timer/Counter Register for each of the timers in the AVR. For example, in the ATmega32, we have TCNT0, TCNT1, and TCNT2. The TCNTn is basically a counter. It counts up with each pulse. It contains zero when reset. We can read or load any value in the TCNTn register. Each timer has a TOV called Time Overflow. The TOVn flag is set when the timer overflows, where ‘n’ is any number of timers.

These timers also have a Timer/Counter Control Register. It denotes this as TCCRn, and we can use it for setting up the modes of the timer. Another register of the timer is OCRn, which is the “Output Compare Register.” We can use it as a compare-and-match register. Here, the contents of OCRn are compared with the contents of TCNTn.

Modes of Operation of Timers

There are two modes of AVR Timers.

  1. Normal Mode
  2. CTC mode

Normal mode: In this mode, the content of the timer or counter increases with each clock. It keeps on counting until it reaches its maximum value of 0xFF. When it turns from 0xFF to 0x00, a flag bit sets up and overflow occurs.

CTC mode: In this mode, the timer matches the content. In other words, the content of the timer increases with each clock. This increment goes on until a stage comes when the contents of the TCNTn register become equal to the contents of OCRn. This clears the timer and sets the OCFn flag as the next clock occurs. Here ‘n’ is the number of the timer, like TCNT0, TCNT1, etc., and we can call OCFn the output compare flag of any timer or counter.

Timer1 Programming

Timer1 is a 16-bit timer, which is as follows:

       TCNT1H                                                                                                        TCNT1L

D15D14D13D12D11D10D9D8D7D6D5D4D3D2D1D0

As Timer1 is a 16-bit register, it splits up into two bytes. They are termed TCNT1L and TCNT1H. TCNT1L is a lower byte, whereas TCNT1H is a higher byte. In the above case, the TCNT1L includes register values from D0 to D7, and the TCNT1H includes register values ranging from D8 to D15.

Timer1 also has two timer/counter control registers, termed TCCR1A and TCCR1B. Similarly, timer overflow registers are TOV1 and TOV2, respectively. Whereas there are two output compare registers, OCR1A and OCR1B. There are two separate flags for each of the OCR registers, which are independent of each other. When TCNT1 is equal to OCR1A, the OCF1 flag is set on the next timer clock. Similarly, when TCNT2 is equal to OCR1B, the OCF2 flag is set on the next timer clock.

Timer1 operation modes

Normal mode

In this mode, the timer counts up until it reaches its maximum value of $FFFF. Then it moves from $FFFF to $0000. As a result, the TOV1 flag is set to high.

CTC Mode

In this mode, the timer keeps on counting until the contents of TCNT1 become equal to those of OCR1A. As the timer clears after the next clock and the OCF1 flag sets as a result of the compare-match case. The size of the time delay depends upon two factors: “the crystal frequency” and “the timer’s 16-bit register”. If we want to increase the delay time, then we can use the prescalar option by reducing the period. This option of TCCR1b facilitates dividing the instruction clock by a factor of 8 to 1024.

Atmega32 AVR Timers Programming in C

It is clear that the general-purpose registers of the AVR are under the control of the C Compiler. They are not directly accessed by the C statements. However, all of the special function registers (SFR) are directly accessed by the C statements. In other words, we can say that in ‘C’, we can access timer registers such as TCNT0, OCR0, and TCCR0 directly using their names.

timer0 of avr microcontroller

Let’s see an example showing this phenomenon. The following example will toggle all the bits of PORTB with some delay. LEDs are connected to the PORTB of the AVR microcontroller to check results. A timer is used to generate delays.

AVR Microcontroller Generates Delay with Timers Code

Here we have provided the code for the Proteus simulation.

#include “avr/io.h”

Void T0Delay();

int main()
{

  DRB = 0xFF; // PORTB output port

  while (1)
  {
    PORTB = 0x55; // repeat forever
    T0 Delay(); // delay size unknown

    PORTB = 0xAA; // repeat forever
    T0 Delay();
  }
}

Void T0Delay()
{
  TCNT0 = 0x20; // load TCNT0
  TCCR0 = 0x01; // Timer0, Normal mode, no prescaler

  While((TIFR & 0x1) == 0); // wait for TF0 to roll over
  TCCR0 = 0; // disable timer 0
  TIFR = 0x1; // clear TF0
}

In the above example, we toggled all the bits with PORTB. We generated a time delay using normal mode, in which the timer reaches its maximum value of $FFF. Then it moves from $FFF to $000, and as a result, the TOV1 flag bit is set to high.

Code Explanation

In this section, we will discuss the workings of this code in detail.

#include “avr/io.h”

Void T0Delay();

Firstly, we include a header “tag avr/io.h”. This tag helps us deal with the input and output ports of the AVR microcontroller. Then we declare the T0Delay() function.

int main()
{

  DRB = 0xFF; // PORTB output port

  while (1)
  {
    PORTB = 0x55; // repeat forever
    T0Delay(); // delay size unknown

    PORTB = 0xAA; // repeat forever
    T0Delay();
  }
}

In the main function, we set port B as an output port. Next in the while loop, using the 0x55 command, we set Port B pins as alternating high and low bits. After this, we call the delay function and again set the Port B pin to alternating high and low bits. But this time we use the command 0xAA. Lastly, we call the delay function. This results in the toggling of Port B pins with two different bit patterns with a delay.

Void T0Delay()
{
  TCNT0 = 0x20; // load TCNT0
  TCCR0 = 0x01; // Timer0, Normal mode, no prescaler

  While((TIFR & 0x1) == 0); // wait for TF0 to roll over
  TCCR0 = 0; // disable timer 0
  TIFR = 0x1; // clear TF0
}

Now, in the T0Delay() function body, we first load TCNT0 with the value of the timer duration. Next, we set the Timer0 to normal mode 0 with no Prescaler. Then we check for a timer overflow flag in the while loop. As the timer overflow flag sets, we disable Timer0 and clear the timer overflow flag for the next delay.

Conclusion

In this tutorial, we have discussed the following topics:

  • Introduction to timers
  • Timers of AVR microcontrollers
  • Basic registers and modes of operation
  • Timer1 programming and timer1 operation modes
  • Programming timers in C
  • Code with an explanation

Related Articles

You may also like to read

6 thoughts on “How to Use Timers of AVR Microcontroller with Code”

  1. Sir I want to display voltage and amp.on seven segment display and protect the device with over load underload ,over current under current with user interface or these settings by user like amp. Range 15-35 amp.and HIGH voltage 500ac low voltage 180 band please give me a code and schematic for NUVOTON 8051 microcontroller or Avr programming

    Reply

Leave a Comment