; Timer Interrupt Service Routine (tim2ISR) ; Die tim2ISR arbeitet periodisch. Dessen Frequenz wird geteilt im ; Phasen-Akkumulator, der taktet die Uhr und ein Forthwort. ; Aufbau der globalen Variablen im Ram: .set heap = heap + CELLSIZE ; -- Platz fuer die Uhr bereit stellen, ; zugreifen per Basisadresse "time" : ; ( -- adr ) VE_TIME: .dw $ff04 .db "time" .dw VE_HEAD .set VE_HEAD = VE_TIME XT_TIME: .dw PFA_DOVARIABLE PFA_TIME: .dw heap .set stunde=heap .set heap = heap + 1 .set minute=heap .set heap = heap + 1 .set sekunde=heap .set heap = heap + 1 ; um eine genaue Sekunde zu bekommen, wird ein Phasen-Akkumulator benutzt: .set phaseaccu=heap .set heap = heap + CELLSIZE ; -- Platz fuer das Datum bereit stellen, ; zugreifen per Basisadresse "date" : ; ( -- adr ) VE_DATE: .dw $ff04 .db "date" .dw VE_HEAD .set VE_HEAD = VE_DATE XT_DATE: .dw PFA_DOVARIABLE PFA_DATE: .dw heap .set jahr=heap .set heap = heap + CELLSIZE .set monat=heap .set heap = heap + 1 .set tag=heap .set heap = heap + 1 ; timer2_ofv Sprungvektor in die Interupt-Tabelle eintragen: .equ bevortim2jmp = pc .org $0012 jmp tim2_ovf ; Timer/Counter2 Overflow ISR .org bevortim2jmp ; Timer2 initialisieren, starten und Interrupt einschalten: ; ( -- ) VE_TIM2INIT: .dw $ff08 .db "tim2init" .dw VE_HEAD .set VE_HEAD = VE_TIM2INIT XT_TIM2INIT: .dw DO_COLON PFA_TIM2INIT: .dw XT_INTOFF, XT_DROP ; drop SREG left by -int. ; Timer-Register setzen: .dw XT_DOLITERAL,$0 .dw XT_DOLITERAL,TCCR2A .dw XT_CSTORE .dw XT_DOLITERAL,7 ; prescaler 1024 - langsamer Takt ist angestrebt. .dw XT_DOLITERAL,TCCR2B .dw XT_CSTORE .dw XT_DOLITERAL,$1 .dw XT_DOLITERAL,TIMSK2 .dw XT_CSTORE .dw XT_INTON .dw XT_EXIT ; Sprungvektor aufbauen fuer das main word der application: ; ( -- n*y ) System Value ; R( -- ) ; deferred action VE_MAINWORD: .dw $ff08 .db "mainword" .dw VE_HEAD .set VE_HEAD = VE_MAINWORD XT_MAINWORD: .dw PFA_DODEFER PFA_MAINWORD: .dw EE_MAINWORD .dw XT_EDEFERFETCH .dw XT_EDEFERSTORE ; tim2ISR: ; -- Minimum an Status retten: tim2_ovf: nop push XH push XL lds XL,0x5F ; Statusregister push XL ; -- Uhr: ; phase accumulator liefert periodisch ein carry-bit-set = uhrtakt. ; Mit diesem Uhrentakt wird eine recht genaue Sekunde gemacht. ; phaseaccu test1: ; Mo. 07.12.09 07:28 - Di 08.12.09 20:24 => Laufzeit: 132960 sec ; mit: accuteiler = (-1431*3/2) = -2.146,5 ; ergab: .time 20 22 27 ok ; ging nach um 93 sec in der Zeit. ; accuteiler = phaseaccu * prescaler * tim2ov / f_cpu = -2.147,483648 .set accuteiler = (-2147) tim2uhr: lds XL,phaseaccu subi XL,low(accuteiler) sts phaseaccu,XL lds XL,phaseaccu+1 sbci XL,high(accuteiler) sts phaseaccu+1,XL ; tim2ISR beenden, falls die Phase noch nicht um ist: brcs tim2_llret ; <--- ganz rausspringen lds XL,sekunde inc XL cpi XL,60 brlo tim2sekunde ; branch if lower lds XL,minute inc XL cpi XL,60 brlo tim2minute lds XL,stunde inc XL cpi XL,24 brlo tim2stunde ldi XL,0 tim2stunde: sts stunde,XL ldi XL,0 tim2minute: sts minute,XL ldi XL,0 tim2sekunde: sts sekunde,XL ; jmp tim2_llret ; fuer Testzwecke ; Im Sekundentakt wird nun im Hintergrund Forth ausgefuehrt. ; Darauf achten, dass nur reentry-feste Forthworte benutzt werden. ; Hier wird der Programmfluss an high level forth uebergeben: ; -- Status retten: push ZL push ZH push R24 ; wl push R25 ; wh push R22 ; tosl = r22 push R23 ; tosh = r23 push YL push YH push temp0 push temp1 ; -- IP setzen: ldi XL,low(pfa_forthISR) ldi XH,high(pfa_forthISR) jmp DO_NEXT ; -- Zeiger auf das colon word, das als nächstes ausgefuehrt wird: pfa_forthISR: .dw XT_MAINWORD ; -- Programmfluss in die tim2ISR zurückleiten: .dw PC+1 ; next IP .dw PC+1 ; next cfa ; -- Benutzte Register wiederherstellen: pop temp1 pop temp0 pop YH pop YL pop R23 pop R22 pop R25 pop R24 pop ZH pop ZL tim2_llret: ; <--- Aussprung, X und Statusregister wiederherstellen. pop XL sts 0x5F,XL pop XL pop XH reti ; finis