;********* ATmega 16 Multitasking 1 ****************** .include "m16def.inc" .equ times = 3000 ; ********************* Einstellungen bei 4 MHz Taktfrequenz: ; 500 = 50 µs (rund 1:1; 50 % Overhead) ; 2000 = 450 µs (1:10; 10 % Overhead) ; 3000= 700 µs (1:14; 6,7 % Overhead) ; 4000 = 1 ms (1:20; 5 % Overhead) ; 20000 = 5 ms (1:100; 1 % Overhead) ; .def temp=r17 .def count=r18 .def old=r19 .def einer=r18 .def zehner=r19 .DSEG .ORG 0x0060 current_task: .byte 2 first_task: .byte 4 sec_task: .byte 4 third_task: .byte 4 last_task: .byte 4 .ORG ramend-(4*90) task_1: .byte 90 task_2: .byte 90 task_3: .byte 90 task_4: .byte 90 .CSEG .ORG 0x0000 ; ************************** Interrupttabelle ************************* jmp anfang jmp extint0 jmp extint1 jmp tim2comp jmp tim2ovf jmp tim1capt jmp tim1compa jmp tim1compb jmp tim1ovf jmp tim0ovf jmp spistc jmp usartrxc jmp usartudre jmp usarttxc jmp adcrdy jmp eeready jmp anacomp jmp twi jmp extint2 jmp tim0comp jmp spmrdy anfang: ldi temp,low(RAMEND) out SPL,temp ;init Stack Pointer Low ldi temp,high(RAMEND) out SPH, temp ;init Stack Pointer High ; initialize ldi temp,0x00 out porta,temp out portb,temp out portc,temp out portd, temp ldi temp,0x7f out ddra,temp out ddrc,temp out ddrb,temp out ddrd,temp ; Tasksteuerung einrichten ldi r24,low(task_1+88-36) ; Stackpointer *********** TASK 1 ldi r25,high(task_1+88-36) sts first_task+2,r24 sts first_task+3,r25 ldi r24,0x39 ; virtual port adrs sts first_task,r24 ldi r24,low(init_1) ; Befehlszähler ldi r25,high(init_1) sts task_1+87,r25 sts task_1+88,r24 ldi r24,low(task_2+88-36) ; Stackpointer ***************** TASK 2 ldi r25,high(task_2+88-36) sts sec_task+2,r24 sts sec_task+3,r25 ldi r24,0x36 ; virtual port adrs sts sec_task,r24 ldi r24,low(init_2) ; Befehlszähler ldi r25,high(init_2) sts task_2+87,r25 sts task_2+88,r24 ldi r24,low(task_3+88-36) ; Stackpointer ****************** TASK 3 ldi r25,high(task_3+88-36) sts third_task+2,r24 sts third_task+3,r25 ldi r24,0x33 ; virtual port adrs sts third_task,r24 ldi r24,low(init_3) ; Befehlszähler ldi r25,high(init_3) sts task_3+87,r25 sts task_3+88,r24 ldi r24,low(task_4+88-36) ; Stackpointer ******************* TASK 4 ldi r25,high(task_4+88-36) sts last_task+2,r24 sts last_task+3,r25 ldi r24,0x30 ; virtual port adrs sts last_task,r24 ldi r24,low(init_4) ; Befehlszähler ldi r25,high(init_4) sts task_4+87,r25 sts task_4+88,r24 ldi r24,low(sec_task) ; auf erste Task einstellen ldi r25, high(sec_task) sts current_task,r24 sts current_task+1,r25 lds yl,current_task ; Vorbereitung für anfänglichen Rückkehrablauf lds yh,current_task+1 ;******************* CTC 1 (Systemzeitgeber) ldi temp, high (times) out ocr1ah,temp ldi temp, low(times) out ocr1al, temp ldi temp,0x09 ; CTC 1 auf Normal Mode; 1:1 Takt out tccr1b,temp ; Clear on Compare Match A ldi temp,0x10 out timsk,temp ; Compare Match A Interrupt rjmp bkout ; mit der ausgewählten Task starten************* Interrupt wird scharf ************* iwait: ; ewige Schleife rjmp iwait ; ************************************************************* init_1: jmp wue ;*************************************************************** init_2: jmp wue ;************************************************************** init_3: jmp wue ; ************************************************************** init_4: jmp wue ; ************************************************************** ;**************** Interrupt Handlers **************************** extint0: extint1: tim2comp: tim2ovf: tim1capt: tim1compa: rjmp timeslice tim1compb: tim1ovf: tim0ovf: spistc: usartrxc: usartudre: usarttxc: adcrdy: eeready: anacomp: twi: extint2: tim0comp: spmrdy: ; ****************************************************************************************** ; ****************************************************************************************** ; Interrupt / System Call brk: cli timeslice: ; sbi porta,0 ; Messimpuls ein push r31 push r30 push r29 push r28 push r27 push r26 push r25 push r24 push r23 push r22 push r21 push r20 push r19 push r18 push r17 push r16 push r15 push r14 push r13 push r12 push r11 push r10 push r9 push r8 push r7 push r6 push r5 push r4 push r3 push r2 push r1 push r0 in temp,sreg push temp ldi temp,0 ; Reserve. Taskzustandsbyte push temp ; alles im Stack ; ----------------------------------------------- lds yl,current_task lds yh,current_task+1 in r24,spl ; Stackpointer holen in r25,sph std y+2,r24 ; Stackpointer abspeichern std y+3,r25 cpi yl,low(last_task) brne nexttask cpi yh, high(last_task) brne nexttask firsttask: ldi yl,low(first_task-4) ldi yh,high(first_task-4) nexttask: adiw yl,4 sts current_task,yl sts current_task+1,yh ; ----------- neue Task eingestellt bkout: ldd r24,y+2 ; Stackpointer einrichten ldd r25,y+3 out spl,r24 out sph,r25 ; -------------------------------------------------- pop temp ; *** dummy res. task State pop temp andi temp,0x7f ; Interrupt Enable Flag aus out sreg,temp ; Flagbits einstellen pop r0 pop r1 pop r2 pop r3 pop r4 pop r5 pop r6 pop r7 pop r8 pop r9 pop r10 pop r11 pop r12 pop r13 pop r14 pop r15 pop r16 pop r17 pop r18 pop r19 pop r20 pop r21 pop r22 pop r23 pop r24 pop r25 pop r26 pop r27 pop r28 pop r29 pop r30 pop r31 ; cbi porta,0 ; Messimpuls aus reti ; nächste Task erhält Laufzeit ;**************************** Wuerfel ************************** wue: lds yl,current_task lds yh,current_task+1 ldd zl,y+0 ; virtuelle Portadresse ldi zh,0 ldi einer,1 wdisplay21: mov temp,einer rcall convseg std z+2,r0 wwarten2: ldd r16,z+0 andi r16,0x80 brne wwarten2 inc einer cpi einer,7 brne wdisplay21 rjmp wue ; ******************* Unterprogramme convseg: push zl push zh ;number in temp ldi zl,low(segtab*2) ldi zh, high(segtab*2) add zl,temp ldi temp,0 adc zh,temp lpm pop zh pop zl ret segtab: .db 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90