VIDEO TUTORIAL ON TIMER1

ATMEGA 16/32 has 3 TIMERS —TIMER0 8 bit , TIMER 1 (16 Bit) , Timer 2 (8 bit).

In the previous post we tested with TIMER0 .

This post is related to TIMER 1 , particularly the INTERRUPT functions.

As we know Timers work by incrementing a counter variable called counter register. The counter register can count to a certain value, depending on its size. The timer increments this counter one step at a time until it reaches its maximum value, at which point the counter overflows, and resets back to zero.

Since Timer1 is 16 bits, it can hold a maximum value of (2^16 – 1), or 65535.

In order to increment the counter value at regular intervals, the timer must have access to a clock source.  The clock source generates a consistent repeating signal.  Every time the timer detects this signal, it increases its counter by one.

If clock source is 8MHz we’ll go through one clock cycle every 1 / 8000000 seconds, or 0.000000125 secs or 0.125 usec . That means Timer1 Counter takes 65535 * 0.000000125 = 0.0082

timer counts will elapse in 0.0082 secs

So , if we need a one second delay ( 1000msec) , 1000/0.0082 = 121951 which obviously higher than 65535 which is the highest count for TIMER1.

Here comes the need of PRESCALER

Clock source can be divided by 8 , 64, 256 , 1024 by setting the bits 0:2 of TCCR1B

After counting 65535 , The timer normally sets a flag (OverFlow Flag) bit to let you know an overflow has occurred.

In case of TIMER1 , COUNTER Register is made of 2 , 8 bit Registers TCCR1A & TCCR1B put together forms a 16 bit Register

You can check this flag manually, or you can also have the timer trigger an interrupt as soon as the flag is set. You can specify an Interrupt Service Routine (ISR) to run code of your choice when the timer overflows. The ISR will reset the overflow flag behind the scenes,

Following table shows the list of REGISTERs associated with TIMER1  TCCR1 is actually composed of two registers TCCR1A & TCCR1B

TCCR1A controls the compare modes & the pulse width modulation modes

TCCR1B controls the prescaler & input multiplexer & input capture modes

TCCR1B COUNTER SELECT bits 0:2 control the input to Timer1 .These 3 select bits provide clock signals that are absolutely identical to those of Timer0 When the timer counts past 65535 (0xFFFF) , it sets the Flag TOV1 (bit 2 of TIFR ) register.The registers TIFR & TIMSK are common for all 3 timers.

When Compare register is used , the OCF1B or OCF1A flag is set according to the channel (A or B) used for Compare operation. Instead of manually checking the Flags in TIFR , Interrupts can be used to trigger ISR automatically when the particular Interrupt bit is Enabled in TIMSK register.

As seen below bits 2 to 5 are for TIMER1

If TOIE1 bit is enabled , on Timer 1 overflow , the corresponding Interrupt Service Routine ISR is called automatically & the code inside ISR is executed Following is the list of Vector table.You have to use the correct VECTOR NAME in the ISR Function From above table you can see RESET is on the top of table & is unmaskable ,having the highest priority

if Timer overflow interrupt TOIE1 is enabled , You need to use the ISR function Vector 9 in table

First example code is using OVERFLOW INTERRUPT.

Using this interrupt we blink an LED connected to PD6 – pin 20

We use the external crystal 8MHZ as clock source. ( High FUSE 0XD9 , LOW Fuse 0XFD)

To start with include the 2 Header files at the top of code.

Inside the Main Function PD6 pin is made as OUTPUT , as we’ve connected an LED at pin20.

DDRD |= (1<<6);

The prescaler we’ve selected is 256 .To apply this we need to set the bit CS12 in the TCCR1B register.In Timer1 the control register is of 2 parts TCCR1A & TCCR1B . Prescaler select bits are found in TCCR1B. TCCR1B |= (1<<CS12); // prescaler 256 selected , clock is now 8000000/256= 31250Hz

Next load the TCNT1 counter with the calculated value

TCNT1 = 49910;

Calculation is as follows :

Suppose we want to blink the LED at at the rate 2HZ , i.e., 0.5sec ( 500 milli secs) interval

We selected  prescaler 256

The clock frequency becomes 8000000 / 256 = 31250 Hz

Time for each Tick is 1 / 31250 = 0.000032 sec = 32usec

For 500 msec to elapse the count is 500 / 0.032 = 15625

Timer 1 counts from 0 to  65535 & overflows.

65535 – 15625 = 49910

So if you preload the counter with 49910 , the counter starts at 49910 & counts up to 65535 elapsing 15625 count & creating 500 msec delay

You can also use the Timer Calculator from

https://www.easycalculation.com/engineering/electrical/avr-timer-calculator.php

Next enable the Timer OverFlow Interrupt TOIE1 in the TIMSK Register

TIMSK |= (1<<TOIE1); Enable the Global Interrupt using the command

sei();

Now we’ve to write the code for ISR with correct vector name TIMER1_OVF_vect

Inside the ISR Function we toggle the LED at PD6 & THEN AGAIN LOAD THE TCNT1 Register with the calcuated value.This is important as otherwise the TCNT1 will start counting from 0.

ISR (TIMER1_OVF_vect)

{

PORTD ^= (1<<6); // toggle LED

TCNT1 = 49910; // again load counter with calculated value

}

Complete code is here :

——————————

#include <avr/io.h>

#include <avr/interrupt.h>

int main (void)

