Program 16 bit AVR timer with WinAVR

AVR 16 bit timer is more advanced timer than 8 bit timer.  It has more features and this allows more accurate program execution timing. 16 bit timer is used when precise signal generation or signal timing measurement needed. As 8 bit timer counter can calculate up to 225 counts the 16 bit timer counter maximum value may reach 65535. In AVR microcontrollers 16 bit timer is Timer1. It contains a 16 bit input capture register (ICR1) and two 16 bit output compare registers (OCR1A and OCR1B). Of course the timer counters register (TCNT1) which is 16 bit long. When programming is ASM language there is special procedure for accessing it (refer to datasheet). While in C language it is done automatically we won’t get to deep into this. Timer1 is controlled by two timer counter control registers (TCCR1A/B). Signals are visible at timer interrupt flag register (TIFR) and interrupts can be individually masked in timer interrupt mask register (TIMSK).

Few words about prescaler. As timer counter is a binary counter it has a prescaler like other timers in AVR microcontrollers. Prescaler may be selected in TCCR1B with bits CS12, CS11 and CS10 like in 8 bit timers.

Lets us go through timer1 modes to clear things out.

Input capture mode

This mode is usually used for measuring of time interval between two events like measuring pulse width. This is done by capturing time event at the beginning and at the beginning of the event. They are subtracted from each other to find how long event lasted. For this task input capture register is used ICR1. Signal is captured using input capture pin (ICP). In a TCCR1B bit ICES1. Input capture mode has also noise canceling feature. Bu setting bit ICNC1 in TCCR1B register will activate this. Noise canceller helps to avoid spikes in the input. It simply waits for low or high signal for four clock cycles.

When input capture has occurred the interrupt is generated, so the interrupt service routine has to determine that was first or second capture and store ICR1 data to some memory because after second capture data will be overwritten.

Let’s say wee want to measure positive signal width using Atmega8 microcontroller.

 

#include <avr\io.h>

#include <avr\interrupt.h>

#include <avr\iom8.h>

#define ICP PINB0

//define ovrflow counter

uint16_t ov_counter;

//define times for start and end of signal

uint16_t rising, falling;

//define overall counts

uint32_t counts;

//overflow counter interrupts service routine

ISR(TIMER1_OVF_vect){

  ov_counter++;

}

//Timer1 capture interrupt service subroutine

ISR(TIMER1_CAPT_vect){

/*This subroutine checks was it start of pulse (rising edge)

or was it end (fallingedge)and performs required operations*/

if (ICP) //if high level

            {

            //save start time

            rising=ICR1;

            //set to trigger on falling edge

            TCCR1B=TCCR1B&0xBF;

            //reset overflow counter

            ov_counter=0;

   }

else

            {

            //save falling time

            falling=ICR1;

            //rising edge triggers next

            TCCR1B=TCCR1B|0x40;

            counts=(uint32_t)falling-(uint32_t)rising+(uint32_t)ov_counter;

            /*you can convert coutns to seconds and send to LCD*/

            }

}

int main(void) {

//enable overflow and input capture interrupts

TIMSK=0x24;

/*Noise canceller, without prescaler, rising edge*/

TCCR1B=0xC1;

sei();

    for (;;) {

/* loop forever timer does the job*/

 

    }

}

 

 

Timer output compare mode

Output compare mode is like anti-input capture mode. This mode is able to generate varying frequency and symmetry signals. This may be used to generate music sounds and so on.

Output compare mode is controlled by TCCR1A register. It can control two pins of microcontroller OC1A and OC1B. They may be left unaffected, toggled, set or cleared. Regarding to bits settings in TCCR1A register. Output compare mode on compare match can generate an interrupt. Interrupt service routine may be used to calculate the OCR1A value.

There are several of output compare modes (selecting bits WGM13:0 in TCCR1A register):

  • Normal mode (WGM13:0=0). Is used to generate interrupts as some given time also as overflow interrupts.
  • Clear timer on compare match (WGM13:0=4 or 12). The OCR1A or ICR1 Register are used to control counter resolution. In CTC mode the counter is cleared to zero when the counter value (TCNT1) matches either the OCR1A (WGM13:0 = 4) or the ICR1 (WGM13:0 = 12). The OCR1A or ICR1 define the top value for the counter, hence also its resolution. This mode allows greater control of the Compare Match output frequency.

 

