Timers
Timers
Review of C Programming
▪ Examples include:
❑ recording the time when an event occurs
▪ Input Capture:
❑ Input signal is connected to a pin, called input capture, of the timer
❑ When an event (rising edge, falling edge, or change) occurs on this pin, the current
timer value is automatically stored in a register
▪ Output Compare:
❑ A timer typically has a pin, called output compare
❑ When the timer reaches a preset value, the output compare pin can be
automatically changed to logic 0 or logic 1
Overview of Timers in ATmega16
▪ When the internal system clock is used, a pre-scaler can be applied to make
the timer count at a slower rate
▪ Example:
❑ Consider a system clock of 1Mhz (i.e., 1μs per cycle)
▪ 16-bit counter
▪ can trigger an input capture interrupt when an event occurs on the input capture pin:
❑ timer value is stored automatically in a register
▪ can trigger an output compare match interrupt when timer reaches a preset value:
❑ There are two independent output compare channels A and B
Timer 1: Block diagram
1) Timer/Counter 1
❑ TCNT1
❑ 16-bit register that stores the current value of the timer
4) Interrupt registers
❑ TIMSK to enable timer interrupts
❑ TIFR to monitor status of timer interrupts
7 6 5 4 3 2 1 0
COM1A1 COM1A0 COM1B1 COM1B0 FOC1A FOC1B WGM11 WGM10
Specify Waveform Generation Mode used with
WGM13, WGM12
WGM13 ... WGM10 = 0000 for normal mode.
7 6 5 4 3 2 1 0
ICNC1 ICES1 - WGM13 WGM12 CS12 CS11 CS10
7 6 5 4 3 2 1 0
OCIE2 TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0
For Timer 0
For Timer 2
Timer/Counter Interrupt Flag Register (TIFR)
7 6 5 4 3 2 1 0
OCF2 TOV2 ICF1 OCF1A OCF1B TOV1 OCF0 TOV0
For Timer 0
For Timer 2
▪ This register has flags that indicate when a timer interrupt occurs
▪ It is not often used in ATmega16 programs
Lecture 4’s sequence
Write a C program for ATmega16 to toggle PORTB every 2 seconds. It should use Timer 1
overflow interrupt to create delays of 2 seconds each.
▪ Analysis
❑ Internal system clock: 1MHz
❑ With no pre-scaler, Timer 1 increments every 1 μs
❑ Timer 1 is 16-bit counter, so it will overflow every 216 μs
❑ For a 2s delay, we need Timer 1 to overflow for 2s/216 μs = ~31 times
▪ Implementation
❑ Write code to enable Timer 1 overflow interrupt
❑ Use ISR to count the number of overflows
❑ When the number of overflows is 31, invert port B
Example 1: Creating an accurate delay
#include <avr/io.h>
#include <avr/interrupt.h> 1
volatile int overflow_count; // declare a global variable
ISR(TIMER1_OVF_vect) { // ISR for Timer1 overflow interrupt
overflow_count++; // increment overflow count
if (overflow_count >= 31) { // when 2s has passed
overflow_count = 0; // start new count 2
PORTB = ~PORTB; // invert port B
}
}
int main(void) {
DDRB = 0xFF; // set port B for output
PORTB = 0x00; // initial value of PORTB
overflow_count = 0; // initialize overflow count
TCNT1 = 0x00; // initial value of counter register
TCCR1A = 0b00000000; // normal mode 4
TCCR1B = 0b00000001; // no pre-scaler, internal clock
TIMSK = 0b00000100; // enable Timer 1 overflow interrupt 3
sei(); // enable interrupt subsystem globally 5
while (1){;} // infinite loop
return 0;
}
Example 2: Measuring elapsed time
Timer Overflows
n=0 TCNT1
TCNT1 = 0
1 2 n
time interval t
start at time t1 stop at time t2
Example 2: Measuring elapsed time
▪ Approach
❑ Clear Timer 1 when the custom code starts
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
volatile uint32_t n; // uint32_t is unsigned 32-bit integer data type
ISR(TIMER1_OVF_vect) { // handler for Timer1 overflow interrupt
n++; // increment overflow count
}
int main(void) {
int i, j;
uint32_t elapse_time; // uint32_t is unsigned 32-bit integer data type
TCCR1A = 0b00000000; // normal mode
TCCR1B = 0b00000001; // no pre-scaler, internal clock
TIMSK = 0b00000100; // enable Timer 1 overflow interrupt
n = 0; // reset n
TCNT1 = 0; // reset Timer 1
sei(); // enable interrupt subsystem globally
Use Timer 1 input capture interrupt to measure the period of a square wave.
▪ Analysis:
❑ The period of a square wave is equal the time difference between two consecutive rising edges
▪ Assumption: The input signal has a high frequency; hence timer overflow can
be ignored
▪ Implementation:
❑ Select timer operations: normal, no pre-scaler, internal clock 1MHz, noise
canceller enabled, input capture for rising edges
TCCR1A = 0b00000000;
TCCR1B = 0b11000001;
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h> // uint32_t is unsigned 32-bit integer data type
uint16_t period; // uint16_t is unsigned 16-bit integer
int main(void) {
DDRB = 0xFF; // set port B for output
TCCR1A = 0b00000000; // normal mode
TCCR1B = 0b11000001; // no pre-scaler, rising edge, noise canceller
TIMSK = 0b00100000; // enable Timer 1 input capture interrupt
sei(); // enable interrupt subsystem globally
while (1){ // infinite loop
PORTB = ~(period >> 8); // top 8-bit to PORT B: LED on=0, off=1
}
return 0;
}