Nothing Special   »   [go: up one dir, main page]

Avr Timer Programming in Assembly and C: BY:-Pratik Gohel Asst. Professor Government Engineering College

Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 45

AVR TIMER

PROGRAMMING
IN ASSEMBLY AND C
BY:- Pratik Gohel
Asst. professor
Government Engineering College
Introduction
• Many applications need to count an event or generate time delays.
• When we want to count an event, we connect the external event
source to the clock pin of the counter register.
• Then, when an event occurs externally, the content of the counter is
incremented; in this way, the content of the counter represents how
many times an event has occurred.
• When we want to generate time delays, we connect the oscillator to
the clock pin of the counter.
• So, when the oscillator ticks, the content of the counter is
incremented.
• one way to generate a time delay is to clear the counter at the start
time and wait until the counter reaches a certain number.
• For example, consider a microcontroller with an oscillator with
frequency of 1 MHz.
• the content of the counter register increments once per microsecond.
• If we want a time delay of 100 microseconds, we should clear the
counter and wait until it becomes equal to 100.
• there is a flag for each of the counters. The flag is set when the
counter overflows, and it is cleared by software.
• The second method to generate a time delay is to load the counter
register and wait until the counter overflows and the flag is set.
• For example, in a microcontroller with a frequency of 1 MHz, with an
8-bit counter register, if we want a time delay of 3 microseconds, we
can load the counter register with $FD and wait until the flag is set
after 3 ticks.
• After the first tick, the content of the register increments to $FE; after
the second tick, it becomes $FF; and after the third tick, it overflows
(the content of the register becomes $00) and the flag is set.
• In ATmega32, there are three timers: Timer0, Timer1, and Timer2.
• Timer0 and Timer2 are 8-bit, while Timer1 is 16-bit.
• we cover Timer0 and Timer2 as 8-bit timers, and Timer1 as a 16-bit timer.
• Every timer needs a clock pulse to tick. The clock source can be internal or
external.
• If we use the internal clock source, then the frequency of the crystal oscillator is
fed into the timer.
• Therefore, it is used for time delay generation and consequently is called a timer.
• By choosing the external clock option, we feed pulses through one of the AYR's
pins. This is called a counter.
Basic Registers of Timers
• In AVR, for each of the timers, there is a TCNTn (timer/founter)
register. That means in ATmega32 we have TCNT0, TCNT1, and
TCNT2.
• The TCNTn register is a counter. Upon reset, the TCNTn contains
zero. It counts up with each pulse.
• The contents of the timers/counters can be accessed using the
TCNTn. You can load a value into the TCNTn register or read its
value.
• Each timer has a TOVn (Timer Overflow) flag, as well. When a
timer overflows, its TOVn flag will be set.
• Each timer also has the TCCRn (timer/counter Control register)
register for setting modes of operation.
• For example, you can specify Timer0 to work as a timer or a
counter by loading proper values into the TCCR0.
• Each timer also has an OCRn (Output Compare Register) register.
The content of the OCRn is compared with the content of the
TCNTn. When they are equal the OCFn (Output Compare Flag)
flag will be set.
• The timer registers are located in the I/O register memory. Therefore,
you can read or write from timer registers using IN and OUT
instructions, like the other I/O registers.
• the following instructions load TCNT0 with 25:
LDI R20,25 ;R20 = 25
OUT TCNT0,R20 ;TCNT0 = R20
or "IN R19, TCNT2" copies TCNT2 to R19.
The internal structure of the ATmega32 timers
is shown in Figure
Timer 1
Timer 2
Timer0 Programming
• TCNTO is 8-bit as shown in Figure:

• TCCRO (Timer/Counter Control Register) register:


