AVR Ep-13

13- AVR ATmega 16 Tutorials- Timers & Counters || Part 1 || Introduction Leave a comment

Hello everyone and welcome back to the Blog.

12Mhz Crystal Oscillator
12Mhz Crystal Oscillator

In this post, we are going to talk about timers and counters which are one of the most crucial aspects of any embedded systems. Microcontrollers or microprocessors use crystal oscillators as clock sources. These clock sources determine the speed at which instructions are executed inside the controller or the processor. The CPU requires a fixed number of clock ticks (or clock cycles) to execute each instruction. The faster the clock, the more instructions the CPU can execute per second.

In the older generation of microcontrollers such as the 8051 series, we needed to provide the clock source externally using an external quartz crystal like the one in the right. We can still do that with the AVR Atmega series and we will do so in future posts when we require more accurate time management. But the AVR microcontrollers also come with an inbuilt internal crystal which we can use as the clock source. In fact, we have been using it in all of the last posts without even knowing about it.

Clock Pulse
Clock Pulse Example

Now the frequency of these crystal oscillators are precisely defined and very stable; therefore, the pulses they generate are always of the same width, which makes them ideal for time measurement. In order to measure the time between two events, it is sufficient to count up pulses coming from the crystal oscillator. That is exactly what the Timer does. If the timer is properly programmed, the value stored in its register will be incremented (or decremented) depending upon the settings, with each coming pulse, i.e. once per each machine cycle. As a result, we can accurately measure the time.

For example, our controller which is ATmega16, by default is set to work at 1 MHz. This means it can execute 1 million instructions every second or the clock inside it will have undergone 1 million individual ticks every one second. So any timer register will count up to 1 million when configured to this configuration every second. We can thus say that if the timer has counted to 1 million then 1 second has elapsed from the start of counting. This is a crude example as in reality the timer register cannot count up to 1 million being either an 8 bit or 16-bit register and the counter will overflow once it reaches its size limit. But you get the idea. We use timers to accurately count the clock ticks and thus the time between two events.

Difference between Timers and Counters

Now the one thing that most people confuse with is the difference between timers and counters. In terms of our application, they are the same thing. We have a functionality in the microcontroller that times the clock speed known as timers and there is a dedicated register present which counts this timing which is known as the counter. They are not separate entities. Timers time the clock and counters store the data. 

Applications of Timers

  • We use them as reference signals for signal generators.
  • They are also used to introduce delays in the code (Example: the util/delay function).
  • We also use timers to create PWM signals required to work with motors and servos.

There are many more applications that we will delve into in future posts as we get more familiar with the microcontroller field. In this post, we will focus on the time functionality of the timers ie. how to measure time and create delays in the code.

Different Timers present in ATmega16

In ATmega16 controller we have got three timers that can work independently as well as together at the same time. They are:

  • Timer/Counter 0 (8-bit)
  • Timer/Counter 1 (16-bit)
  • Timer/Counter 2 (8-bit)

Now comes the question of what does 8 and 16 bit as written above actually mean…

We know now that a timer will count in parallel with the clock source. Every machine cycle will therefore either increment or decrement the value of the counter depending upon the timer settings. So there needs to be a dedicated register in the microcontroller where this value is stored and updated every machine cycle. Here comes the concept of 8 and 16 bits. For Timer/Counter 0 and 2, this register has a size of 8 bits. This means that the maximum this register can count up to is 255 starting from zero. After which the register will overflow and needs to be reset.

Now here again comes a problem. Even with the low speed of 1 MHz, our controller clock ticks at the rate of 1 million ticks per second. This means that the timer will count up to 1 million in 1 second. But, that is not possible as the maximum value that the timer can store is 255. Think now how fast the timer will overflow in this situation. How do we then record time for let’s say 500 milliseconds or 1 second which are too large of a time interval for the timer to store. There are various ways of solving this problem and one of them is by using prescalers. We will talk about them in the next post when we practically implement Timers on a project.
The 16-bit timer…which is Timer/Counter 1 can then count up to 65535 starting from zero, which is a little better and gives a little flexibility when dealing with large time intervals.

Timer Counter Register(TCNT)

The counter values are stored in a register named TCNT; which stands for Timer Counter Register. Each timer has a dedicated register for itself so in total, we have three registers.

  • TCNT0
  • TCNT1 
  • TCNT2 

TCNT1 here is of 16 bit while the other two as said are of 8 bits each. At any instant in the code, we can check the TCNT value of any timer which has been enabled to know how many clock cycle has elapsed since the timer was turned on.

Timer Overflow Interrupt

The question now comes as to what to do with this timer/counter value that is stored in the TCNT register. Here, we can incorporate the concept of interrupts that we learned in the last two posts.
One way to do this is an overflow interrupt. So whenever the TCNT register reaches its maximum value which is 255 in the case of 8 bits and 65535 for the 16 bits timer; an interrupt is triggered. In the Interrupt routine, we can then give any commands for the microcontroller to execute after the timer overflowed.

Output Compare Register(OCR)

Another way of using timers is we first decide on a value which we save in a dedicated register and then in each machine cycle, we compare this value with the current value of the TCNT register. Whenever these values match an interrupt is triggered. In ATmega16 controller we have dedicated registers for this that even take care of the compare by themselves. The registers are called Output Compare Register or OCR. The value that we store in this register is automatically compared with the value stored in the TCNT register and an interrupt can be triggered whenever a match is achieved. This is done automatically and we do not need to do the compare ourselves. For each timer we have these registers:

  • OCR0 for Timer/Counter 0 (8-bit)
  • OCR2 for Timer/Counter 2 (8-bit)
  • OCR1A & OCR1B for Timer/Counter 1 (16-bit)

We will get into their details when we implement them on a practical project. You can now visualize a situation where whenever a certain time has elapsed we trigger an interrupt and do a certain task let’s say toggle an LED or send some information to an LCD. This is how we use timers for delay purposes in microcontrollers.

I would ask you now to go through the video below where I explain everything in more details:



If you want to continue on with this series I would ask you to visit our YouTube channel and subscribe to receive continuous notifications. You can also subscribe to our Newsletter below to get email notification of each post as and when they are posted.

You can also follow us on social media platforms such as  Facebook and Twitter.

Thanks a lot for reading through this post. Feel free to follow through this series and comment your queries in the comment box below. Also feel free to contact us regarding any out of stock product and we will try to get back to you as soon as possible.

Leave a Reply