{

DDRD |= (1<<6); // PD6 is Output

TCCR1B |= (1<<CS12); // prescaler 256 selected , clock is now 8000000/256= 31250Hz

TCNT1 = 49910; // load counter with calculated value

TIMSK |= (1<<TOIE1); // enable Timer overflow interrupt

sei();

while (1) {}

ISR (TIMER1_OVF_vect)

{

PORTD ^= (1<<6); // toggle LED

TCNT1 = 49910; // again load counter with calculated value

}

————————————-

Compile the code as we’ve done in previous examples & upload the HEX code to see the LED blinking at 500 msec delay.

You can also use the code creator for AVR from :

ONLINE AVR CODE creator

http://www.dioda.ro/avrwiz/index.html

CLEAR TIMER ON COMPARE MATCH CTC MODE

In previous above example we loaded the Counter with a calculated value & then waited for the counter to Overflow & used the Overflow interrupt to execute TIMER1_OVF_vect ISR

In compare mode, there is one compare register, where we can set value to compare with the Timer / counter register value. Once the compare value matches with timer / counter register value, compare match occurs. This compare match event can be used for waveform generation.

The Timer counts up until the value of the TCNT1 (Timer / counter register) register becomes equal to the content of OCRx (Compare register). As soon as TCNT1 becomes equal to the OCRx, compare match occurs and then timer will get cleared and OCFx flag will get set.

Hence, this comparison takes place  inside the AVR CPU hardware . Once the counts value becomes equal to the compare value, a flag in the status register is set and the timer is reset automatically.  Hence the name – CTC – Clear Timer on Compare Let us explore the code :

First we enable the CTC mode by setting the bit WGM12 bit of TCCR1B.

Prescaler selected is 256 by setting CS12 bit in TCCR1B

TCCR1B |= (1 << WGM12) | (1 << CS12); The WGM bits are found in both the registers.But we need to set only the WGM12 bit to enable CTC. This bit is found inside TCCR1B Register. So no need to set the TCCR1A register. We then initialize the TCNT1 value to start from 0.

When the TCNT1 value reaches a compare value , an interrupt is enabled.

This compare value is loaded into a  OCR1 x Register.

The Output Compare Register 1A – OCR1A and the Output Compare Register 1B – OCR1B are utilized for this purpose.

Since the compare value will be a 16-bit value (in between 0 and 65535), OCR1A and OCR1B are 16-bit registers. In ATMEGA16/32, there are two CTC channels – A and B. We can use any one of them or both. Let’s use OCR1A.

Let us load the Compare value as

OCR1A = 31250 ;

Calculation is as follows :

Clock is 8 MHz & we use a prescaler of 256

Now the clock to Timer1 is 8000000/256 = 31250 Hz

Time period is reciprocal of freq = 1/31250 = 0.000032 usec or 0.032 milli sec

To generate a delay of 500 ms 500ms/ 0.032 msec = 15625 counts

To generate 1 sec delay ( 1000millisec) 1000/0.032 = 31250

Now enable the OCIE1A Interrupt in TIMSK Register TIMSK |= (1 << OCIE1A);

Whenever a match occurs (TCNT1 becomes equal to OCR1A ), an interrupt is fired (as OCIE1A is set) and the OCF1A flag is set (we do not check this flag manually, as we use interrupt).

Now  we need an Interrupt Service Routine (ISR) to attend to the interrupt.

Executing the ISR clears the OCF1A flag bit automatically and the timer value (TCNT1) is reset.

##### The ISR is defined as follows with the correct vector name TIMER1_COMPA_vect

ISR (TIMER1_COMPA_vect)

{

PORTD ^= (1 << 6);

}

Complete code is as below :

———————————————-

#include <avr/io.h>

#include <avr/interrupt.h>

void timer1_init()

{

TCCR1B |= (1 << WGM12) | (1 << CS12);

TCNT1 = 0;

OCR1A = 31250;

TIMSK |= (1 << OCIE1A);

sei();

}

ISR (TIMER1_COMPA_vect)

{

PORTD ^= (1 << 6);

}

int main(void)

{

DDRD |= (1 << 6);

timer1_init();

while(1)  {}

}

———————————-

Compile & upload the HEX file to see the LED blinking at 1 sec interval

#### Hardware CTC Mode

Without Interrupt enable you can toggle or generate waveform on certain predefined OC pins which is called Hardware CTC , Output Compare

PB3, PD4, PD5 and PD7 represent the OUTPUT COMPARE pins

OC0 , OC1A, OC1B , OC2

These are the Output Compare pins of TIMER0, TIMER1 and TIMER2 respectively. Timer/Counter1 Control Register A

The TCCR1A Register bits 4 to 7 decide the Compare output mode of unit  A or B

These bits control the behaviour of the Output Compare (OC) pins. The behaviour changes depending upon the following modes:

· Non-PWM mode (normal / CTC mode)

· Fast PWM mode

· Phase Correct / Phase & Frequency Correct PWM mode

.  CTC Mode   Simply set the timer1 to the mode 01 as seen in table above.

Whenever a compare match occurs, the OC1A pin is automatically toggled.

Only PD5 or PD4 (OC1A or OC1B) can be controlled this way, which means that we should connect the LED to PD5 (since we are using channel A

————————————-

#include <avr/io.h>

#include <avr/interrupt.h>

void timer1_init()

{

TCCR1B |= (1 << WGM12)|(1 << CS11)|(1 << CS10);

// set up timer OC1A pin in toggle mode

TCCR1A |= (1 << COM1A0);

TCNT1 = 0;

// initialize compare value

OCR1A = 31250;

}

int main(void)

{

DDRD |= (1 << 5);

timer1_init();

while(1) {}

}

——————————————-