top of page

3. Timer and Counter Introduction

This tutorial is to introduce timer and counter in AVR microcontrollers.

The timer and counter in the microcontroller count based on the clock frequency. The microcontroller has an embedded clock, and it is also able to connect to an external clock for a higher-frequency operation.

 

The counter can only count up to either 256 (8 bit) or 65535 (16 bit). The Prescaler can be used to skip a certain number of clock ticks and allow the counter to count in a longer interval. The AVR microcontroller has the prescaling number of 8, 64, 256, and 1024. For instance, if 256 is set in the Prescaler, the counter will count once when the clock ticks 256 times.

 

In AVR microcontrollers, such as ATmega328/P, TC0 is a general purpose 8-bit timer/counter, and TC1 is a 16-bit time/counter. This tutorial is only focused on the 8-bit timer/counter.

 

The behaviors of the timer and counter are determined by the Timer/Counter Control Registers.  

 

Example 1: Overview of the TCCR0A and TCCR0B registers

 

    BIT              7                  6                  5                  4                  3                  2                  1                  0

TCCR0A    COM0A1    COM0A0    COM0B1     COM0B0              -                   -            WGM01      WGM00

 

 

    BIT              7                   6                  5                  4                  3                  2                  1                  0

TCCR0B    FOC0A          FOC0B             -                   -              WGM02       CS02           CS01           CS00

 

 

COM0A and COM0B controls the OC0A pin’s and OC0B pin’s behavior respectively. WGM0 is used to set the Waveform Generation Mode.

 

Example 2: The description of the Waveform Generation Mode in WGM0

 

Mode     WGM02     WGM01      WGM00     Timer/Counter Mode     TOP      Update of OCROx at     TOV Flag Set on

   0              0               0                0                       Normal                0xFF               Immediate                   MAX

   1              0               0                1            PWM, Phase Correct     0xFF                  TOP                     BOTTOM

   2              0               1                0                          CTC                OCR0A             Immediate                  MAX

   3              0               1                1                     Fast PWM             0xFF               BOTTOM                    MAX

   4              1               0                0                      Reserved                 -                         -                              -

   5              1               0                1            PWM. Phase Correct     OCR0A               TOP                     BOTTOM

   6              1               1                0                      Reserved                 -                         -                              -

   7              1               1                1                     Fast PWM             OCR0A            BOTTOM                   MAX

 

MAX: 0xFF (8 bit) or 0xFFFF (16 bit)

BOTTOM: 0x00 or 0x0000

TOP: The counter reaches to the highest value in the count sequence. TOP value can be MAX or the value stored in the Output Compare Register A (OCR0A) Register.

 

 

FOC0x (x = A or B) is only active when the WGM0 is specified as a non-PWM mode. When a logic 1 is written to FOC0x, an immediate compare match is forced on the waveform generation unit. The output from OC0x pin is changed based on the COM0x setting. 

 

The FOC0x bit is implemented as a strobe that neither generates any interrupt, nor clears the timer in Clear timer on Compare match (CTC) mode using OCR0x as TOP. The FOC0x bit is always read as zero.

 

CS0 is used to select the clock source and set the Prescaler

 

Example 3: The description of the Clock Select Bit

 

CS02     CS01     CS00     Description

   0            0             0          No Clock source (timer/counter stopped)

   0            0             1          CLK I/O/1 (no prescaling)

   0            1             0          CLK I/O/8 (from prescaler)

   0            1             1          CLK I/O/64 (from prescaler)

   1            0             0          CLK I/O/256 (from prescaler)

   1            0             1          CLK I/O/1024 (from prescaler)

   1            1             0          External clock source on T0 pin. Clock on falling edge

   1            1             1          External clock source on T0 pin. Clock on rising edge

 

 

TCNT Register holds the 8-bit counter value in the microcontroller. TCNT0 is 8-bit and TCNT1 is 16-bit.

 

OCR0x (x = A or B) is an 8-bit register that contains a value that is continuously compared with the counter value in TCNT0. When the value in OCR0x matches the value in TCNT0, an output compare interrupt or a waveform output on the OC0x pin can be generated.

 

Example 4: Set timer 0 in CTC mode

 

TCCR0A = 0b00000010; //Put in CTC mode

 

Alternatively, the code in Example 4 can be written as:

 

TCCR0A |= 1 << WGM01; //Put in CTC mode

 

Example 5: Set the Prescaler to 1024

 

TCCR0B = 0b00000101; //Set the Prescaler to 1024

 

Alternatively, the code in Example 5 can be written as:

 

TCCR0B |= 1<<CS00 | 1 << CS02; //Set the Prescaler to 1024

 

Example 6: Set the TOP value to 200

 

OCR0A = 200; //Set the TOP value

 

Timer/Counter Interrupt Mask Register (TIMSK) is used to enable different interrupt mode. Timer/Counter Interrupt Flag (TIFR) is used to determine which interrupt is currently pending.

 

Example 7: Set the interrupt

 

TIMSK0 |= 1 << OCIE0A; //Interrupt will be triggered when counter reaches the number set in OCR0A

 

Because there is an interrupt event in the program, the library <avr/interrupt.h> has to be included and the global interrupt needs to be enabled.

 

Example 8: Enable the global interrupt

 

sei(); //Enable global interrupt

 

When the condition meets, the Interrupt Service Routing is called. 

 

Example 9: The function of the Interrupt Service Routing

 

ISR (TIMER0_COMPA_vect)

{

}

 

In a 1MHZ microcontroller, if each count takes 1024 clock ticks, and a total count is 200 before the counter restarts, a full cycle would take (1,024x200)/1,000,000 = 0.2048 second.

 

Inside the Interrupt Service Routing, an XOR operation is written to toggle the LED in PIND3

 

Example 10: write a program to toggle the LED in PIND3

 

PORTD ^= 1<<PIND3; //Toggle the LED

 

 

Example 11: The full code to toggle the LED in PIND3

 

#include <avr/io.h>

#include <avr/interrupt.h>

 

int main(void)

{

    TCCR0A |= 1 << WGM01; //Put in CTC mode

    TCCR0B |= 1 << CS00 | 1<<CS02; //Set the Prescaler to 1024

    OCR0A = 200; //Set the TOP value

    TIMSK0 |= 1 << OCIE0A; //Interrupt will be triggered when counter reaches the number set in OCR0A

    DDRD |= 1<<3; //Set PIN3 in PORTD as an output

    sei(); //enable global interrupt

 

    while (1) {}

 

}

 

ISR (TIMER0_COMPA_vect)

{

    PORTD ^= 1<<PIND3; //Toggle the LED

}

 

The code above is to toggle the LED in every 0.2048s; thus, the frequency of the blinking LED is somewhere around 1/(2*0.2048) = 2.4414 Hz.

 

 

 

 

 

 

 

©2020 by Pulin Global

bottom of page