• TCCRO is an 8-bit register used for control of Timer0.
CS02:CS00 (Timer0 clock source)
• These bits in the TCCRO register are used to choose the clock source.
• CS02:CS00 = 000, then the counter is stopped.
• If CS02-CSOO have values between 001 and IOI, the oscillator is used
as clock source and the timer/counter acts as a timer.
FOC0 Bit D7
• Force compare match: This is a write-only bit, which can be used
while generating a wave. Writing 1 to it causes the wave generator to
act as if a compare match had occurred.
WGM00, WGM01
D6 D3 Timer0 mode selector bits
0 0 Normal
0 1 CTC (Clear Timer on Compare Match)
1 0 PWM, phase correct
1 1 Fast PWM

COM01:00
• D5 D4 Compare Output Mode:
These bits control the waveform generator
CS02:00
D2 D1 D0 Timer0 clock selector
0 0 0 No clock source (Timer/Counter stopped)
0 0 1 Clk (No Prescaling)
0 1 0 Clk I 8
0 1 1 Clk I 64
1 0 0 Clk I 256
1 0 1 Clk/ 1024
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.

• Find the value for TCCRO if we want to program Timer0 in Normal


mode, no prescaler. Use AVR's crystal oscillator for the clock source.
TIFR (Timer/counter Interrupt Flag Register) register
• The TIFR register contains the flags of different timers, as shown in
Figure
TOVO (Timer0 Overflow)
• The flag is set when the counter overflows, going from $FF to $00.
• when the timer rolls over from $FF to 00, the TOYO flag is set to 1 and it
remains set until the software clears it.
• The strange thing about this flag is that in order to clear it we need to write
1 to it.
• when we want to clear a given flag of a register we write 1 to it and 0 to the
other bits. For example, the following program clears TOV0:
• LDI R20,0x01
• OUT TIFR,R20 ;TIFR 0b0000001
Normal mode
• In this mode, the content of the timer/counter increments with each clock.
• It counts up until it reaches its max of 0xFF. When it rolls over from 0xFF to
0x00, it sets high a flag bit called TOV0 (Timer Overflow).
Steps to program Timer0 in Normal mode
• Load the TCNT0 register with the initial count value.
TCNT0 = 0x20;
• Load the value into the TCCR0 register, indicating which mode (8-bit or16-bit) is to be
used and the prescaler option. 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.
TCCR0 = 0x01; //TimerO, Normal mode, no prescaler
• Keep monitoring the timer overflow flag (TOV0) to see if it is raised. Get out of the loop
when TOV0 becomes high.
(TIFR&0x1)==0 //wait for TF0 to roll over
• Stop the timer by disconnecting the clock source, using the following instructions:
TCCR0 = 0;
• Clear the TOV0 flag for the next round.
TIFR = 0x1;
• Go back to Step 1 to load TCNT0 again.
Write a C program to toggle all the bits of PORTB continuously with
some delay. Use Timer0, Normal mode, and no prescaler options to
generate the delay.
#include "avr/io.h"
void T0Delay ( );
int main ( )
{
DDRB = 0xFF; //PORTB output port
while (1)
{
PORTB 0x55; //repeat forever
T0Delay ( ) ; //delay size unknown
PORTB = 0xAA; //repeat forever
T0Delay ( ) ;
}
}
void T0Delay ( )
{
TCNT0 = 0x20; //load TCNTO
TCCR0 = 0x01; //Timer0, Normal mode, no prescaler
while ((TIFR&0x1)==0); //wait for TFO to roll over
TCCRO = 0;
TIFR = 0x1; //clear TF0
}
Calculating delay length using timers

• the delay length depends primarily on two factors: (a) the crystal
frequency, and (b) the prescaler factor.
• A third factor in the delay size is the C compiler because various C
compilers generate different hex code sizes, and the amount of overhead
due to the instructions varies by compiler.
• Example to calculate delay: Use Timer0, Normal mode, and 1:8 prescaler
to create 70 μs delay. Assume XTAL = 8 MHz.
• XTAL = 8MHz T machine cycle = 1/8 MHz
• Prescaler = 1:8 Tclock = 8 x 1/8 MHz= 1 μs
• 70 μs/1 μs = 70 clocks 1 + 0xFF – 70 = 0xBA= 186
Write a C program to toggle only the PORTB.4 bit continuously every 70 μs.
Use Timer0, Normal mode, and 1:8 prescaler to create the delay. Assume XTAL
= 8 MHz.
#include <avr/io.h>
void T0Delay ( );
int main ( )
{
DDRB = 0xFF; //PORTB output port
while (1)
{
T0Delay ( ); //Timer0, Normal mode
PORTB = PORTB ~ 0x10; //toggle PORTB.4
}
}
void T0Delay ( )
{
TCNT0 = 186; //load TCNT0
TCCR0 = 0x02; //Timer0, Normal mode, 1:8 prescaler
while ((TIFR&(1<<TOV0))==0); //wait for TOV0 to roll over
TCCR0 = 0; //turn off Timer0
TIFR = 0x1; //clear TOV0
}
Write a C program to toggle only the PORTB.4 bit continuously every 2 ms.
Use Timer1, Normal mode, and no prescaler to create the delay. Assume
XTAL = 8 MHz.
• XTAL = 8MHz T machine cycle = 1/8 MHz
• Prescaler = 1:1 Tclock = 1 x 1/8 MHz= 0.125 μs
• 2ms/0.125 μs = 16000 clocks 0X3E80 Clocks
• 1+ 0xFFFF - 0x3E80 = OxC180
Solution
#include <avr/io.h>
void T1Delay ( );
int main ( )
{
DDRB = 0xFF; //PORTB output port Cont….
while (1)
{
PORTB = PORTB ^ (1<<PB4); //toggle PB4
T1Decay ( ); //delay size unknown
}}
void T1Delay ( )
{
TCNT1H =0xC1; //TEMP 0xC1
TCNT1L = 0x80;
TCCR1A =0x00; //Normal mode
TCCR1B = 0x01; //Normal mode, no prescaler
while ((TIFR&(0x1<<TOV1))==0); //wait for TOV1 to roll over
TCCR1B = 0;
TIFR = 0x1<<TOV1; //clear TOV1
}
C programming of Timers 0 and 1 as
counters
• Timers can be used as counters if we provide pulses from outside the
chip instead of using the frequency of the crystal oscillator as the
clock source.
• By feeding pulses to the T0 (PB0) and T1 (PB1) pins, we use Timer0
and Timer 1 as Counter 0 and Counter 1, respectively.
• Let how Timers 0 and l are programmed as counters using C language.
Assuming that a l Hz clock pulse is fed into pin T0, use the TOV0 flag to
extend Timer0 to a 16-bit counter and display the counter on PORTC and
PORTD.

#include <avr/io.h>
int main ( )
{
PORTB = 0x01; //activate pull-up of PB0
DDRC = 0xFF; //PORTC as output
DDRD = 0xFF; //PORTD as output
TCCR0 = 0x06; //output clock source
TCNT0 = 0x00;
while (1)
{
• Do
•{
• PORTC = TCNT0;
• } while((TIFR&(0x1<<TOV0))==0) ; //wait for TOV0 to roll over
• TIFR = 0x1<<TOV0; //TIFR = 0x0<<TOV0;
• PORTD ++; //increment PORTD
•}
•}
Assume that a 1-Hz external clock is being fed into pin T1 (PB1). Write
a C program for Counter1 in rising edge mode to count the pulses and
display the TCNT1H and TCNT1L registers on PORTD and PORTC,
respectively.
#include <avr/io.h>
int main ( )
{
PORTB = 0x01; //activate pull-up of PB0
DDRC = 0xFF; //PORTC as output
DDRD = 0xFF; //PORTD as output

TCCR1A = 0X00 //output clock source


TCCR1B = 0X00 //output clock source cont.….
Cont.….
TCNT1H = 0x00 //set count to 0
TCNT1L = 0x00 //set count to 0
while (1)
{
do
{
PORTC = TCNT1L;
PORTD = TCNT1H; //place value on pins
} while((TIFR&(0x1<<TOV1))==0); //wait for TOV1
TIFR = 0x1<<TOV1; //clear TOV1
}}
Assuming that XTAL = 8 MHz, write an assembly program to
generate a square wave with a period of 12.5 μs on pin
PORTB.3.
• For a square wave with T = 12.5 μs we must have a time delay of 6.25
μs. Because XTAL = 8 MHz, the counter counts up every 0.125 μs.
• This means that we need 6.25 μs I 0.125 μs = 50 clocks. 256 - 50 = 206
= 0xCE. Therefore, we have TCNT0 = 0xCE .

