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:
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.
- Normal Mode
- 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
D15 | D14 | D13 | D12 | D11 | D10 | D9 | D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
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.
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
- Generate Delay with Raspberry Pi Pico Timers using MicroPython.
- ESP8266 Interrupts and Timers Arduino IDE – PIR Motion Sensor Example.
- MicroPython: Timers with ESP32 and ESP8266 – Generate Delay with Timer.
- FreeRTOS Software Timers with Arduino – Create One-shot and Auto-Reload Timer.
- AVR microcontroller tutorials for beginners.
- optocoupler interfacing with avr pic and 8051 microcontrollers.
TNX it was useful 4 me .
Thanks you very, this is really great and useful article.
Very Helpful because it was easy to understand.
Thank you.
How to produce 20 sec delay with Crystal frequency of 20 MHZ in AvR microcontroller.. Please help
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