Embedded Systems: Engr. Rashid Farid Chishti
Embedded Systems: Engr. Rashid Farid Chishti
Embedded Systems: Engr. Rashid Farid Chishti
Oscillator 0
Counter register
COUT
External 1
source
Flag
Counter/Timer
A Generic Timer / Counter
Time Delay Generation
Generate a 1 sec delay.
Event Counting
Count number of revolution of a wheel
Wave-form generating
Piano Note Frequencies
Capturing
Measuring Period
TCCR2A TCCR2B
OCR1AH OCR1AL TCNT1H TCNT1L OCR1BH OCR1BL
OCR2A TCNT2 OCR2B
TOV1
TOV2
= = = =
OCF1A OCF1B OCF2A OCF2B
Registers for Timers in AVR
TCNTn (Timer/Counter register) TCCR0A TCCR0B
TOVn (Timer Overflow flag) OCR0A TCNT0 OCR0B
TCCRn (Timer Counter control register) TOV0
TCCR2A TCCR2B
OCR1AH OCR1AL TCNT1H TCNT1L OCR1BH OCR1BL
OCR2A TCNT2 OCR2B
TOV1
TOV2
= = = =
OCF1A OCF1B OCF2A OCF2B
Timer0 (8-bit Timer)
Output Compare Register B
Timer Counter Control Register A
TCCR0A TCCR0B
8 TOV0
8 8
= =
OCF0A OCF0B
PSR10
Clock Selector (CS)
Clear
clkIO 10-bit T/C Prescaler
CS02 CS01 CS00 Comment
clk/8
clk/64
clk/256
clk/1024
0 0 0 No clock source (Timer/Counter stopped)
0 0 1 clk (No Prescaling) T0
0 1 0 clk / 8 0
0 1 1 clk / 64
1 0 0 clk / 256
CS00 0 1 2 3 4 5 6 7
1 0 1 clk / 1024
CS01
1 1 0 External clock source
CS02 on T0 pin. Clock on falling edge
1 1 1 External clock source on T0 pin. Clock on rising edge
Timer/Counter0 clock
source
Timer0 Control Register
D7 D6 D5 D4 D3 D2 D1 D0 Bit
COM0A1 COM0A0 COM0B1 COM0B0 - - WGM01 WGM00 TCCR0A
10
Timer0 Normal Mode Programming
Normal mode
In this mode, the content of the timer/counter increments with
each clock. It counts up until it reaches its max of FF. When it
rolls over from FF to 00, it sets high a flag bit called TOV0 (Timer0
Overflow).
Timer0 Normal Mode Programming
TCNT0
0xFF
TOV TOV TOV
0 time
FF
FE
2
1 TOV0: 0
1
0 TOV0 = 1
12
Timer0 Normal Mode Programming
Steps to program Timer0 in Normal mode
1. Load the TCNT0 register with the initial count value.
2. Load the value into the TCCR0A and TCCR0B register, indicating
which mode is to be used and the prescaler option.
3. When you select the clock source, the timer/counter starts to
count, and each tick causes the content of the timer/counter to
increment by 1.
4. Keep monitoring the timer overflow flag (TOV0) to see if it is
raised. Get out of the loop when TOV0 becomes high.
5. Stop the timer by disconnecting the clock source, using the
following instructions:
6. Clear the TOV0 flag for the next round.
7. Go back to Step 1 to load TCNT0 again.
Example 1: Timer 0 Normal Mode
// Q. toggle bits of PB5 continuously with some delay.
void T0_Delay(){
TCNT0 = 0x20; // initial Value of TCNT0 = 0x20 = 32 = -224
TCCR0A = 0x00; // Normal mode
TCCR0B = 0x01; // Run Timer0 with no Pre-scaler
while ((TIFR0&(1<<TOV0))==0); // wait for TOV0 to roll over
TCCR0B = 0; // Stop Timer
TIFR0 |= 1<<TOV0; // Clear TOV0
}
void setup(){
DDRB = DDRB | (1<<5) ; // PB5 as output
SREG &= ~(1<<7); // disable all interrupts
}
void loop(){
PORTB = PORTB & ~(1<<5); T0_Delay(); // Turn OFF LED
PORTB = PORTB | (1<<5); T0_Delay(); // Turn ON LED
}
14
Timer 0 Normal Mode Programming
Calculating Delay Length of Previous Program
Assume XTAL = 16 MHz.
void T0_Delay(){
TCNT0 = -140; // initial Value of TCNT0 = 116 = 0x74 = -140
TCCR0A = 0x00; // Normal mode
TCCR0B = 0x02; // Run Timer0 with 1:8 Pre-scaler
while ((TIFR0&(1<<TOV0))==0); // wait for TOV0 to roll over
TCCR0B = 0; // Stop Timer
TIFR0 |= 1<<TOV0; // Clear TOV0
}
void setup(){
DDRB = DDRB | (1<<5) ; // PB5 as output
SREG &= ~(1<<7); // disable all interrupts
}
void loop(){
PORTB = PORTB & ~(1<<5); T0_Delay(); // Turn OFF LED
PORTB = PORTB | (1<<5); T0_Delay(); // Turn ON LED
}
18
Timer 0 Max Delay
Q Find the largest delay that we can generate using Timer0.
Assume XTAL = 16 MHz.
Solution:
= 64 µs
Max delay = Max Counts * delay of one count
void T0_Delay(){
TCNT0 = 0x00; // Start timer from 0x00
OCR0A = 250 - 1; // initial Value of OCR0A = 249
TCCR0A = 0x02; // CTC mode
TCCR0B = 0x03; // Run Timer0 with 1:64 Pre-scaler
while ((TIFR0 & (1<<OCF0A))==0); // wait for Compare Match
TCCR0B = 0; // Stop Timer
TIFR0 |= 1<<OCF0A; // Clear OCF0A
}
void setup(){
DDRB |= (1<<5); // PB5 as output
SREG &= ~(1<<7); //
}
void loop(){
PORTB = PORTB | (1<<5); T0_Delay(); // Turn ON LED
PORTB = PORTB & ~(1<<5); T0_Delay(); // Turn OFF LED
}
// In Theory Delay = (249+1) * 8 µs = 1 ms (for 16MHz Clock) 22
Timer0 CTC Mode Programming
Example 4
Assuming XTAL = 16 MHz, write a program to generate a delay of 12.8 ms.
Use Timer0, CTC mode, with Prescaler = 1024.
Solution:
Due to Prescaler = 1024 each timer clock lasts 1024 × 0.0625 µs = 64 µs.
Thus in order to generate a delay of 12.8 ms,
we should wait 12.8 ms / 64 µs = 200 clocks.
Notice that the comparator checks for equality; thus, if we load OCR0A
register with a value smaller than TCNT0’s value, the counter will miss the
compare match and will count up until it reaches the maximum value of 0xFF
and rolls over. This causes a big delay and is not desirable in many cases.
Timer0 CTC Mode Programming
Timer2 vs. Timer0
Timer0 Timer2
TCCR0A TCCR0B TCCR2A TCCR2B
TOV0 TOV2
= = = =
25
The difference between Timer0 and Timer2
Timer0 Timer2
void T2_Delay(){
TCNT2 = -125; // initial Value of TCNT2 = 131 = 0x83 = -125
TCCR2A = 0x00; // Normal mode
TCCR2B = 0x06; // Run Timer2 with 1:256 Pre-scaler
while ((TIFR2 & (1<<TOV2) )==0); // wait for TOV2 to roll over
TCCR2B = 0; // Stop Timer
TIFR2 |= 1<<TOV2; // Clear TOV0
}
void setup(){
DDRB |= (1<<5); // PB5 as output
SREG &= ~(1<<7); // disable all interrupts
}
void loop(){
PORTB &= ~(1<<5); T2_Delay(); // Turn OFF LED
PORTB |= (1<<5); T2_Delay(); // Turn ON LED
}
27
Example 5: Timer 2 CTC Mode Programing
// toggle bits of PB5 continuously with 1ms delay using Timer 2
// CTC Mode.
void T2_Delay(){
TCNT2 = 0x00; // Start timer from 0x00
OCR2A = 250 - 1; // initial Value of OCR2A = 249
TCCR2A = 0x02; // CTC mode
TCCR2B = 0x04; // Run Timer2 with 1:64 Pre-scaler
while ((TIFR2 & (1<<OCF2A))==0); // wait for Compare Match
TCCR2B = 0; // Stop Timer
TIFR2 |= 1<<OCF2A; // Clear OCF2A
}
void setup(){
DDRB |= (1<<5) ; // PB5 as output
SREG &= ~(1<<7); // disable all interrupts
}
void loop(){
PORTB &= ~(1<<5); T0_Delay(); // Turn OFF LED
PORTB |= (1<<5); T0_Delay(); // Turn ON LED
} 28
Timer 1
TCCR1A TCCR1B TCCR1C
TOV1
16 16 16
= =
OCF1A OCF1B
29
Basic Registers of Timer1
TCNT1 (Timer/Counter Register)
Timer1 is a 16-bit timer and it is split into two bytes, TCNT1L
(Timer1 low byte) and TCNT1H (Timer1 high byte).
Timer1 has three control registers named TCCR1A (Timer/counter 1
control register), TCCR1B and TCCR1C.
The TOV1 (timer overflow) flag bit goes HIGH when overflow
occurs.
Timer1 also has the Prescaler options.
There are two 16-bit OCR registers in Timer1: OCR1A and OCR1B.
There are two separate flags for each of of Timer1 OCR registers,
which act independently of each other.
Whenever TCNT1 equals OCR1A, the OCF1A flag will be set on the
next clock. When TCNT1 equals OCR1B, the OCF1B flag will be set
on the next clock.
30
COM1A1 COM1A0 COM1B1 COM1B0 - - WGM11 WGM10 TCCR1A
31
COM1A1 COM1A0 COM1B1 COM1B0 - - WGM11 WGM10 TCCR1A
PSR10
Clear
clkIO 10-bit T/C Prescaler
clk/8
clk/64
clk/256
clk/1024
T1
0
CS10 0 1 2 3 4 5 6 7
CS11
CS12
Timer/Counter1 clock
source
32
COM1A1 COM1A0 COM1B1 COM1B0 - - WGM11 WGM10 TCCR1A
void T1_Delay(){
TCNT1 = 0x0000; // Start timer from 0x00
OCR1A = 15625 - 1; // initial Value of OCR1A = 15,624
TCCR1A = 0x00; //
TCCR1B = 0x0D; // Run Timer1 with CTC mode, 1:1024 Pre-scaler
while ((TIFR1 & (1<<OCF1A))==0); // wait for Compare Match
TCCR1B = 0; // Stop Timer 1
TIFR1 |= 1<<OCF1A; // Clear OCF1A Flag
}
void setup(){
DDRB |= (1<<5); // PB5 as output
SREG &= ~(1<<7); // disable all interrupts
}
void loop(){
PORTB = PORTB & ~(1<<5); T1_Delay(); // Turn OFF LED
PORTB = PORTB | (1<<5); T1_Delay(); // Turn ON LED
} 35
Timer1 Normal Mode Programming
Example 3
Assuming XTAL = 16 MHz, write a program to generate a Frequency of 100
Hz using Timer1 Normal mode.
Solution:
Timer Period = 1/100 = 10 ms
With 50% duty cycle Time for logic 1 = 10 * 0.5 = 5 ms
Pre- Timer Clock Timer Period Total Counts
Scaler (Time of One Count)
None 16 MHz 1/16MHz = 0.0625 µs 5ms / 0.0625 µs = 80,000
8 16 MHz / 8 = 2MHz 1/2MHz = 0.5 µs 5ms / 0.5 µs = 10,000
64 16 MHz / 64 = 250KHz 1/250KHz = 4 µs 5ms / 4 µs = 1,250
256 16 MHz / 256 = 62.5KHz 1/62.5KHz = 16 µs 5ms / 16 µs = 312.5
1024 16 MHz / 1024 = 15.625 1/15.625 KHz = 64 µs 5ms / 64 µs = 78.125
KHz
From the above calculation we can use the options Prescaler = 8 or 64
To wait 1,250 clocks we should load TCNT1 with 65,536 – 1,250 = 64,286
Example 7: Timer 1 Normal Mode Programing
// Generate 100 Hz Frequency (T = 10 ms)at PB5 using Timer 1
// Normal Mode.
void T1_Delay(){
TCNT1 = -1250; // TCNT1 = 65,536-1250 = 64,286 = 0xFB1E = -1250
TCCR1A = 0x00; // Normal Mode
TCCR1B = 0x03; // Run Timer1 with 1:64 Pre-scaler
while ((TIFR1 & (1<<TOV1))==0); // wait for Compare Match
TCCR1B = 0; // Stop Timer 1
TIFR1 |= 1<<TOV1; // Clear OCF1A Flag
}
void setup(){
DDRB |= (1<<5) ; // PB5 as output
SREG &= ~(1<<7); // disable all interrupts
}
void loop(){
PORTB = PORTB & ~(1<<5); T1_Delay(); // Turn OFF LED
PORTB = PORTB | (1<<5); T1_Delay(); // Turn ON LED
} 38
Example 8: Timer 1 as 16-bit Counter
// Count events at T1 using Timer 1 and send it to serial port.
void setup(){
Serial.begin(9600); // use 9600 bits per second
DDRD &= ~(1<<5); // Make PD5 (T1) Pin as input
PORTD |= (1<<5); // Enable pull-up at PD5 (T1)
SREG &= ~(1<<7); // disable all interrupts
T0
TCNT1 = 0x0000; // Set initial Count to 0
TCCR1A = 0x00; // 16-bit counter, Normal Mode
TCCR1B = 0x06; // Start Counting at
// Falling Edge using T1 pin T1
} // For Rising Edge put 0x07
void loop(){
Serial.println(TCNT1);
delay(500); // Delay in between reads for stability
if(TIFR1 & (1<<TOV1)) // if it overflows
TIFR1 = 1<<TOV1; // clear TOV1 flag
}
39
Example 8: Timer 1 as 16-bit Counter
40
Example 9: Timer 0 as 8-bit Counter
// Count events at T0(PD4) pin using Timer 0 and send it to Port B.
// Show Number of Overflows at PORTC.
void setup(){
DDRB = 0xFF; // Make Port B as output
DDRC = 0xFF; // Make Port C as output
DDRD &= ~(1<<4); // Make PD4 (T0) Pin as input
PORTD |= (1<<4); // Enable pull-up at PD5 (T1)
T0
SREG &= ~(1<<7); // disable all interrupts
TCNT0 = 0x00; // Set initial Count to 0
TCCR0A = 0x00; // 8-bit counter, Normal Mode
TCCR0B = 0x06; // Start Counting at T1
// Falling Edge using T0 pin
} // For Rising Edge put 0x07
void loop(){
PORTB = TCNT0;
if(TIFR0 & (1<<TOV0)){ // if it overflows
TIFR0 = 1<<TOV0; // clear TOV0 flag
PORTC++; // update Number of Overflows
}
}
41
Example 10: Timer 1 as a Counter
// Count events at T1 using Timer 1 and toggle LED at PB5 after
// every 100 event (pulse) using CTC Mode.
#define LED 5
void setup(){
DDRB |= (1<<LED); // Make PB5 as output
DDRD &= ~(1<<5); // Make PD5 (T1) Pin as input
PORTD |= (1<<5); // Enable pull-up at PD5 (T1)
T0
SREG &= ~(1<<7); // disable all interrupts
TCNT1 = 0x0000; // Set initial Count to 0
OCR1A = 100-1; // for 100 counts
TCCR1A = 0x00; // 16-bit counter, CTC Mode T1
TCCR1B = 0x0E; // Start Counting at
// Falling Edge using T1 pin
// For Rising Edge put 0x07
}
void loop(){
while ((TIFR1 & (1<<OCF1A))==0); // wait for Compare Match
TIFR1 |= 1<<OCF1A; // Clear OCF1A Flag
PORTB ^= 1<<LED ; // Toggle LED
} 42
43
Example 11: Frequency Checker (1/2)
// Count events at T0(PD4) using Timer 0 for one second and show
// them on PORTC and PORTD.
void T1_Delay(){
TCNT1 = 0x0000; // Start timer from 0x00
OCR1A = 15625 - 1; // initial Value of OCR1A = 15,624
TCCR1A = 0x00; //
TCCR1B = 0x0D; // Run Timer1 with CTC mode, 1:1024 Pre-scaler
while ((TIFR1 & (1<<OCF1A))==0); // wait for Compare Match
TCCR1B = 0; // Stop Timer 1
TIFR1 |= 1<<OCF1A; // Clear OCF1A Flag
}
void setup(){
DDRC |= 0x0F ; // Make PC0 to PC3 as output
DDRB |= 0x0F ; // Make PB0 to PB3 as output
DDRD &= ~(1<<4); // Make PD4 (T0) Pin as input
PORTD |= (1<<4); // Enable pull-up at PD5 (T1)
SREG &= ~(1<<7); // disable all interrupts
}
44
Example 11: Frequency Checker (2/2)
void loop()
{
TCNT0 = 0x00; // Start counting from 0
TCCR0A = 0x00; // 8-bit counter, Normal Mode
45
200Hz
100Hz