8-Bit AVR® MCU Timer Example Project

Last modified by Microchip on 2023/11/09 09:12

This page illustrates several methods of configuring the timers on an 8-bit AVR® MCU. An overview of the timers on an AVR is provided before the step-by-step example is presented.

Resources

Back to top

Overview of Timers on 8-bit AVR MCUs

ATmega328PB microcontroller has five Timer/Counters:

Timer 0TC08-bit Timer/counter with PWM
Timer 1TC116-bit Timer/counter with PWM and Asynchronous Operation.
Timer 2TC28-bit Timer/counter with PWM and Asynchronous Operation.
Timer 3TC316-bit Timer/counter with PWM and Asynchronous Operation.
Timer 4TC416-bit Timer/counter with PWM and Asynchronous Operation.

Back to top

Definitions:

Register Nomenclature
BOTTOMThe counter reaches the BOTTOM when it becomes zero (0x00 for 8-bit counters and 0x0000 for 16bit counters
MAXThe counter reaches its maximum value when it becomes 0x0F (15 decimal) for 8-bit counters and 0x00FF (255 decimal) for 16-bit counters
TOPThe counter reaches the TOP when its value becomes equal to the highest value possible. The TOP value can be assigned fixed value MAX or the value stored in the OCRxA register. This assignment is dependent upon the mode of operation

Back to top

Timer 0 - 8-bit Timer/Counter with PWM

Timer/Counter0 (TC0) is a general purpose 8-bit Timer/Counter module, with two independent Output Compare Units, and PWM support.

Back to top

TC0 Registers

The Timer/Counter 0 register (TCNT0) and Output Compare TC0x registers (OCR0x) are 8-bit registers. Interrupt request signals are all visible in the Timer Interrupt Flag Register 0 (TIFR0). All interrupts are individually masked with the Timer Interrupt Mask Register 0 (TIMSK0).

TC0 Register

Back to top

TC0 Timer/Counter Clock Sources

TC0 can be clocked by an internal or an external clock source. The clock source is selected by writing to the Clock Select (CS02:0) bits in the Timer/Counter Control Register (TCCR0B).

Back to top

Bits 2:0 – CS0n: Clock Select [n = 0..2]

The three Clock Select bits select the clock source to be used by the Timer/Counter.

CS02CS01CS00Description
000No Clock source (Timer stopped)
001clkio/1 (No prescaling)
010clkio/8 (From prescaler)
011clkio/64 (From prescaler)
100clkio/256 (From prescaler)
101clkio/1012 (From prescaler)
110External clock source on T0 pin (clock on falling edge)
111External clock source on T0 pin (clock on rising edge)

Back to top

TC0 Counter Unit

Depending on the mode of operation used, T0 is cleared, incremented, or decremented at each timer clock (clkT0). clkT0 can be generated from an external or internal clock source, selected by the Clock Select bits (CS0[2:0]).

The counting sequence is determined by the setting of the WGM01 and WGM00 bits located in the T0 Control Register A (TCCR0A) and the WGM02 bit located in the Timer/Counter Control Register B (TCCR0B).

Back to top

Bits 1:0 – WGM0n: Waveform Generation Mode [n = 1:0]

Combined with the WGM02 bit found in the TCCR0B Register, these bits control the counting sequence of the counter, the source for maximum (TOP) counter value, and what type of waveform generation to be used. Modes of operation supported by the Timer/Counter unit are: Normal mode (counter), Clear Timer on Compare Match (CTC) Mode, and two types of Pulse Width Modulation (PWM) modes.

Back to top

Table 1-2 Waveform Generation Mode Bit Description

ModeWGM2:0Mode of OperationTOPOCR0x UpdateTOV flag set on
00 0 0Normal0xFFImmediateMAX
10 0 1PWM Phase Correct0xFFTOPBOTTOM
20 1 0CTCOCRAImmediateMAX
30 1 1Fast PWM0xFFBOTTOMMAX
41 0 0Reserved~~~
51 0 1PWM Phase CorrectOCRATOPBOTTOM
61 1 0Reserved~~~
71 1 1Fast PWMOCRABOTTOMMAX

Note:
1. MAX = 0xFF
2. BOTTOM = 0x00

Back to top

Modes of Operation for TC0

The mode of operation determines the behavior of TC0 and the Output Compare pins. It is defined by the combination of the Waveform Generation mode bits and Compare Output mode bits in the Timer/Counter control Registers A and B (TCCR0B.WGMn2, TCCR0A.WGM01, TCCR0A.WGM00, and TCCR0A.COM0x[1:0]).

Available modes of operation for TC0 are:

  • Normal Mode
  • Clear Timer on Compare Match (CTC) Mode
  • Fast PWM Mode
  • Phase Correct PWM Mode

Back to top

Clear Timer on Compare Match Mode

In Clear Timer on Compare mode (WGM0[2:0]=0x2), the OCR0A Register is used to manipulate the counter resolution: the counter is cleared to ZERO when the counter value (TCNT0) matches the OCR0A. The OCR0A defines the top value for the counter, hence also its resolution.

The counter value (TCNT0) increases until a compare match occurs between TCNT0 and OCR0A, and then the counter (TCNT0) is cleared. An interrupt can be generated each time the counter value reaches the TOP value by setting the OCF0A Flag. If the interrupt is enabled, the interrupt handler routine can be used for updating the TOP value.

The waveform frequency is defined by the following equation:

Frequency Equation

N represents the prescaler factor (1, 8, 64, 256, or 1024).

Back to top

TC1, TC3, & TC4 - 16-bit Timer/Counters with PWM

The 16-bit Timer/Counter units allow accurate program execution timing (event management), wave generation, and signal timing measurement.

Back to top

Registers (TC1, TC3, TC4)

  • The Timer/Counter (TCNTn), Output Compare Registers (OCRA/B), and Input Capture Register (ICRn) are all 16-bit registers.
  • The Timer/Counter Control Registers (TCCRnA/B) are 8-bit registers and have no CPU access restrictions.
  • Interrupt requests (abbreviated to Int.Req. in the block diagram) signals are all visible in the Timer Interrupt Flag Register (TIFRn). All interrupts are individually masked with the Timer Interrupt Mask Register (TIMSKn).

Back to top

Timer/Counter Clock Sources (TC1, TC3, TC4)

The Timer/Counter can be clocked by an internal or an external clock source. The clock source is selected by the Clock Select logic which is controlled by the Clock Select bits in the timer/Counter control Register B (TCCRnB.CS[2:0]).

TCCRnB Register

Bits 2:0 – CS[2:0]: Clock Select [n = 0..2]
The three Clock Select bits select the clock source to be used by the Timer/Counter.

CS02CS01CS00Description
000No Clock source ( Timer stopped
001clkio/1 (No prescaling)
010clkio/8 (From prescaler)
011clkio/64 (From prescaler)
100clkio/256 (From prescaler)
101clkio/1012 (From prescaler)
110External clock source on T0 pin (clock on falling edge)
111External clock source on T0 pin (clock on rising edge)

Back to top

Counter Unit (TC1, TC3, TC4)

TC1, TC3, and TC4 are programmable 16-bit bi-directional counters.

Each 16-bit counter is mapped into two 8-bit I/O memory locations: Counter High (TCNTnH) containing the upper eight bits of the counter, and Counter Low (TCNTnL) containing the lower eight bits.

Depending on the selected mode of operation, the counter is cleared, incremented, or decremented at each timer clock (clkTn). The clock clkTn can be generated from an external or internal clock source, as selected by the Clock Select bits in the Timer/Counter Control Register B (TCCRnB.CS[2:0]).

The counting sequence is determined by the setting of the Waveform Generation mode bits in the Timer/Counter Control Registers A and B (TCCRnB.WGM[3:2] and TCCRnA.WGM[1:0]).

Back to top

Modes of Operation (TC1, TC3, TC4)

The mode of operation is determined by the combination of the Waveform Generation mode (WGM[3:0]) and Compare Output mode (TCCRnA.COMx[1:0]) bits.

Available modes of operation are:

  • Normal Mode
  • Clear Timer on Compare Match (CTC) Mode
  • Fast PWM Mode
  • Phase Correct PWM Mode
  • Phase and Frequency Correct PWM Mode

Back to top

Fast PWM Mode

The Fast Pulse Width Modulation or Fast PWM modes (modes 5, 6, 7, 14, and 15, WGM[3:0]= 0x5, 0x6, 0x7, 0xE, 0xF) provide a high frequency PWM waveform generation option. The Fast PWM differs from the other PWM options by its single-slope operation. The counter counts from BOTTOM to TOP then restarts from BOTTOM.

In Fast PWM mode the counter is incremented until the counter value matches either one of the fixed values 0x00FF, 0x01FF, or 0x03FF (WGM[3:0] = 0x5, 0x6, or 0x7), the value in ICRn (WGM[3:0]=0xE), or the value in OCRnA (WGM[3:0]=0xF). The counter is then cleared at the following timer clock cycle.

The PWM frequency for the output can be calculated by the following equation:

Frequency Equation

Note:
• The “n” in the register and bit names indicates the device number (n = 0 for Timer/Counter 0), and the “x” indicates Output Compare unit (A/B).
• N represents the prescale divider (1, 8, 64, 256, or 1024).

Back to top

TC2 - 8-bit Timer/Counter2 with PWM and Asynchronous Operation

Timer/Counter2 (TC2) is a general purpose, dual channel, 8-bit Timer/Counter module.

Back to top

TC2 Registers

The Timer/Counter (TCNT2) and Output Compare Register (OCR2A and OCR2B) are 8-bit registers. Interrupt request signals are all visible in the Timer Interrupt Flag Register (TIFR2). All interrupts are individually masked with the Timer Interrupt Mask Register (TIMSK2).

TC2 Register
Back to top

TC2 Clock Sources

TC2 can be clocked by an internal synchronous or an external asynchronous clock source:
The three Clock Select bits (CS2:CS0) select the clock source to be used by the Timer/Counter.

CS02CS01CS00Description
000No Clock source (Timer stopped)
001clkio/1 (No prescaling)
010clkio/8 (From prescaler)
011clkio/64 (From prescaler)
100clkio/256 (From prescaler)
101clkio/1012 (From prescaler)
110External clock source on T0 pin ( clock on falling edge)
111External clock source on T0 pin ( clock on rising edge)

Back to top

TC2 Counter Unit

Depending on the mode of operation used, the counter is cleared, incremented, or decremented at each timer clock (clkT2). clkT2 can be generated from an external or internal clock source, selected by the Clock Select bits (CS2[2:0]).
The counting sequence is determined by the setting of the WGM21 and WGM20 bits located in the Timer/Counter Control Register (TCCR2A) and the WGM22 bit located in the Timer/Counter Control Register B (TCCR2B).

Back to top

TC2 Modes of Operation

The mode of operation, i.e., the behavior of the Timer/Counter and the Output Compare pins, is defined by the combination of the Waveform Generation mode (WGM2[2:0]) and Compare Output mode (COM2x[1:0]) bits.
Available modes of operation are:

  • Normal Mode
  • Clear Timer on Compare Match (CTC) Mode
  • Fast PWM Mode
  • Phase Correct PWM Mode

Back to top

Normal Mode

In the Normal mode (WGM22:0 = 0) the counting direction is always up (incrementing), without having the counter cleared. The counter will roll over to 0c00 when it passes its maximum 8-bit value (TOP = 0xFF).

In normal operation, the Timer/Counter Overflow Flag (TOV2) will be set in the same timer clock cycle as the TCNT2 becomes zero. The TOV2 Flag, in this case, behaves like a ninth bit, except that it is only set, not cleared. However, combined with the timer overflow interrupt that automatically clears the TOV2 flag, the timer resolution can be increased by software. There are no special cases to consider in the Normal mode, a new counter value can be written any time.

Regardless of which mode is used the programmer needs to remember two things:

  1. The timer has to be started by selecting the clock source.
  2. If interrupts are used they must be enabled.

Back to top

Connection Diagram

The mEDBG chip controls the programming/debug interface, as well as supplying a 16 MHz clock when the Xplained board is connected via USB cable to a PC.

Connection Diagram
Back to top

​Procedure

Attach the ATmega328PB Xplained Mini board

Using a USB-A-male-to-Micro-B-male cable, attached the Xplained Mini to your computer. Start MPLAB® X IDE. If the board has been successfully enumerated, you should see the board image come up in Studio as shown:

Open MPLAB X.  ATmega328PB Xplained Mini board shows in window.

Back to top

Create a New Project

In MPLAB X IDE, select File > New Project

New Project Dialog Box

Choose Project

Select Microchip Embedded and then Standalone Project and then select Next.

Back to top

Select Device

Use the pulldown or type into the boxes to indicate the Family,  ATmega328PB, and Tool. Then Select Next.

Device Selection Dialog

Back to top

Select Compiler

Select the XC8 Compiler and then Next

Compiler Selection Dialog

Back to top

Name the Project

Choose a name for the project, browse to a location to save it, and select Finish

Project Name Dialog Box

Back to top

Create a New main.c file

Right-click on Source Files in the file explorer window and select New>avr-main.c and rename the File Name to main.  Then select Finish

New mail.c dialog box

Back to top

Add the Code

Delete the contents of the newly created main.c file. Copy and Paste the following code into it.

/*******************************************************************************
* File:  main.c
*
* Project:  8avr-mega-timer-example
*
* Description: 8-abit AVR Timer Example
*    
*    Main loop monitors the Counter. CLKPR is updated Every 10 sec
*    to dynamically change the SYS_CLK frequency.
*
*    CLKPR is toggled between div/1 and div/4 setting, which changes
*    the toggle from 100ms to 400mS respectively.
*
* Date:  19-Apr-2023
* Revision:
* Author:
*
* Hardware: ATmega328PB Xplained Mini
*
*    Clock:  16MHz (External - from EDBG IC)
*    LED0:  PB5
*    
*
* Fuses:  Programmed in MPLAB X
*
*    
*    Ext:  0xFC
*    High:  0xDF
*    Low:  0xC0 (EXT CLK, Fast VDD rise, CLKDIV = 1)
*
******************************************************************************/


//Necessary #include files
#include <avr/io.h>
#include <avr/interrupt.h>

//Set Fuses to configure the device
FUSES = {
 .low = 0xE0, // LOW {SUT_CKSEL=EXTCLK_6CK_14CK_65MS, CKOUT=CLEAR, CKDIV8=CLEAR}
 .high = 0xDF, // HIGH {BOOTRST=CLEAR, BOOTSZ=256W_3F00, EESAVE=CLEAR, WDTON=CLEAR, SPIEN=SET, DWEN=CLEAR, RSTDISBL=CLEAR}
 .extended = 0xFE, // EXTENDED {BODLEVEL=1V8, CFD=CFD_ENABLED}
};

LOCKBITS = 0xFF; // {LB=NO_LOCK, BLB0=NO_LOCK, BLB1=NO_LOCK}

//Initialize Variables
int counter;
int MyTimerConstant;
int duty_cycle;
int counterTimer2;
int MyTimer2Constant;


//Modification 1: Paste void init_TC0(void) code here


//Modification 1: Paste ISR (TIMER0_COMPA_vect) code here


//Paste void init_TC1_pwm(void) code here


//Paste Copy ISR (TIMER1_COMPA_vector)code here   



//Main loop:  Both code modifications require pasting code to replace the main
int main(void)

{
   
   while (1)
    {
       //main loop      
    }
   
}

//Modification 2:  Paste ISR (TIMER1_COMPA_vect) Here

Back to top

Modification 1 - Blinking a LED using TC0

In this example, Timer 0 blinks the LED connected to PB5 every 32 ms.

Modify the main function by adding the following code:

int main(void)

{
   set RB5 as output
    DDRB |= 1 << DDRB5;

    call TMR0 initialization function
    init_TC0();

   enable interrupt
    sei();

   while (1)
    {
        main loop
    }
}

Create the function init_TC0 () in main.c. Add the following code:

void init_TC0(void)
{

   // Set the Timer Mode to CTC
   TCCR0A |= (1 << WGM01);

   // Set the value that you want to count to
   OCR0A = 0xF9; //249

   //Set the ISR COMPA vect
   TIMSK0 |= (1 << OCIE0A);    

   // set prescaler to 1024 and start the timer
   TCCR0B |= (1 << CS00) | (1 << CS02);  
}

The preceding code does the following:

  • Configures Timer 0 in CTC mode by setting the corresponding WGM bit in TCCR0A register;

  • Sets the TOP value in the OCR0A register calculated using the equation 1 to blink the LED at 30 kHz;

  • Enables the Timer Interrupt;

  • Sets the pre-scaler to 1024 by configuring the CS00 and CS02 bits in TCCR0B register;]

Back to top

Add the interrupt service routine to main.c:
ISR (TIMER0_COMPA_vect)
{
   //event to be executed every 32ms*MyTimerConstant
   counter++;

   if (counter == MyTimerConstant) {
        counter = 0;
        PORTB ^= 1 << PORTB5; //toggle LED on PORTB5
   }
}

Back to top

Program the Device

At the top of the MPLAB X IDE, select the Make and Program device button

Program the Device

The use of the constant MyTimerConstant and the variable counter is optional. If used, changing the value of MyTimer Constant will alter the time it takes the LED to blink.

Back to top

Modification 2 - Using TC1 in PWM mode to dim the LED

This example uses TC1 to generate a PWM signal which is fed through an I/O pin to drive an LED. Changing the PWM duty-cycle will result in a change in the brightness of the LED.

Modify the main function by adding the following code:

int main(void)

{
   //set direction of pin PB1 set as output
   DDRB |= 1 << DDRB1;

    init_TC1_pwm();

   //enable global interrupts
   sei();

   while (1)
    {
       //main loop
   }
}

For configuring the direction bit of pin PB1, write the DDB1 bit to logic 1 in the DDRB register. On the ATmega328PB Xplained Mini Board, LED is connected to PB5 and PWM is generated on PB1. To view the LED dimming, connect a wire from PB5 to PB1 on the ATmega328PB Xplained Mini Board, as shown below.

Back to top

Modification 2 - Blinking an LED using TC2

Create the init_TC1_pwm () function before the main loop with the following code:

void init_TC1_pwm(void)
{
   //clear OCnA on compare match, BOTTOM (non-inverting mode)
   TCCR1A = (1 << COM1A1);

   //the counting sequence is determined by the setting of the waveform generation mode bits in Timer
   TCCR1A |= (1 << WGM10);
    TCCR1B |= (1 << WGM12);

   //256 presclaer clock select bits
   TCCR1B |= (0 << CS10) | (1 << CS12);

   //enable interrupts
   TIMSK0 |= (1 << OCIE1A);
}

init_TC!_PWM() performs the following

  • Sets the bits COMA1=1 and COMA0=0 (non-inverting mode from datasheet table Compare Output Mode, Fast PWM in the TCCR1A register;
  • Configures Bits 1:0 – WGM[1:0]:Waveform Generation Mode accordingly for Fast PWM, 8-bit mode;
  • Verifies the configuration for the clock source and prescaler to be used by the Timer/Counter, which decides the frequency of the PWM. Internal clock source divided by 256 is configured by writing to the CS10 and CS12 bits in TCCR1B register;
  • Enables the Timer Interrupt;

Back to top

Modification 2

Add the ISR function after the main loop to execute dimming LED event:

ISR (TIMER1_COMPA_vect)  // timer1 interrupt
{
    duty_cycle--;
   if (duty_cycle == 0) {
        duty_cycle = 0xFF;
    }
    OCR1A = duty_cycle;

The register OC1RA decides the duty cycle of the PWM. To dim the LED gradually decrease the duty cycle.

Back to top

Program the Device

At the top of the MPLAB X IDE, select the Make and Program device button

Program the Device

Back to top

Modification 2 Blinking an LED using TC2

For this example, Timer 2 (TC2) is configured to blink the LED connected to PB5 at a period of 3 seconds.

Modify the main function by adding the following code:

int main(void)
{
   //set direction of PB5 as output
   DDRB |= 1 << DDRB5;

   /* Timer clock = I/O clock / 1024 */
    TCCR2B = (1 << CS22) | (1 << CS20) | (1 << CS21);

   /* Clear overflow flag */
    TIFR2 = 1 << TOV2;

   /* Enable Overflow Interrupt */
    TIMSK2 = 1 << TOIE2;

   // enable global interrupts
   sei();

   while (1)
    {
       // Main loop
   }
}
  • Configures the direction bit of pin PB5, write the DDB5 bit to logic 1 in the DDRB register;
  • Sets the prescaler to 1024 by configuring the CS20, CS21 and CS22 bits in TCCR2B register;
  • Clears Overflow flag - TOV2 is cleared by writing a logic one to the flag.
  • Enables global interrupts by calling sei();

Back to top

Add the interrupt service routine to main.c

Enable the Overflow Timer Interrupt;

Add the ISR function after the main loop to execute blinking LED event:

ISR (TIMER0_COMPA_vect)
{
   //event to be executed every 32ms*MyTimerConstant
   counter++;

   if (counter == MyTimerConstant) {
        counter = 0;
        PORTB ^= 1 << PORTB5; //toggle LED on PORTB5
   }
}

Set the PORTB register to blink the LED 

The use of the constant MyTimerConstant and the variable counter is optional. If used, changing the value of MyTimer Constant will alter the time it takes the LED to blink.

Back to top

Program the Device

At the top of the MPLAB X IDE, select the Make and Program device button

Program the Device

Back to top