. INCLUDE "M32DEF.INC“
LDI R20,HIGH(RAMEND)
OUT SPH,R20
LDI R20,LOW(RAMEND)
OUT SPL,R20
LDI R16, 0x20
SBI DDRB,5 ;PB5 as an output
LDI R17, 0
OUT PORTB, R17
BEGIN:RCALL DELAY
EOR R17 ,R16 ;toggle DS of R17
OUT PORTB, R17 ;toggle PB5
RJMP BEGIN
DELAY:LDI R20,0x3E
OUT TCNT0,R20 ;load timer0
LDI R20,0x01
OUT TCCR0,R20 ;Timer0, Normal mode, int clk, no prescaler
AGAIN:IN R20,TIFR ;read TIFR
SBRS R20,TOV0 ;if TOV0 is set skip next instruction
RJMP AGAIN
LDI R20, 0x00
OUT TCCR0,R20 ;stop Timer0
LDI R20, (1<<TOV0) ;R20 = 0x01
OUT TIFR,R20 ;clear TOV0 flag
RET
Assuming XTAL = 8 MHz, write a Assembly
program to generate 1 Hz frequency on PC4.
• With 1 Hz we have T = 1 I F = 1 I 1 Hz = 1 second, half of which is high
and half low. Thus we need a delay of 0.5 second duration.
• Since XTAL = 8 MHz, the different outputs of the prescaler are as
follows:

• From the above calculation we can use options 64 or 256. We choose


