~/tmp/buzzer/buzzer.asm.html
; Copyright 2006
; Marco Gubka, Chris Huebsch
;
#include p16f84a.inc
__CONFIG _WDT_OFF & _RC_OSC
;PROCESSOR p16F84A
; Konstanten
w0 equ d'2'
w1 equ d'6'
w2 equ d'12'
w3 equ d'14'
w4 equ d'16'
w5 equ d'32'
; Variable
cblock 0x0c
_dividend
_divisor
w_temp
STATUS_temp
wait1
wait2
wait3
blinkaddr
delay
endc
; Makros
; dividiert register (dividend) durch konstante (divisor)
; ganzzahlig
; Ergebnis in w
div macro dividend, divisor
movf dividend, w
movwf _dividend
movlw divisor
movwf _divisor
call division
endm
waitn macro anz
movlw anz
movwf wait3
call wait ; warten
endm
rt_an macro
bsf PORTA, 0 ; ALLE ROTEN AN
bsf PORTA, 2
endm
gn_an macro
bsf PORTA, 1
bsf PORTA, 3
endm
rt_aus macro
bcf PORTA, 0 ; ALLE ROTEN AUS
bcf PORTA, 2
endm
gn_aus macro
bcf PORTA, 1
bcf PORTA, 3
endm
nur_rt macro
movlw b'00000101'
movwf PORTA
endm
nur_gn macro
movlw b'00001010'
movwf PORTA
endm
; Programm
org 0
goto start
org 4 ;interrupt
movwf w_temp
swapf STATUS,w
movwf STATUS_temp
; interrupt-routine
; movfw TMR0
w0test
btfsc PORTB, 1 ; ds1 steht auf 1 - dh. PORTB[1] == 0
goto w1test ; wenn nicht, dann test der naechsten ds-stufe
div TMR0, w0 ; teile TMR0 durch 2 - 50 von 100
btfsc STATUS, Z ; wenn teilbar ohne rest - gewonnen
goto win
goto lose
w1test
btfsc PORTB, 2 ; ds1 steht auf 2 - dh. PORTB[2] == 0
goto w2test ; wenn nicht, dann test der naechsten ds-stufe
div TMR0, w1 ; teile TMR0 durch 5 - 20 von 100
btfsc STATUS, Z ; wenn teilbar ohne rest - gewonnen
goto win
goto lose
w2test
btfsc PORTB, 3 ; ds1 steht auf 3 - dh. PORTB[3] == 0
goto w3test ; wenn nicht, dann test der naechsten ds-stufe
div TMR0, w2 ; teile TMR0 durch 10 - 10 von 100
btfsc STATUS, Z ; wenn teilbar ohne rest - gewonnen
goto win
goto lose
w3test
btfsc PORTB, 4 ; ds1 steht auf 4 - dh. PORTB[4] == 0
goto w4test ; wenn nicht, dann test der naechsten ds-stufe
div TMR0, w3 ; teile TMR0 durch 13 - 7.6 von 100
btfsc STATUS, Z ; wenn teilbar ohne rest - gewonnen
goto win
goto lose
w4test
btfsc PORTB, 5 ; ds1 steht auf 5 - dh. PORTB[5] == 0
goto w5test ; wenn nicht, dann test der naechsten ds-stufe
div TMR0, w4 ; teile TMR0 durch 25 - 4 von 100
btfsc STATUS, Z ; wenn teilbar ohne rest - gewonnen
goto win
goto lose
w5test
btfsc PORTB, 6 ; ds1 steht auf 6 - dh. PORTB[6] == 0
goto w6test ; wenn nicht, dann test der naechsten ds-stufe
div TMR0, w5 ; teile TMR0 durch 50 - 2 von 100
btfsc STATUS, Z ; wenn teilbar ohne rest - gewonnen
goto win
goto lose
w6test ; ds steht auf "7" - d.h. es ist eigentlich aus
movlw 0xff
movwf PORTA
bsf PORTB, 7
waitn 3
; ende interrupt-routine
int_done
bcf INTCON, INTF ; externen Interrupt als bearbeitet markieren
swapf STATUS_temp,w
movwf STATUS
swapf w_temp,f
swapf w_temp,w
retfie
; Hauptprogramm
start
bsf PORTB, 7 ; sound nicht spielen
bsf STATUS, RP0 ; Registerbank 1 waehlen
; Portrichtungen festlegen
movlw b'01111111' ; PortB7 auf Ausgang und
movwf TRISB ; PortB0-PortB6 auf Eingang
movlw b'00000000'
movwf TRISA ; PortA0-PortA4 auf Ausgang
; Optionen definieren
bcf OPTION_REG, NOT_RBPU ; Register B Pullups aktivieren
bcf OPTION_REG, INTEDG ; Interrupt auf fallende Flanke
bcf OPTION_REG, T0CS ; Interner Clock fuer Timer0
; Prescaler dem WDT-Zuordnen
; das muss so sein laut Anleitung!
bcf STATUS, RP0
clrf TMR0 ; Timer 0 loeschen
bsf STATUS, RP0
clrwdt
bsf OPTION_REG, PSA ; Prescaler aus
bcf STATUS, RP0
; Interrupts aktivieren
bcf INTCON, INTF ; PortB0-Interrupt als bearbeitet markieren
bcf INTCON, RBIF ; Port-Change B0-3 als bearbeitet markieren
bcf INTCON, T0IF ; Timer-Interrupt als bearbeitet markieren
bsf INTCON, INTE ; Interrupt auf PortB0-Aktivitaet aktivieren
bsf INTCON, GIE ; Interrupts global aktivieren
clrf blinkaddr
main movfw blinkaddr
call table
movwf PORTA
movlw 0x10
call pause
incf blinkaddr, f
btfsc blinkaddr, 3
clrf blinkaddr
goto main
sleep ;hier sollte er nie hinkommen!
; funktion bestimmt Teilbarkeit von _dividend durch _divisor
; Ergebnis in Zero-Flag
; wenn Division ohne Rest, dann Z=0, sonst Z=1
; funktion berechnet NICHT das Divisionsergebnis
division
movf _divisor, w
divnext
subwf _dividend, f
btfsc STATUS, Z ;letzte Subtraktion hat Null ergeben
goto divende
btfsc STATUS, C ;letzte Subtraktion hat negativen Wert gebracht
goto divnext
divende return
; funktion lose wird bei verloren aufgerufen
; wird nicht mit call, sondern mit goto aufgerufen
; ausschliesslich aus interrupt-routine verwenden,
; da zurueck in interrupt gesprungen wird
lose
clrf PORTA ; Alle LED aus
movfw TMR0
andlw b'00000111'
movwf delay
bsf STATUS, C
rlf delay, f
; tmr0<3:0> mal schnell blinken
delay_cl nur_gn
movlw 0x20
call pause
nur_rt
movlw 0x20
call pause
decfsz delay, f
goto delay_cl
nur_gn
movlw 0x20
call pause
; langsam langsamer werden
movlw 0x10 ; durch rlf weiter unten wird eigentlich mit 20 begonnen
movwf delay
delay_ll nur_rt
rlf delay, w
call pause
nur_gn
bcf STATUS, C
rlf delay, w
call pause
rlf delay, f
btfss STATUS, C
goto delay_ll
nur_rt
bcf PORTA, 4 ; Auswahl Adresse 00000000 auf Soundchip
nop
bcf PORTB, 7 ; Ton abspielen ausloesen
waitn 5
bsf PORTB, 7 ; Erneutes Abspielen vorbereiten
goto int_done
; funktion win wird bei gewinn aufgerufen
; wird nicht mit call, sondern mit goto aufgerufen
; ausschliesslich aus interrupt-routine verwenden,
; da zurueck in interrupt gesprungen wird
win
clrf PORTA ; Alle LED aus
movfw TMR0
andlw b'00000111'
movwf delay
bsf STATUS, C
rlf delay, f
; tmr0<3:0> mal schnell blinken
delay_cw nur_gn
movlw 0x20
call pause
nur_rt
movlw 0x20
call pause
decfsz delay, f
goto delay_cw
; langsam langsamer werden
movlw 0x10
movwf delay
delay_lw nur_gn
rlf delay, w
call pause
nur_rt
bcf STATUS, C
rlf delay, w
call pause
rlf delay, f
btfss STATUS, C
goto delay_lw
; jetzt gewinn ausgeben
nur_gn
bsf PORTA, 4 ; Auswahl Adresse 01000000 auf Soundchip
nop
bcf PORTB, 7 ; Ton abspielen ausloesen
waitn 5
bsf PORTB, 7 ; Erneutes Abspielen vorbereiten
goto int_done
; ruft pause wait3-mal auf
wait movlw 0x00 ; nicht erschrecken - das bedeutet 256 mal
call pause
decfsz wait3, f
goto wait
return
; Verzoegert W*0xff Takte
; in W steht die Anzahl d. Verzoegerungen
; sollten ca. 1/16 sek sein
pause movwf wait1 ;- Inhalt Arbeitsregister nach wait1 kopieren
pause1 movlw 0xff ;- Kopiere Zahl 255 ins Arbeitsregister
movwf wait2 ;- Inhalt Arbeitsregister nach wait2 kopieren
pause2 nop ;- Taktverzoegerung
decfsz wait2, f ;- dekrementiere, falls wert 0,
; dann ueberspringe naechsten befehl
; dann ueberspringe naechsten befehl
goto pause2 ;- gehe zu label pause2
decfsz wait1, f ;- dekrementiere, falls wert 0,
; dann ueberspringe naeaehsten befehl
goto pause1 ;- gehe zu Label pause1
return ;- zurueck ins Hauptprogramm
; Tabelle mit LED-Werten
table addwf PCL, f
retlw b'0001'
retlw b'0011'
retlw b'0010'
retlw b'0110'
retlw b'0100'
retlw b'1100'
retlw b'1000'
retlw b'1001'
end