Code:
;***** Simple time-based scheduler ********
;
;The goal is to allow several tasks to execute at a regular rate
;without making a HUGE timer ISR. The timer 0 interrupt just
;decrements counters which are tested in a loop to dispatch
;subroutines. Timer 0 ticks at a mSec rate in this code.
;Task descriptions:
; task 1: blink LED 0 2/sec
; task 2: blink LED 1 1/sec
; task 3: Detect button 0 and change task 1 blink rate if the button is down
;
;********************************
;You will need to CHANGE this path
,nolist
.include "c:\avrtools\appnotes\8515def.inc"
.list
;********************************
;define registers
.def save =r1
.def temp =r16 ;temporary register
.def LED =r17 ;the actual LED value to display
.def reload =r18 ;holds timer reload value
;Specify the interval for each task to execute:
;since we are toggling LED state on each task entry,
;the task times are 1/2 the desired blink times
.equ t1 =250 ;250 mSec
.equ t2 =125 ;125 mSec - Task2 will need to have another counter
.equ t3 =30 ;30 mSec interval for the keyboard scanner
;********************************
;RAM locations:
;Task execution time intervals
.dseg
time1: .byte 1
time2: .byte 1
time3: .byte 1
;Task2 state variable needed to
;count 4 times the 1/4 second secheduled time
tsk2c: .byte 1
;message from task3 to task1 to change rate
tsk3m: .byte 1
;*******************************
; Initialization
.cseg
.org $0000
rjmp RESET ;reset entry vector
reti
reti
reti
reti
reti
reti
rjmp TIMER
reti
reti
reti
reti
reti
RESET:
ldi Temp, LOW(RAMEND) ;setup stack pointer
out SPL, Temp
ldi Temp, HIGH(RAMEND)
out SPH, Temp
;set up the PORTs
ser Temp ;set PORTB to be
out DDRB,Temp ;all outputs
ldi Temp, 0xff ;turn off LEDs
out PortB, Temp
clr Temp ;set PORTD to be
out DDRD,Temp ;all inputs
;set up timer 0 for 1 mSec ticks
ldi Temp,exp2(TOIE0);enable timer interrupt
out TIMSK, Temp
ldi Temp, 3 ;prescale timer by 64
out TCCR0, Temp
ldi Reload,256-62 ;preload timer since
out TCNT0, Reload ;62.5 x (64x.25) microSec = 1.0 mSec.
;initialize task timers
ldi temp, t1 ;mSec
sts time1, temp
ldi temp, t2
sts time2, temp
ldi temp, t3
sts time3, temp
;initialize LED state
ldi LED, 0xff ;all LEDs off
;initialize task2 state variable (4 times thru equals 1/2 sec)
ldi temp, 4
sts tsk2c, temp
;initalize task3 message to zero (don't modify task1 rate)
ldi temp, 0
sts tsk3m, temp
;Start the clock ticking
sei ;enable all interrupts
******************************************************************
;Now start scheduling events.
;This is the main program loop.
;All tasks are subroutines called from here when
;their respective timers reach zero.
Sched:
tsk1: lds temp, time1 ;test for first task ready
tst temp
brne tsk2 ;if not then skip it
rcall Task1
tsk2: lds temp, time2 ;test for second task ready
tst temp
brne tsk3 ;if not then skip it
rcall Task2
tsk3: lds temp, time3 ;test for third task ready
tst temp
brne Sched ;if not then skip it
rcall Task3
rjmp Sched
;*****************************************************************
;The three actual tasks:
;******************************
;LED 0 2/sec (but modified by Task 3)
Task1: lds temp, tsk3m ;get the message from task 3
tst temp ;and test it for "fast/normal"
brne t1fast
;if we get here the message from task 3 ="normal rate"
ldi temp, t1 ;reinit time counter
sts time1, temp
rjmp t1blk
;if we get here the message from task 3 ="fast rate"
t1fast: ldi temp, t1 ;reinit time counter
lsr temp ;divide time by four
lsr temp
sts time1, temp
;now toggle the LED
t1blk: mov temp, LED ;isolate the zero bit
andi temp, 0b00000001; and invert it
andi LED, 0b11111110
com temp
andi temp, 0b00000001
or LED, temp
out PORTB, LED
ret ;go back to scheduler
;******************************
;LED 1 1/sec
Task2: ldi temp, t2 ;reinit time counter
sts time2, temp
lds temp, tsk2c ;find out if 4 counts have occured
dec temp ;so that we can count to 1/2 second
sts tsk2c, temp
tst temp
brne t2exit ;if not then leave
;if we get here, then 1/2 second has passed and we
;should toggle the LED
mov temp, LED ;isolate the zero bit
andi temp, 0b00000010; invert it
andi LED, 0b11111101; then combine it with LED again
com temp
andi temp, 0b00000010
or LED, temp
out PORTB, LED
ldi temp, 4 ;and reset the state variable
sts tsk2c, temp
t2exit: ret ;go back to scheduler
;******************************
;Button detect and modify Task 1 blink rate
Task3: ldi temp, t3 ;reinit time counter
sts time3, temp
in temp, PIND ;get all the buttons
com temp ;convert a button-down to a one
andi temp, 0b00000001;isolate button 0
brne t3modt
;if we get here then set message to "normal" task1 rate
ldi temp, 0 ;set message value
sts tsk3m, temp ;and store it
rjmp t3exit
;if we get here then set message to "fast" task1 rate
t3modt: ldi temp, 1 ;set message value
sts tsk3m, temp ;and store it
t3exit: ret ;go back to scheduler
;**************************************************************
;timer 0 ISR (timer-zero overflow)
;Enters every 1.0 mSec
TIMER: in save, SREG
out TCNT0, Reload ; keeps clock ticking at 1 mSec
push temp ; use temp in ISR
;update each of the three timers
;for the three tasks
;BUT if the count is zero don't do anything until the process
;resets it
lds temp, time1
tst temp
breq t0t2
dec temp
sts time1, temp
t0t2: lds temp, time2
tst temp
breq t0t3
dec temp
sts time2, temp
t0t3: lds temp, time3
tst temp
breq t0end
dec temp
sts time3, temp
t0end: pop temp
out SREG, save
reti ;back to backgound tasks
;**************************************************************
Ist glaub für Mega32
Lesezeichen