64 in this Example .
. INCLUDE "M32DEF.INC“
LDI R16,HIGH(RAMEND) ;initialize stack pointer
OUT SPH,Rl6
LDI R16,LOW(RAMEND)
OUT SPL,Rl6
SBI DDRC, 4 ;PC4 as an output
BEGIN:SBI PORTC,4 ;PC4= 1
RCALL DELAY_1s
CBI PORTC, 4 ;PC4 =0
RCALL DELAY_1s
RJMP BEGIN
;------------------- Timer1 delay
DELAY_1s:
LDI R20,HIGH (62500-1)
OUT OCR1AH,R20 ;TEMP = $F4 (since 62499 - $F423)
LDI R20,LOW (62500-1)
OUT OCR1AL,R20 ;OCR1AL = $23 (since 62499 • $F423)
LDI R20, 0X00
OUT TCNT1H,R20 ;TEMP = 0x00
OUT TCNT1L,R20 ;TCNT1L= 0x00, TCNT1H =TEMP
LDI R20,0x00
OUT TCCR1A,R20
LDI R20,0x3
OUT TCCR1B,R20 ;WGM13:12=00, Normal mode, CS - CLK/64
AGAIN: IN R20,TIFR ;read TIFR
SBRS R20,0CF1A ;if OCF1A is set skip next instruction
RJMP AGAIN
LDI R20,1<<OCF1A
OUT TIFR,R20 ;clear OCF1A flag
LDI R19,0
OUT TCCR1B,R19 ;stop timer
OUT TCCR1A,R19
RET
Timer As Counter
• The value for TCCR0 if we want to program Timer0 as a Normal mode
counter by using an external clock for the clock source and increment
on the positive edge is TCCR0 = 0000 0111 Normal, external clock
source, no prescaler.
• case ofTimer0, when CS02:00 is 6 or 7, pin TO provides the clock pulse
and the counter counts up after each clock pulse coming from that
pin.
• Similarly, for Timer1, when CS12:10 is 6 or 7, the clock pulse coming
in from pin T1 (Timer/Counter 1 External Clock input) makes the
TCNT1 counter count up.
• When CS 12: 10 is 6, the counter counts up on the negative (falling)
edge. When CS12:10 is 7, the counter counts up on the positive
(rising) edge.
Assuming that a 1 Hz clock pulse is fed into pin T0 (PB0), write a
program for Counter0 in normal mode to count the pulses on falling
edge and display the state of the TCNT0 count on PORTC.
.INCLUDE "M32DEF.INC“
CBI DDRB, 0 ;make T0 (PB0) input
LDI R20,0xFF
OUT DDRC, R20 ;make PORTC output
LDI R20, 0x06
OUT TCCR0, R20 ;counter, falling edge
AGAIN:
IN R20,TCNT0
OUT PORTC, R20 ; PORTC = TCNT0
IN R16,TIFR
SBRS R16, TOV0 ;monitor TOV0 flag
RJMP AGAIN ;keep doing if Timer0 flag is low
LDI R16, 1<<TOV0
OUT TIFR, R16 ;clear TOV0 flag
RJMP AGAIN ; keep doing it
Assuming that clock pulses are fed into pin T1 (PB1), write a program
for Counter 1 in Normal mode to count the pulses on falling edge and
display the state of the TCNT1 count on PORTC and PORTD.
.INCLUDE "M32DEF.INC“
CBI DDRB,1 ;make T1 (PB1) input
LDI R20,0xFF
OUT DDRC,R20 ;make PORTC output
OUT DDRD,R20 ;make PORTD output
LDI R20, 0x06
OUT TCCR1B,R20 ;counter, falling edge

Program Continue……
AGAIN:
IN R20,TCNT1L ;R20 = TCNT1L, TEMP = TCNT1H
OUT PORTC, R20 ; PORTC = TCNT0
IN R20,TCNT1H ;R20 = TEMP
OUT PORTD,R20 ; PORTD = TCNT0
IN R16, TIFR
SBRS R16, TOV1
RJMP AGAIN; keep doing it
LDI R16, 1<<TOV1 ;clear TOV1 flag
OUT TIFR, R16
RJMP AGAIN; keep doing it
Assuming that clock pulses are fed into pin T1 (PB1) and a buzzer is
connected to pin PORTC.0, write a program for Counter I in CTC mode
to sound the buzzer every 100 pulses.
• To sound the buzzer every 100 pulses, we set the OCR1A value to 99
(63 in hex), and then the counter counts up until it reaches OCR1A.
Upon compare match, we can sound the buzzer by toggling the
PORTC.O pin.
.INCLUDE "M32DEF.INC"
CBI DDRB,1 ;make T1 (PB1) input
SBI DDRC,0 ;PC0 as an output
LDI R16,0x1
LDI R17,0
LDI R20,0x0
OUT TCCR1A,R20
LDI R20,0x0E
OUT TCCR1B,R20 ;CTC, counter, falling edge
Program Continue…..
AGAIN:
LDI R20,0
OUT OCR1AH,R20 ;TEMP = 0
LDI R20,99
OUT OCR1AL,R20 ;ORC1L = R20, OCR1H = TEMP
L1: IN R20,TIFR
SBRS R20,0CF1A
RJMP L1 ; keep doing it
LDI R20,1<<OCF1A ;clear OCF1A flag
OUT TIFR, R20
EOR R17,R16 ;toggle D0 of R17
OUT PORTC, R17 ; toggle PC1
RJMP AGAIN; keep doing it
Exercise
• Program Timer1 to generate a square wave of 3 kHz. Assume that
XTAL = 8 MHz.

You might also like