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) {}
}
——————————————-
Thank you for your contributions. I have learned much from several of your videos. Keep up the good work!
Craig Larson