What are the timers in microcontrollers

Atmel AVR microcontroller

Relief of the microcontroller

Until now, time delays have been created using time loops. However, many applications require exact time delays or time spans.
With time loops it is practically impossible to program exact time delays. In addition, the microcontroller cannot perform any other tasks when processing a loop.

Timers are used to relieve the microcontroller and to meet exact time conditions.

Timer applications

  • Counting external impulses
  • Generation of exact times (time controls, square pulses, etc.)
  • Generation of pulse width signals (PWM) for the control of DC motors, LED dimming, etc.

A timer counts clock pulses from the internal or external oscillator and triggers an interrupt or flag in the event of an overflow.
The internal clock frequency can be clocked down even further with a prescaler.

The timer can be used both as a timer and as an event counter for external pulses (counter).

The 8-bit timer / counter of the ATtiny 2313

The timer / counter register TCNT forms the central part of the assembly.
The ATtiny2313 has an 8-TCNT register (TCNT0) which counts the clock pulses (with 8-bit max. Of 0 to 255 or 0x00 to 0xFF).
The counter reading in the register is increased by 1 with each cycle. If the register is set with all bits, i.e. 1111 1111, the maximum count of 255 has been reached.
The timer now reaches its overflow and sets the timer overflow flag (in the timer / counter interrupt flag register TIFR) to 1.

The flag can be queried or used to trigger an interrupt.
After the overflow, the timer / counter register starts again at 0000 0000 and counts the clocks again to 255 etc.


The set flag can be deleted by setting bit 1 (TOV0 for timer 0) or bit 7 (TOV1 for timer 1) in the timer / counter interrupt flag register TIFR set to 0.

Delete the TOV0

... in the timer / counter interrupt flag register TIFR in C:

TIFR | = (0 << TOV0);


Settings on the timer

In order to be able to operate a timer, it must be set beforehand. These settings are made in various timer registers.

  1. Activation of the interrupts
  2. Activate interrupt for timer overflow
  3. Setting the counting frequency
  4. Setting the timer start value

Timer example - 1 second cycle

Here is a small C program that uses a timer to generate a 1-second cycle. With this second cycle, all LEDs on the PORTB should flash.

The internal clock frequency was set via the fuse bits with 4MHz. This is the base frequency for the clock.
Using the 8-bit timer, a timer interrupt should now be triggered once per second, which then inverts the PORTB and thus generates the flashing sequence.

Since an 8-bit timer counts from 0 to 255 at most, this results in a clock frequency of 4MHz (4000000/256 = 15625 timer overflows per second).
On the one hand, these timer overflows could be counted using a counting loop and thus inverted the PORTB after 15625 timer overflows, or the oscillator clock could be divided down a little with the prescaler.

In this example, the clock frequency is pre-allocated with the prescaler.

Code step by step

The header file is required because an interrupt is used.

TIMSK = (1 << TOIE0);
In the timer interrupt mask register TIMSK becomes the 1st bit TOIE0 (Timer0-Overflow-Interrupt-Enable) set to high.
This tells the program that the Timer0 overflow interrupt should be triggered in the event of a timer overflow.

TCCR0B = (1 << CS02);
We set the value (divider) of the prescaler in the timer / counter control register 0B.
The 2nd bit is set here and results in a frequency division of 256.

Here is an overview of the prescaler settings. For example, to set an advance of 64, the 0th and 1st bit must be set.
CS00 and CS01 = 1 TCCR0B = (1 << CS00) && (1 << CS01);

Clock Select Bit

In our example, the divider 256 was selected and results in a timer frequency of:

4000000/256 = clock frequency of 15625 Hz.

So for the 8-bit timer, we get 15625/256 = 61.0352 overflows per second.
(If you want to have a very exact time base, the timer is preloaded accordingly. But more on that later.)

TCNT0 = 0x00;
Here the timer / counter register is set to the initial state 0000 0000.
If you were to preload the timer with the value 131 (0b1000 0011 or 0x83), for example, then the timer overflows after exactly 125 clock cycles.
And 125 clock cycles correspond to a frequency of 15625/125 = 125 overflows per second.

while (1)
asm ("nop");
The while loop forms an infinite loop. The assembler command nop (No Operation) causes - no operation - so nothing.

If a timer overflow occurs, the timer interrupt is called with ISR (Timer0_OVF_vect).
The if query counts the timer overflows and if 61 overflows are exceeded, the PORTB is inverted in the else statement.

The list of interrupt vectors can be found in the respective data sheet.

Reset and Interrupt Vectors