#include <avr\io.h>

#include <avr\interrupt.h>

#include <avr\iom8.h>

#define OCP PINB1

/*This example demonstrates how 1kHz signal

can be generated using timer and compare match interrupt

if F_CPU=1MHz, then 1 clk is 1us. For 1kHz signal

there is 1000clk=1000us. For toggling ponts = 500clk

*/

//Output compare ISR

ISR(TIMER1_COMPA_vect){

  OCR1A+=500;

}

int main(void) {

//Set PORTB1 pin as output

DDRB=(1<<OCP);

//Output compare toggles OC1A pin

TCCR1A=0x40;

//start timer without prescaler

TCCR1B=0x01;

//enable output compare interrupt for OCR1A

TIMSK=0x10;

 

sei();

    for (;;) {

/* loop forever timer does the job*/

 

    }

}

 

results:

 

  • Fast PWM mode (WGM13:0=5, 6, 7, 14 or 15). This mode is used to provide high frequency PWM. It’s a single slope generation. The PWM resolution for fast PWM can be fixed to 8-, 9-, or 10-bit, or defined by either ICR1 or OCR1A. The minimum resolution allowed is 2-bit (ICR1 or OCR1A set to 0x0003), and the maximum resolution is 16-bit (ICR1 or OCR1A set to MAX):

 Phase correct PWM mode (WGM13:0=1, 2, 3, 10 or 11). It is dual slope mode. Resolution can be selected between 8, 9, 10 bits or defined by ICR1 or OCR1A. The output is phase correct, but unsymmetrical:

 

  • Phase and frequency correct PWM mode (WGM13:0=8 or 9). This PWM mode generates phase correct PWM and correct frequency because of symmetrical output:



Example bellow shows how correct phase and frequency PWM duty cycle can be controlled using two buttons connected to PIND0 and PIND1:

 

#include <avr\io.h>

#include <avr\iom8.h>

int main(void) {

//Port D pins as input

DDRD=0x00;

//Enable internal pull ups

PORTD=0xFF;

//Set PORTB1 pin as output

DDRB=0xFF;

//

OCR1A=76;

//Output compare OC1A 8 bit non inverted PWM

TCCR1A=0x91;

//start timer without prescaler

TCCR1B=0x01;

    for (;;) {

if(bit_is_clear(PIND, 0))           {

//increase duty cycle

             OCR1A+=10;

loop_until_bit_is_set(PIND, 0);

            }

if(bit_is_clear(PIND, 1))           {

//decease duty cycle

            OCR1A-=10;

loop_until_bit_is_set(PIND, 1);

            }

    }

}

Download example projects ready to run with VMLAB simulation tools from here

Comments

Hi, for input capture:

- The code shows the interrupt being called for both rising and falling, even though it is configured for Rising Edge..
- Why use uint32_t for a 16bit timer value?

Actually edge is changed insie interrupt. Once ISR is called on rising edge, next will be on falling edge"

            //set to trigger on falling edge

            TCCR1B=TCCR1B&0xBF;

uint32_t is used in case pulse is longer than timer overflows. so to be sure there are 32 bit value used. Anyway dont mind

counts=(uint32_t)falling-(uint32_t)rising+(uint32_t)ov_counter;

the counts value is calculated wrongly. should be like:

counts=((uint32_t)falling +(uint32_t)(ov_counter*0xFFFF))-(uint32_t)rising;

when i put below line it didnt show the  correct value in hz like whe i have send 20k it shows only 67 on display it should be 20000 plz replycounts=((uint32_t)falling +(uint32_t)(ov_counter*0xFFFF))-(uint32_t)rising;

how can you convert this counts to seconds

Just use the clocking rate of your timer and divide counts by counts per seconds.

In the event that you aer using a timer with a nice frequency like 1 Mhz you get your count in us. else you will just have to divide. unit analysis => counts divided by (counts / s ) = s

There is a bug in example of ICP mode. Configuring uP for ICP mode disables the port PIN function (PINB0 always FALSE).

Just a quick FYI, It is advisable never to use avr/io*.h in your file. Just use <avr/io.h> and the computer will pick up the correct ones.

how can i convert this count in freq..what is the formula  i have to use. plz reply