| .include "tn13def.inc"
.def temp1 = r16
.def presscount = r17
.def rxptr = r18
.def dosleep = r19
.def pulseoutput = r20
.def temp2 = r21
.def temp3 = r22
.def pulsestatus = r23
.def wrongcount = r24
.def lockcount = r25
.def temp4 = r26
//PB BITs der Funktionespins
.equ OUTPUT = 1
.equ STATUS = 2
.equ TASTER_INTERN = 3
.equ TASTER_EXTERN = 4
//Wartezeit bei überschreiten der Fehlversuche .equ LOCKTIME = 75 //bedeutet ca 75*8 Sekunden
.equ CODELENGTH = 5 //Die Schluessel-Länge, maximal RAM / EEprom Groesse- Stack)
.equ MAX_TRY = 3 //Anzahl der Fehlversuche
.org $0000
rjmp reset
.org WDTAddr
rjmp wdthandler
.org PCI0Addr
rjmp PCIHandler
.org OVF0addr
rjmp OVF0Handler
.org INT_VECTORS_SIZE*2
reset:
//Stack Pointer initialisieren
ldi temp1,low(ramend)
out spl,temp1
//Output und Status-Pins als Ausgang
ldi temp1,(1<<OUTPUT) | (1<<STATUS)
out ddrb,temp1
//Pullups für die Eingaenge anschalten
ldi temp1,0b00111111 ^ ((1<<OUTPUT) | (1<<STATUS))
out portb,temp1
//Timer 0 Interrupt An
ldi temp1,(1<<TOIE0)
out TIMSK0,temp1
//Prescaler sezten und Timer Starten
ldi temp1,0b00000101
out TCCR0B,temp1
//interne Zaehler zurücksetzen
clr presscount
clr rxptr
clr pulseoutput
clr pulsestatus
clr lockcount
clr wrongcount
// Pinchange Interrupt auf externem Taster aktivieren
ldi temp1,(1<<TASTER_EXTERN)
out PCMSK,temp1
ldi temp1,(1<<PCIE)
out GIMSK,temp1
//Semaphore für Sleep loeschen
clr dosleep
//Watchdog init
rcall initwdt
sei
endless:
tst dosleep
brne exec_sleep
//idle
ldi temp1,0b00100000
out MCUCR,temp1
sleep
rjmp endless
exec_sleep: cli
clr presscount
clr rxptr
sbi portb,STATUS
//Pulsieren , dabei wird auch die Sleep-Semaphore wieder geloescht.
delay:
inc dosleep
brne delay
cbi portb,STATUS
//Power Down Modus
ldi temp1,0b00110000
out MCUCR,temp1
sei
sleep
rjmp endless
OVF0Handler:
//Register und Temp1 sichern
in r1,sreg
push temp1
push yl
push yh
tst pulsestatus
breq testpulseout
dec pulsestatus
brne testpulseout
cbi portb,status
testpulseout:
tst pulseoutput
breq testbutton
dec pulseoutput
brne testbutton
cbi portb,OUTPUT
testbutton:
//prüfen, ob taster gedrückt
sbic pinb,TASTER_EXTERN
rjmp releasehandler
//maximal 10 Interrupt-Zyklen lang hochzählen
cpi presscount,$10
breq exitovf0
inc presscount
rjmp exitovf0
// Taster wurde losgelassen
releasehandler:
cpi presscount,$02
brsh valid
//zu kurz gedrückt / entprellung
clr presscount
rjmp exitovf0
valid: ldi temp1,$00
//wenn länger als 8 Zyklen gedrueckt, dann als LANG erkennen
cpi presscount,$05
brlo nolong
inc temp1
//Erkannten Tastendruck im SRAM speichern
nolong: clr presscount
ldi yl,low(rxbuf)
ldi yh,high(rxbuf)
add yl,rxptr
adc yh,presscount
st y,temp1
//Zeiger auf empfangenes Byte erhöhen
inc rxptr
//wenn alle Tastendrücke fertig, dann auswerten
cpi rxptr,CODELENGTH
brne exitovf0
//empfangspointer wieder loeschen
clr rxptr
rcall eval
exitovf0: pop yh
pop yl
pop temp1
out sreg,r1
reti
wdthandler: in r1,sreg
//Sleep-Semaphore setzten
ldi dosleep,$01
//Ausgangssperre herabzaehlen,
tst lockcount
breq exitwdt
dec lockcount
exitwdt:
out sreg,r1
reti
pcihandler: in r1,sreg
wdr
out sreg,r1
reti
//die empfangenen Tastendruecke auswerten
eval: //Wenn alle uebereinstimmen, dann Ausgang aktivieren oder
//wenn onboard-Button gedrueckt, als neuen code abspeichern
sbis pinb,TASTER_INTERN
rjmp setcode
//CODELENGTH aufeinanderfolgende Bytes aus EEPROM lesen und vergleichen
ldi yl,low(rxbuf)
ldi yh,high(rxbuf)
ldi temp2,low(code)
ldi temp4,CODELENGTH
evalloop:
rcall readeeprom
ld temp3,y+
cp temp1,temp3
brne eval_error
dec temp4
brne evalloop
rcall pulse
clr wrongcount
exiteval: rcall status_short
ret
eval_error: inc wrongcount
cpi wrongcount,MAX_TRY
brlo exiteval
ldi lockcount,LOCKTIME
rjmp exiteval
setcode: //code im EEPROM abspeichern
ldi yl,low(rxbuf)
ldi yh,high(rxbuf)
ldi temp4,codelength
ldi temp2,low(code)
writeloop:
ld temp1,y+
rcall writeeeprom
dec temp4
brne writeloop
rcall status_long
ret
initwdt: //watchdog-Interrupt alle 8s
wdr
in temp1,WDTCR
ori temp1,(1<<WDCE) | (1<<WDE)
out WDTCR,temp1
ldi temp1,(1<<WDTIE) | (1<<WDP3) | (1<<WDP0)
out WDTCR,temp1
ret
//Standard-Routinen für eeprom
//der Adresszeiger in TEMP2 wird hier automatisch inkrementiert, da
//dieses Programm sequentiell auf das EEPROM zugreift.
readeeprom:
sbic EECR,EEPE
rjmp readeeprom
out EEARL,temp2
sbi EECR,EERE
in temp1,EEDR
inc temp2
ret
writeeeprom:
sbic EECR,EEPE
rjmp writeeeprom
ldi temp3,(0<<EEPM1)| (0<<EEPM0)
out EECR,temp3
out eearl,temp2
out eedr,temp1
sbi EECR,EEMPE
sbi EECR,EEPE
inc temp2
ret
status_short:
ldi pulsestatus,$02
sbi portb,status
ret
status_long:
ldi pulsestatus,$08
sbi portb,status
ret
pulse: //Ausgang nur dann aktivieren, wenn nicht Ausgangssperre
tst lockcount
brne exit_pulse
//Ausgang aktivieren
sbi pinb,OUTPUT
//wird durch OVF0 wieder abgeschaltet
ldi pulseoutput,$0b
exit_pulse:
ret
.dseg
rxbuf:
.byte CODELENGTH
.eseg
code: .byte CODELENGTH
|