PathHome =>
AVR-Overview =>
Tutorial => Part 4
; Test 4: Learn more about timer in interrupt mode
; New things to learn here:
; - Timer in interrupt
mode
; - Interrupts, Interrupt-Vector
; - BCD-Arithmetic
.NOLIST
.INCLUDE "8515def.inc"
.LIST
; define universal register
.DEF mp = R16
; Counts the number of overflows of the
hardware counter, called software counter
.DEF z1 = R0
; Working register for the Interrupt-Service-Routine
; Note that any registers used during an interrupt,
including the
; status-register with all the flags, must either be
; reserved for that purpose or they have to
reset to their initial
; value at the end of the service routine! Otherwise nice and
; nearly unpredictable effects will occur.
.DEF ri = R1
; Register zum Zählen der Sekunden, gepackte BCD-Ziffern
.DEF sec
= R2
; Reset-Vektor on address 0000
RJMP main
; This is the first time we really need this RJMP
command, because here
; we have to put interrupt vectors to position
1, 2, 3 and so on.
; Interrupt-vector
definitions not used here (all but the timer overflow vector)
; are dummied by the return-from-interrupt
command RETI,
; RETI is a special return command for interrupt
service routines as it
; preserves the interrupt-flags in
the status-register. Be sure that the jump
; to the interrupt service routine tc0i is
exactly at adress 0007, otherwise
; the interrupt fails. The following mechanism
goes on: If the timer overflows
; (transition from 255 to 0) the program run is interrupted, the current adress
; in the program counter is pushed to the stack,
the command at adress 0007
; is executed (usually a jump instruction). After finishing execution of the
; interrupt service routine the program counter
value is restored from the
; stack and
program execution maintains at that point.
RETI ; Int0-Interrupt
RETI ; Int1-Interrupt
RETI ; TC1-Capture
RETI ; TC1-Compare
A
RETI ; TC1-Compare
B
RETI ; TC1-Overflow
RJMP tc0i ;
Timer/Counter 0 Overflow, my jump to the service routine
RETI ; Serial
Transfer complete
RETI ; UART
Rx complete
RETI ; UART
Data register empty
RETI ; UART
Tx complete
RETI ; Analog
Comparator
; Interrupt-Service-Routine for the counter
tc0i: IN ri,SREG ;
save the content of the flag register
INC z1 ;
increment the software counter
OUT SREG,ri ;
restore the initial value of the flag register
RETI ; Return
from interrupt
; ; The main program starts here
main: LDI mp,LOW(RAMEND) ;Initiate
Stackpointer
OUT SPL,mp ;
for use with interrupts and subroutines
LDI mp,HIGH(RAMEND)
OUT SPH,mp
; Software-counter-register to zero
LDI mp,0 ;
z1 cannot be accessed directly
MOV z1,mp ;
copy 0 in mp to z1
MOV sec,mp ;
and to the seconds counter
; Prescaler of the counter/timer = 256, that is 4 MHz/256 = 15625 Hz = $3D09
LDI mp,0x04 ;Initiate
Timer/Counter 0 prescaler
OUT TCCR0,mp ;
to Timer 0 Control register
LDI mp,0xFF ;
all bits are output
OUT DDRB,mp ;
to data direction register
; enable interrupts from timer 0
LDI mp,$02 ;
Bit 1 set
to 1
OUT TIMSK,mp ;
in Timer Interupt Mask Register
; Enable all interrupts
SEI ; enables
interrupts by setting flag in status-register
; The 8-bit counter overflows from time to
time and the interrupt
service
; routine increments a counter in a register.
The main program loop reads this
; counter register and waits until it reaches
hex 3D. Then the timer is read until
; he reaches 09 (one second = dez 15625 = hex
3D09 timer pulses). The timer
; and the register are set
to zero and one second is incremented. The
seconds
; are handled as packed BCD-digits
(one digit = four bits, 1 Byte
represents
; two digits). The seconds are reset to zero
if 60 is reached. The seconds
; are displayed on the LEDs.
loop: LDI mp,$3D ;
compare value for register counter
loop1: CP z1,mp ;
compare with the register
BRLT loop1 ;
z1 < mp, wait
loop2: IN mp,TCNT0 ;
read counter LSB
CPI mp,$09 ;
compare with LSB
BRLT loop2 ;
TCNT0 < 09, wait
LDI mp,0 ;
zero to
OUT TCNT0,mp ;
hardware-counter LSB
MOV z1,mp ;
and to software-counter MSB
RCALL IncSec ;
subroutine increment second counter
RCALL Display ;
display second counter
RJMP loop ;
the same again
; subroutine for incrementing the second
counter
; in BCD-arithmetic!
Lower Nibble = Bit 0..3, Upper Nibble = 4..7
IncSec: SEC ;
Set Carry-Flag for adding a one
LDI mp,6 ;
Provoke overflow of lower Nibble
ADC sec,mp ;
by adding 6 + 1 (Carry)
BRHS Chk60 ;
if overflow then jump to 60-Check
SUB sec,mp ;
subtract 6, no overflow occurred
Chk60: LDI mp,$60 ;
compare with 60
CP sec,mp
BRLT SecRet ;
jump, if lower than 60
LDI mp,256-$60 ;
load complement
ADD sec,mp ;
and add
to zero
SecRet: RET ;
return to the main program
; subroutine displaying the second counter
on the LEDs
Display:
MOV mp,sec ;
copy seconds to mp
COM mp ;
One-complement = XOR(FF) to invert
OUT PORTB,mp ;
software-counter to LEDs
RET ; Back to
the main program
©2002 by http://www.avr-asm-tutorial.net