2008-11-09

Použití časovačů k běhu úloh

Protože pro vážnější práci nemohu mít založený program na čekacích smyčkách, zkoušel jsem dnes rozblikat LED diodu s použitím časovače. Časovač generuje přerušení a obslužná rutina pak počítá tato přerušení a po určitém počtu změní stav LED diody. Tento přístup mi fungoval. Program jsem ale přepracoval a uvádím jeho poslední verzi.

Diodou na PB3 bliká starý kód s použitím čekacích smyček.
Kód s použitím časovače blikal diodou na PB4 ale je neaktivní.
Na PB4 jsem připojil sluchátko a s pomocí druhého časovače generuji zvuk.


;; Tabulka vektorů přerušení
.ORG 0
RESET: RJMP MAIN ; Reset Handle
V_INT0: RJMP RESET ; External IRQ0 handler
V_IOPCH:RJMP RESET ; Pin Change Interrupt
RJMP T1CMA ; Timer1 Compare Match A
V_T1OVF:RJMP RESET ; Timer1 Overflow
V_T0OVF:RJMP T0OVF ; Timer/Counter0 Overflow
V_EERDY:RJMP RESET ; EEPROM Ready
V_ANAC: RJMP RESET ; Analog Comparator
V_ADCCC:RJMP RESET ; ADC Conversion Complete
.ORG 9

;;; Initialize the MCU
INIT:
;;; Initialize T0 as interrupt source delivering ticks.
;LDI W,CS0CK1024 ; 1562.5Hz (6.1Hz)
;LDI W,CS0CK256 ; 6250.0 Hz (24.4Hz)
LDI W,CS0CK64 ; 25kHz (97.66Hz)
;LDI W,CS0CK8 ; 200kHz (782.25Hz)
OUT TCCR0,W

;;; Initialize T1 as the source for the beep frequency.
;; Set CTC1 to Reset Counter to $00 on Compare Match A
;; Set COM1A to Timer/Counter disconnected from output pin OC1A
;; Set source to CK (cca 1.6MHz)
;; Set Prescaler to CK/1024 (cca 1562.5Hz, 0.64ms)
; LDI W,(CTC1 | CS1CK1024)
; LDI W,(CTC1 | CS1CK512) ; 3125Hz
; LDI W,(CTC1 | CS1CK256) ; 6250Hz
LDI W,(CTC1 | CS1CK128) ; 12500Hz
OUT TCCR1,W
;; Set the divide factor, the compared value.
LDI W,3 ; 12500Hz/3 = 4166.6 Hz
OUT OCR1A,W


;; Reset all counters and prescalers.
LDI W,0
OUT TCNT0,W
OUT TCNT1,W
LDI W,(FOC1A | PSR1 | PSR0)
OUT SFIOR,W

;; Clear Interrupt Flags for all counters.
LDI W,(OCF1A | TOV1 | TOV0)
OUT TIFR,W

;; Allow Interrupt from Counter 1 Compare Match and Counter 0 Overflow
LDI W,(OCIE1A | TOIE0)
OUT TIMSK,W

RET


;;; Main code executed after power on and/or reset.
MAIN:

; We don't initialize stack (SPL,SPH) because ATtiny15
; contains hardware stack 3 level deep.

;; Initialize
LDI W,$18 ; PB3,PB4 out, only
OUT DDRB,W

RCALL INIT
SEI
;; All peripherals are initialized, now the main program.


;; Before main loop and flashing led we do a reset blinking.
LDI RA,16
RSTFL:
RCALL BLINK_RB3
LDI R22,1
RCALL DLY100MS
DEC RA
BRNE RSTFL

SBI PORTB,3 ; LED on
LDI R22,6
RCALL DLY3
CBI PORTB,3 ; LED off
RCALL DLY100MS

CBI PORTB,3
;;; Main Program Loop, the old code running in prallel.
LOOP:
RCALL BLINK_RB3

LDI R22,1
RCALL DLY3

; SBI PORTB,4
LDI R22,2
RCALL DLY3

RCALL BLINK_RB3
; CBI PORTB,4
RCALL DLY
RCALL DLY
RCALL DLY
RCALL DLY
RCALL DLY

RJMP LOOP

;; Zpožďovací procedura

DLY:
LDI R22,2
DLY3: LDI R21,255
DLY2: LDI R20,255
DLY1: DEC R20
BRNE DLY1
DEC R21
BRNE DLY2
DEC R22
BRNE DLY3
RET
;;; Timer0 is used in creation of tick for software. This interupt
;;; should be generate with 25kHz frequency.
T0OVF:
;; Because owerflow, we need to set the value.
LDI WI,7 ; With CK8 this should generate 100Hz overflow
OUT TCNT0,WI

;; Now we generate slower signal
DEC T0L
BRNE NOSLOW
;; Counter is zero. Initialize for next cycle and generate SLOW TICK
LDI T0L,100-1
;; SLOW TICK
; The RB4 is for earphone.
;RCALL BLINK_RB4
NOSLOW:
RETI
;;; Blink the LED on RB4 pin. We do this by inverting the value on the pin.
BLINK_RB4:
;; Read the RB4 and negate it to genereate tone.
SBIC PORTB,4
RJMP RB4CLR
RB4SET: SBI PORTB,4
RJMP RB4Done0
RB4CLR: CBI PORTB,4
RB4Done0:
RET

;;; Blink the LED on RB3 pin. We do this by inverting the value on the pin.
BLINK_RB3:
;; Read the RB3 and negate it to genereate tone.
SBIC PORTB,3
RJMP RB3CLR
RB3SET: SBI PORTB,3
SBR BITF,0b00000001 ; Enable beep
RJMP RB3Done0
RB3CLR: CBI PORTB,3
CBR BITF,0b00000001 ; Stop beep
RB3Done0:
RET

;;; Timer/Counter 1 Compare Match A Interrupt Routine. This generate tone.
;;; Because this interrupt is caled often it should be as short as possible.
T1CMA:
SBRC BITF,0
RCALL BLINK_RB4
RETI

Žádné komentáře: