| CODE |
; ************************************ ; Zachary Seto & Jackson Yu ; Final Project - EE476 ; Home Alarm System ; ************************************ ; Port A - Zones ; Port B - LED's ; Port C - Keypad ; Port D - LCD(?) .include "c:\users\z&j\4414def.inc" .device AT90S4414 .def codel =r1;lower two digits of user code .def codeh =r2;upper two digits of user code .def incodel =r3;input code, lower two digits .def incodeh =r4;input code, upper two digits .def lowtemp =r5;lower temp reg .def tempcdl =r6;lower temp code .def tempcdh =r7;upper temp code .def zones =r8;zone fault codes .def temp =r16 ;temporary register .def temp2 =r17 ;temporary register 2 .def savSREG =r18 ;save the status register .def keyraw =r19 ;the raw keyscan code .def key =r20 ;keeps track of what key was pressed .def charcnt =r21 ;keeps track of the number of characters written to the LCD .def wreg =r22 ;temp for delay .def flag =r23 ;generic flag .def audio =r24 ;audio on/off flag and hi/lo tone .def count =r25 ;count for timer0 overflow .equ azero ='0' ;0x30 ascii '0' .equ lcdrs =PD6 ;LCD rs pin connected to PD6 .equ lcdrw =PD5 ;LCD r/w pin connected to PD5 .equ lcde =PD4 ;LCD enable pin connected to PD4 .equ lo =137 ;define low tone: C4 .equ hi =166 ;define hi tone: F4 ;************************************** .cseg .org $0000 rjmp RESET ;reset entry vector reti reti reti reti reti rjmp t1ovfl rjmp t0int reti reti reti reti reti ;analog comparator ;define fixed strings to be tranmitted from flash- zero terminated ready: .db "Ready...",0x00 armed: .db "Armed!!!",0x00 zone: .db "Zone Fault-",0x00 oldcd: .db "Enter Old Code",0x00 newcd1: .db "Enter New Code",0x00 newcd2: .db "Verify New Code",0x00 errorcd:.db "ERROR: Bad Code",0x00 RESET: ldi temp, LOW(RAMEND);setup stack pointer out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp ;initial conditions ser temp ;set PORTB to be out DDRB,temp ;all outputs out PORTB,temp ;turn off all LED's cbi PORTB,6 ldi temp,0b00010101;setup PORTA direction out DDRA,temp ;output to DDRA out PORTA, temp ser audio ;init audio off clr count ;init counter for timer0 ovfl ;init timers ldi temp,0x82 ;setup timer0/1 overflow interrupt out TIMSK,temp ;output to TIMSK ldi temp,0 out TCCR1B,temp;turn off timer1 out TCCR0,temp ;turn off timer0 ;init user code ldi temp,0x35 mov codel,temp ldi temp,0x12 mov codeh,temp sei ;bring up LCD ;power down the LCD cbi PORTB,7 ldi temp,100 ;then Wait 1.5 second with LCD power off ldi temp2,0 ;Delay 15 mS offwait:dec temp brne offwait ;now power up LCD sbi PORTB,7 ldi temp,100 ;Wait 1.5 second for LCD power up ldi temp2,0 ;Delay 15 mS puwait: dec temp brne puwait ;hopefully by now the LCD has rebooted rcall lcdinit ;Initialize LCD module ;send "Ready..." to LCD TOP: rcall lcdclr clr charcnt ldi ZL, LOW(ready<<1) ldi ZH, HIGH(ready<<1) rcall nextc sbi PORTB,0 ;turn on the ready LED cbi PORTB,1 ;turn off armed LED ser flag ;Check for Zone Faults CHECK: rcall zfault ;if faults display trouble zones until ready cpi temp,0xff breq NOFAULT ;output error zones until ready rFAULT: rcall lcdclr clr charcnt ldi ZL, LOW(zone<<1) ;show zone to LCD ldi ZH, HIGH(zone<<1) rcall nextc rcall blink fcont: sbrc zones,1 ;check for zone 1 fault rjmp fcont1 ldi temp,0x31 ;load 1 for LCD output rcall lcdput inc charcnt fcont1: sbrc zones,3 ;check for zone 2 fault rjmp fcont2 cpi charcnt,12 ;check for prev. zone output brlo char2 ldi temp,0x2c ;if so, output comma rcall lcdput inc charcnt char2: ldi temp,0x32 ;load 2 for LCD output rcall lcdput inc charcnt fcont2: sbrc zones,5 ;check for zone 3 fault rjmp fcont3 cpi charcnt,12 ;check for prev. zone output brlo char3 ldi temp,0x2c ;if so, output comma rcall lcdput inc charcnt char3: ldi temp,0x33 ;load 3 for LCD output rcall lcdput inc charcnt fcont3: brtc fcont4 ;check T flag, branch if clear clt sbrs flag,7 ;if flag is clear, turn on led sbi PORTB,0 sbrc flag,7 ;if flag is set, turn off LED cbi PORTB,0 com flag ;switch flag value rcall blink ;setup blink delay again fcont4: mov temp2,zones rcall zfault cpi temp,0xff ;exit if no faults breq TOP cp temp,temp2 breq fcont3 ;keep checking if no change rjmp rFAULT ;rewrite if change NOFAULT:rcall debnce ;Check for programming code cpi key,4 ;'A' button breq PROG0 ;Check for user code (only if no faults) rcall code tst temp brne ARM ;ARM system rjmp CHECK ;if user code, arm system; else back to code scan ARM: rcall lcdclr clr charcnt sbi PORTB,1 cbi PORTB,0 clr flag ldi ZL, LOW(armed<<1) ;send "Armed" to LCD ldi ZH, HIGH(armed<<1) rcall nextc ;check for zone faults ARMPOLL:rcall zfault cpi temp,0xff brne FAULT ;if no faults, check for alarm code rcall debnce ;check for button push tst key breq ARMPOLL rcall code ;if button push, check for code tst temp breq ARMPOLL ;if code, disarm system rjmp TOP PROG0: rjmp PROG ;if fault, alarm, show problem zone(s) ;Zone 1 gives 15 sec. delay, others alarm instantly ;check for user code ;if code, goto ready ;else goto zone FAULT: sbrc zones,1 ;check for zone 1 fault rjmp f1 clt rcall entry ;start 15 sec. entry delay f0: rcall debnce ;check for first button push tst key breq f0a rcall code ;check for correct code input sbrc temp,7 rjmp TOP ;if so, change alarm state to ready f0a: brtc f0 ;if not, check for T flag (timeout) f1: rcall alrmon rcall lcdclr clr charcnt ldi ZL, LOW(zone<<1) ;show zone to LCD ldi ZH, HIGH(zone<<1) rcall nextc sbrc zones,1 ;check for zone 1 fault rjmp f2 ldi temp,0x31 ;load 1 for LCD output rcall lcdput inc charcnt f2: sbrc zones,3 ;check for zone 2 fault rjmp f3 cpi charcnt,12 ;check for prev. zone output brlo fchar2 ldi temp,0x2c ;if so, output comma rcall lcdput inc charcnt fchar2: ldi temp,0x32 ;load 2 for LCD output rcall lcdput inc charcnt f3: sbrc zones,4 ;check for zone 3 fault rjmp f4 cpi charcnt,12 ;check for prev. zone output brlo fchar3 ldi temp,0x2c ;if so, output comma rcall lcdput inc charcnt fchar3: ldi temp,0x33 ;load 3 for LCD output rcall lcdput inc charcnt f4: rcall debnce tst key breq f4 rcall code tst temp breq f4 rcall alrmoff rjmp TOP PROG: ;*********** PROGRAM USER CODE ************* ; enter old user code ; if not user code, goto ready ; if user code... ; enter new user code ; verify new user code ; goto ready rcall lcdclr clr charcnt ldi ZL, LOW(oldcd<<1) ;prompt for old code ldi ZH, HIGH(oldcd<<1) rcall nextc prog1: rcall debnce tst key breq prog1 rcall code tst temp breq ERROR rcall lcdclr clr charcnt ldi ZL, LOW(newcd1<<1) ;prompt for new code ldi ZH, HIGH(newcd1<<1) rcall nextc prog2: rcall debnce tst key breq prog2 rcall code mov tempcdl,incodel ;copy new code mov tempcdh,incodeh rcall lcdclr clr charcnt ldi ZL, LOW(newcd2<<1) ;prompt for new code again ldi ZH, HIGH(newcd2<<1) rcall nextc prog3: rcall debnce tst key breq prog3 rcall code cp incodel,tempcdl ;make sure code was verified brne ERROR cp incodeh,tempcdh brne ERROR mov codel,incodel ;store new code mov codeh,incodeh rjmp TOP ERROR: rcall lcdclr clr charcnt ldi ZL, LOW(errorcd<<1);prompt for new code ldi ZH, HIGH(errorcd<<1) rcall nextc ldi temp,100 ;Delay 1.5 Sec erwait: rcall delay dec temp brne erwait rjmp TOP ;***************************** ;LCD Stuff ;Clear entire LCD lcdclr: ldi temp,1 ;Clear LCD command rcall lcdcmd ret ================================================ ; Initialize LCD module lcdinit:ldi temp,0 ;Setup port pins out PORTD,temp ;Pull all pins low ldi temp,0xff ;All pins are outputs out DDRD,temp rcall delay ; LCD specs call for 3 repetitions as follows ldi temp,3 ;Function set out PORTD,temp ;to 8-bit mode nop ;nop is data setup time sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde rcall delay ldi temp,3 ;Function set out PORTD,temp nop sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde rcall delay ldi temp,3 ;Function set out PORTD,temp nop sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde rcall delay ldi temp,2 ;Function set, 4 line interface out PORTD,temp nop ; rcall strobe ;Toggle enable line sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi temp,0b11110000;Make 4 data lines inputs out DDRD,temp ; Finally, ; At this point, the normal 4 wire command routine can be used ldi temp,0b00100000;Function set, 4 wire, 1 line, 5x7 font rcall lcdcmd ldi temp,0b00001100;Display on, no cursor, no blink rcall lcdcmd ldi temp,0b00000110;Address increment, no scrolling rcall lcdcmd ret ============================================ ; Wait for LCD to go unbusy lcdwait:ldi temp,0xF0 ;Make 4 data lines inputs out DDRD,temp sbi PORTD,lcdrw ;Set r/w pin to read cbi PORTD,lcdrs ;Set register select to command waitloop: sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde in wreg,PIND ;Read busy flag ;Read, and ignore lower nibble sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde sbrc wreg,3 ;Loop until done rjmp waitloop ret ============================================= ; Send command in temp to LCD lcdcmd: push temp ;Save character rcall lcdwait ;Wait for LCD to be ready ldi temp,0xFF ;Make all port D pins outputs out DDRD,temp pop temp ;Get character back push temp ;Save another copy swap temp ;Get upper nibble andi temp,0x0F ;Strip off upper bits out PORTD,temp ;Put on port nop ;wait for data setup time sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde pop temp ;Recall character andi temp,0x0F ;Strip off upper bits out PORTD,temp ;Put on port nop sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ldi temp,0xF0 ;Make 4 data lines inputs out DDRD,temp ret ============================================= ;Send character data in temp to LCD lcdput: push temp ;Save character rcall lcdwait ;Wait for LCD to be ready ldi temp,0xFF ;Make all port D pins outputs out DDRD,temp pop temp ;Get character back push temp ;Save another copy swap temp ;Get upper nibble andi temp,0x0F ;Strip off upper bits out PORTD,temp ;Put on port sbi PORTD,lcdrs ;Register select set for data nop sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde pop temp ;Recall character andi temp,0x0F ;Strip off upper bits out PORTD,temp ;Put on port sbi PORTD,lcdrs ;Register select set for data nop sbi PORTD,lcde ;Toggle enable line cbi PORTD,lcde ;cbi PORTD,lcdrs ;-- ldi temp,0xF0 ;Make 4 data lines inputs out DDRD,temp ret nextc: lpm ;Get next character from ROM tst R0 ;See if at end of message breq end1 ;If so, next message cpi charcnt,8 ;addressing changes at char #8! brne wrtit ;at char 8, fix it ldi temp,0xC0 ;Set address to last 8 chars rcall lcdcmd wrtit: mov temp,R0 ;Send it to the LCD rcall lcdput adiw ZL,1 ;Increment Z-pointer inc charcnt ;keep track of chars on display rjmp nextc ;Loop for more end1: ret ;***** Delay 15 milliseconds using timer 1 delay: in wreg,SREG ;Save status register push wreg clt ;Clear T ldi temp2,0xff ;preload timer1 out TCNT1H,temp2 ;write high part of timer1 ldi temp2,0x15 ;preload timer1 out TCNT1L,temp2 ;write low part of timer1 ldi wreg,4 ;Timer 1 prescaler, CK / 256 out TCCR1B,wreg dwait: brtc dwait ;Wait for timer 0 interrupt to set T pop wreg ;Restore status register out SREG,wreg ret ;***************************** ;keypad polling routine ;keypad on PORTC keytbl: .db 0b11101110, 0b11101101, 0b11101011, 0b11100111 .db 0b11011110, 0b11011101, 0b11011011, 0b11010111 .db 0b10111110, 0b10111101, 0b10111011, 0b10110111 .db 0b01111110, 0b01111101, 0b01001011, 0b01110111 KeyPoll:ldi temp, 0x0f out DDRC, temp ldi temp, 0xf0 out PORTC, temp nop nop nop nop in temp, PINC mov keyraw,temp ldi temp, 0xf0 out DDRC, temp ldi temp, 0x0f out PORTC, temp nop nop nop nop in temp, PINC or keyraw, temp ldi ZL, low(keytbl*2) ldi ZH, high(keytbl*2) ldi key, 0 tbllp: lpm cp keyraw, r0 breq foundit inc key cpi key, 0x10 breq illegal adiw ZL, 1 rjmp tbllp foundit:subi key, -1 ret illegal:clr key ret debnce: clr key ;clear the key pressed variable rcall KeyPoll ;check for button push tst key breq nokey ;if no button, exit mov lowtemp,key;store first key read rcall delay ;wait 15ms rcall delay ;wait 15ms rcall KeyPoll ;wait for button still push cp key,lowtemp;check to see that the same button was still pushed brne nokey rcall delay ;wait 15ms rcall delay ;wait 15ms hold: rcall KeyPoll tst key brne hold mov key,lowtemp;restore key ret nokey: ldi key,0 ;clear key ret ;************************ ; Check for Zone Fault zfault: in temp,PINA ;get pin values com temp ori temp,0b11010101 ;set the output to 1's, zone bits 0 if fault ;bit 1 = Zone 1, bit 3 = Zone 2, bit 5 = Zone 3 mov zones,temp ret code: ;assume that the first key is preloaded in key ;rcall debnce ;setup first digit tst key breq NOCODE swap key mov incodeh,key code1: rcall debnce ;setup second digit tst key breq code1 or incodeh,key code2: rcall debnce ;setup third digit tst key breq code2 swap key mov incodel,key code3: rcall debnce ;setup fourth digit tst key breq code3 or incodel,key cp incodeh,codeh ;compare upper two digits brne NOCODE cp incodel,codel ;compare lower two digits brne NOCODE ser temp ;set for correct code ret NOCODE: clr temp ;clear for incorrect code ret ;***** Delay 15 seconds using timer 1 entry: in wreg,SREG ;Save status register ldi temp2,0x1B ;preload timer 1 to 6941 out TCNT1H,temp2 ldi temp2,0x1D ;preload timer 1 to 6941 out TCNT1L,temp2 clt ;Clear T ldi temp2,5 ;Timer 0 prescaler, CK / 1024 out TCCR1B,temp2 ;Run timer out SREG,wreg ret ;***** Delay 1 sec using timer 1 blink: in wreg,SREG ;Save status register ldi temp2,0xf8 ;preload timer 1 to 61629 out TCNT1H,temp2 ldi temp2,0x5e ;preload timer 1 to 61629 out TCNT1L,temp2 clt ldi temp2,5 ;Timer 1 prescaler, CK / 1024 out TCCR1B,temp2 ;Run timer out SREG,wreg ret ;***** Timer 0 overflow interrupt handler t0int: in savSREG,SREG ;save the status reg ldi wreg,0xf0 ;load xor value eor audio,wreg ;toggle audio output sbrs audio,7 ;if flag is clear, turn on audio sbi PORTB,6 sbrc audio,7 ;if flag is set, turn off audio cbi PORTB,6 sbrc audio,3 ;check for hi flag ldi wreg,hi ;reload the timer with hi sbrs audio,3 ;check for lo flag ldi wreg,lo ;reload the timer with lo out TCNT0,wreg cpi count,90 ;~.25 sec brlo tcont clr count ldi wreg,0x0f ;load xor value eor audio,wreg ;toggle hi/lo tone tcont: inc count ;increment the duration counter out SREG,savSREG ;restore status reg reti ;return from ISR ;***** Timer 1 overflow interrupt handler t1ovfl: ldi wreg,0 ;turn off Timer 1 out TCCR0,wreg set reti ;***** Start alarm tones alrmon: ldi temp,3 ;prescale timer by 64 out TCCR0,temp ;turn on timer0 ori audio,0xf0 ;turn on audio ret ;***** Stop alarm tones alrmoff:ldi temp,0 out TCCR0,temp ;turn off timer0 andi audio,0x0f ;turn off audio ret |