You are on page 1of 4

Timer Interrupts in C

The Atmel ATmega16 has three Timer/Counters:

Timer/Counter0 is a general purpose, single channel, 8-bit Timer/Counter module.


Timer/Counter1 is a 16-bit general purpose Timer/Counter also incorporates
wave generation.
Timer/Counter2 is an 8-bit Timer/Counter with PWM and Asynchronous
Operation. This is a general purpose, single channel, 8-bit Timer/Counter module.
Difference between this unit and the previous two is that it supports clocking from
External 32 kHz Watch Crystal Independent of the I/O Clock for Real Time
Clock applications. e.g if you want a stopwatch program or wish to display (store)
the date and time.

We are originally interested in using Timer/Counter0 and the rest of this handout will
refer to Timer/Counter0.

All interrupts are individually masked with the Timer Interrupt Mask register (TIMSK).
The Timer/Counter can be clocked internally, via the prescaler, or by an external clock
source on the T0 pin. The clock source can be selected in the STK500 ISP (In System
Programming) window by selecting Fuses and then the required source. For this
particular practical I would suggest:

INT RC Osc 1MHz: Start up time = 6CK + 64ms

This gives a clock rate of 1MHz which means that each clock pulse period is 1us. (i)

Time per clock cycle = 1/clock frequency

There are two ways to determine the count value one is to use an 8-bit comparator
which continuously compares TCNT0 with the Output Compare Register (OCR0).
Whenever TCNT0 equals OCR0, the comparator signals a match and generates an
interrupt. The other, and the method we will use, is to allow the value stored in TCCR0 to
count up to 255 and then reset to zero this will generate a timer overflow interrupt
(TOIE0).

To program this timer we need to program TCCR0. As far as we are concerned all we
need to worry about are the 3 least significant bits, which set a prescalar. The prescalar
divides the clock by 8, 64, 256 or 1024 depending upon the values entered.

TCCR0
FOC0 WGM00 COM01 COM00 WGM01 CS02 CS01 CS00
Address 0x33
The values for TCCR0 can be determined from Table 1.

CS02 CS01 CS00 Description

1
0 0 0 No clock source (Timer/Counter stopped).
0 0 1 clkI/O/(No prescaling)
0 1 0 clkI/O/8 (From prescaler)
0 1 1 clkI/O/64 (From prescaler)
1 0 0 clkI/O/256 (From prescaler)
1 0 1 clkI/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.
Table 1

As far as the count is concerned, we just need to enter the value into TCNT0. However
we need to calculate the numbers based upon the required delay.

Example
We require a delay of 250ms. This means that the timer will generate an interrupt every
second.

Answer
Given that each clock pulse period is 1 x 10-6 seconds (1us which was stated in (i))

required time = clock period x prescaler x TCCR0 count

or

(required time/ clock period) / prescaler = TCCR0 count

(250 x 10-3/1 x 10-6 ) / prescaler= 250,000

As the maximum prescaler value is 1024 then 250,000/1024 = 244 to nearest


whole number.

As the timer counts up then we need to load TCCR0 with 255 -244 = 11 or in
hex (0x0b).

The other register we need to program is the timer mask register (TIMSK).

OCIE2 TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0


TIMSK
Address 0x39
The interrupt we wish to enable is bit 0 TOIE0: The Timer/Counter0 Overflow
Interrupt Enable.

2
The only other thing that is required before the interrupt will work is to enable the Global
interrupts using the sei instruction. Alternatively we could have selected bit 7 in the
SREG (address 0x3f)

I T H S V N Z C
SREG
Address 0x3F
This can also be enabled using sei()

Page 4 shows a C program using the timer to flash the leds on and off at about 1 second
intervals.

Note the line SIGNAL(SIG_OVERFLOW0) will load the vector table with the
correct address of the interrupt handler.
The ^ sign is an exculsive OR.

XOR Truth table
Inputs Output
0 0 0
0 1 1
1 0 1
1 1 0

Hence toggle = toggle ^ 0xff; will cause the LEDs to all change value (from
0s to 1s and vice versa), on each pass.

#include <avr/interrupt.h> and #include <avr/signal.h> are the


header files and contain the sei() declaration which is the global interrupt enable.

The comments should therefore make the rest of the program on page 4 understandable.

3
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

int volatile count;


char toggle;

void init(void)
{
DDRA = 0xff;
TCNT0 = 0x00;//Count = 0
TCCR0 = 0x05;// Prescaler = 1024
TIMSK = 0x01;// Enable tomer overflow 0 interrupt
sei();// Global interrupt enable
}

SIGNAL(SIG_OVERFLOW0)
{
if (count < 5)
{
count++;
else
{
count = 0;
toggle = toggle ^ 0xff;
PORTA = toggle;

}
TCNT0 = 0;;
}

main()
{
init();
count = 0;
toggle = 0;
while(1);

You might also like