| CODE |
;;*************************************** ;;* Ji Bae & Clifford Lim ;;* Monday Afternoon Lab ;;* Final Project ;;* Hi-Tek Car Alarm ;;* Port A - LED outputs ;;* Port D - RS232 interface ;;* Port C - Inputs from Triggers and Sensors and Siren Output ;;* Port B - Inputs from Push Buttons ;;*************************************** ;.include "c:\users\ji&cliff\4414def.inc" .include "c:\avrtools\appnotes\4414def.inc" .device AT90S4414 .def EEdrd =r0;EEprom read data .def count30 =r1;30 second count .def savSREG =r2;save the status register .def reload =r3;reload for timer 1 .def sensmem =r15;trigger memory .def temp =r16;temporary register .def uconfig =r17;user config options from EEprom .def TXbusy =r18;transmit busy flag .def RXchar =r19;a received character .def TXflash =r20;text to be sent is in flash if <>0 .def state =r21;state of the alarm .def LED =r22;LED pattern .def count =r23;counter for interrupts .def sensors =r24;input triggers/sensors .def press =r25;press register .def dbstate =r26;debounce state register .def lock =r27;register flag which simulates lock -- temporary .def wreg =r28;working register .def EEdwr =r29;data for write to EEprom .def EEaddr =r31;address for EEprom r/w .equ baud96 =25;9600 baud constant for 4Mhz crystal .equ go ='p' ;0x67 ascii 'p' .equ one ='1' .equ two ='2' .equ three ='3' .equ stop ='s';0x73 ascii 's' .equ azero ='0';0x30 ascii '0' .equ button3 =0xf7;button 3 pressed -- program button .equ button2 =0xfb;button 2 pressed -- panic button .equ button1 =0xfd;button 1 pressed -- valet button .equ button0 =0xfe;button 0 pressed -- arm/disarm button .equ arm = 0;states for alarm operation .equ disarm = 1 .equ panic = 2 .equ valet = 3 .equ active = 4 .equ program = 5 .equ st0 = 0;states for push button debouncing .equ st1 = 1 .equ st2 = 2 .equ st3 = 3 .equ sec1 = 2;30 second duration .equ sec2 = 4;60 second duration ;masks for user config eeprom settings .equ sdur = 0x01;siren duration .equ aarm = 0x02;auto arm/lock .equ chirp = 0x04;quiet chirp .cseg .org $0000 rjmp RESET;reset entry vector reti reti reti reti reti rjmp t1ovfl;Timer 1 overflow - used for timing rjmp t0ovfl;Timer 0 overflow - used for LED reti rjmp RXdone;UART receive done rjmp TXempty;UART buffer empty rjmp TXdone;UART transmit done reti ;define fixed strings to be tranmitted from flash- zero terminated text1: .db "Program mode",0x0d, 0x0a, 0x00 crlf: .db 0x0d, 0x0a, 0x00 ;carrage return/line feed menu1: .db "1) Siren Duration 30/60",0x0d, 0x0a, 0x00 menu2: .db "2) Auto Arm/Lock toggle",0x0d, 0x0a, 0x00 menu3: .db "3) Quiet Chirp",0x0d, 0x0a, 0x00 menu4: .db "p) Quit",0x0d, 0x0a, 0x00 menu5: .db "Make your choice (1,2,3,p): ",0x0d, 0x0a, 0x00 resp1: .db "*** Siren duration = 30",0x0d, 0x0a, 0x00 resp2: .db "*** Siren duration = 60",0x0d, 0x0a, 0x00 resp3: .db "*** Enabled",0x0d, 0x0a, 0x00 resp4: .db "*** Disabled",0x0d, 0x0a, 0x00 resp5: .db "*** Quit",0x0d, 0x0a, 0x00 RESET: ldi temp, LOW(RAMEND);setup stack pointer out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp;initial conditions clr TXbusy ;start out not busy on TX ldi RXchar, stop;start out stoped ;setup UART -- enable TXempty & RXdone int, and RX, TX pins ldi temp, 0b10111000 out UCR, temp ;set baud rate to 9600 ldi temp, baud96 out UBRR, temp ;intialize text pointer BEFORE turning on interrupts ;because RESET causes the TX empty flag to be SET ldi ZL, LOW(crlf<<1);do shift to convert word-addr to byte ldi ZH, HIGH(crlf<<1) ;turn on Timer 0 and Timer 1 overflow interrupts ldi temp, 0b10000010 out TIMSK, temp ;setup timer stuff clr temp ;turn off timer 0 out TCCR0, temp ldi count, 4 ;setup LED blink rate clr temp out TCCR1B, temp ;turn off timer 1 set ;set T bit ;setup ports ser temp ;set Port A all output out DDRA, temp out PORTA, temp ;all LED off initially clr temp out DDRB,temp ;Set Port B all input - push buttons ser temp out PORTB,temp ;set Port B to pullups ldi temp, 0xf0 ;set upper byte to output, lower byte to input out DDRC, temp ;set Port C ldi temp,0x0F out PORTC, temp ser temp ;set Port D to all output out DDRD, temp out PORTD, temp ;set Port D to High clr sensmem ldi EEaddr,0x02 rcall EERead mov state, EEdrd ;load last state stored in EEPROM ldi dbstate, st0 ;initialize keyboard debounce ldi EEaddr,0x01 rcall EERead mov uconfig, EEdrd ;load user config from EEprom ldi temp, sdur ;setup siren duration and temp, uconfig cpi temp, sdur ;determine specified duration breq siren60 ldi temp,sec1 ;30 second duration rjmp rel siren60:ldi temp,sec2 ;60 second duration rel: mov reload, temp mov count30,reload sei main: cpi state, arm ;main program is a state machine breq a ;armed state cpi state, disarm breq dbrch ;disarm state cpi state, active breq actbrch ;active state cpi state, panic breq pbrch ;panic state cpi state, valet breq vbrch ;valet state cpi state, program breq prbrch ;program state error: com state ;error state out PORTA,state rjmp main ;rjmps because branches out of reach prbrch: rjmp prog dbrch: rjmp d pbrch: rjmp p actbrch:rjmp act vbrch: rjmp v ;armed state a: ser temp out PORTA,temp;clear all LED's ldi temp, 5 ;turn on timer 0 clk/1024 out TCCR0, temp;blink LED cbi PORTA,0 ;lock doors guard: rcall stenter ;poll for button press cpi press, button0 breq to_d cpi press, button1 breq to_v cpi press, button2 breq to_p in sensors,PINC;check for trigger andi sensors,0x0F cpi sensors, 0x0F breq guard ldi state, active;go active if triggered mov sensmem,sensors;store event com sensmem ;reorder sensmem ldi temp,0x0F and sensmem, temp;only look at lower byte ldi EEaddr,0x02;save state in EEprom mov EEdwr,state rcall EEWrite set ;set T bit for timing purposes rjmp main ;go to main prog to_v: ldi state, valet;load valet state ldi EEaddr,0x02 mov EEdwr,state rcall EEWrite ;save state in EEprom clr temp ;reset Timer 1/Turn Off out TCCR1B,temp out TCNT1H,temp out TCNT1L,temp rcall SChirp ;siren chirp rcall WChirp ;delay between chirps rcall SChirp rcall WChirp rcall SChirp rcall WChirp rcall SChirp rjmp main ;go to main prog to_p: ldi state, panic;load panic state ldi EEaddr,0x02 mov EEdwr,state rcall EEWrite ;save state in EEprom clr temp ;reset Timer 1/Turn Off out TCCR1B,temp out TCNT1H,temp out TCNT1L,temp rjmp main ;go to main prog to_a: ldi state, arm;load armed state ldi EEaddr,0x02 mov EEdwr,state rcall EEWrite ;save state in EEprom clr temp ;reset Timer 1/Turn Off out TCCR1B,temp out TCNT1H,temp out TCNT1L,temp rcall SChirp ;siren chirp rcall WChirp ;delay between chirps rcall SChirp rjmp main to_d: set ;set T bit cbi PORTC, 4;turn off siren ldi state, disarm;load disarmed state ldi EEaddr,0x02 mov EEdwr,state rcall EEWrite ;save state in EEprom clr temp ;reset Timer 1 out TCNT1H,temp out TCNT1L,temp rcall SChirp ;siren chirp rjmp main ;disarmed state d: sbi PORTA, 6 clr temp ;turn off timer 0 out TCCR0, temp tst sensmem ;check if trigger while away breq nosens ;else chirp three times rcall WChirp rcall SChirp rcall WChirp rcall SChirp clr sensmem nosens: sbrs uconfig,1;check for auto arm/lock enable rjmp aarmoff ldi temp,5 out TCCR1B,temp;timer1 clk/1024 in sensors,PINC;check for trigger andi sensors,0x0F cpi sensors, 0x0F;check for open trigger brne open ;don't auto arm if trigger present brtc to_a2 ;auto arm/lock rjmp aarmoff open: set ;reset auto/arm if trigger present clr temp out TCNT1H,temp;reset Timer 1 out TCNT1L,temp aarmoff:sbi PORTA,7 sbi PORTA,0 ;unlock doors cbi PORTA,1 ;show disarm state on LED's rcall stenter ;poll for button press, go to appropriate state cpi press, button0 breq to_a cpi press, button1 breq to_v2 cpi press, button2 breq to_p2 rjmp nosens to_v2: rjmp to_v to_p2: rjmp to_p ;active state act: clr temp ;turn off timer 0 out TCCR0, temp ldi temp, 0x05 out TCCR1B, temp;turn on timer 1 clk/1024 sbi PORTA, 7 sbi PORTC, 4;turn on siren/strobe act2: rcall stenter ;poll for button press cpi press, button0;look for disarm breq to_d ;turn off if disarm button press brtc to_a2 ;turn off after specified siren duration rjmp act2 to_a2: cbi PORTC,4 ;turn off siren/strobe ldi state, arm;load arm state ldi EEaddr,0x02 mov EEdwr,state rcall EEWrite ;save state in EEprom clr temp ;reset Timer 1 out TCCR1B,temp out TCNT1H,temp out TCNT1L,temp rjmp main ;go back to main prog ;panic state p: clr temp ;turn off timer 0 out TCCR0, temp sbi PORTA, 7 cbi PORTA, 6;turn on siren/strobe sbi PORTC,4 ;turn on siren cpi lock,0 ;toggle locks breq lockit2 sbi PORTA,0 clr lock rjmp p2 lockit2:cbi PORTA,0 ser lock p2: rcall stenter ;poll for button press cpi press, button0;look for disarm button press breq to_d2 rjmp p2 to_d2: rjmp to_d ;valet state v: clr temp ;turn off timer 0 out TCCR0, temp cbi PORTA,7 ;constant LED light sbi PORTA,1 ;clear other LED rcall stenter ;poll for button press cpi press, button0;toggle lock on arm/disarm button press breq toggle cpi press, button1;get out of valet and go to disarm breq to_d3 cpi press, button3;go to program state breq to_prog rjmp v toggle: cpi lock,0 ;toggle lock upon disarm/arm button press breq lockit sbi PORTA,0 clr lock rjmp v lockit: cbi PORTA,0 ser lock rjmp v to_d3: rjmp to_d to_prog:ldi state, program;load program state ldi temp, valet;store valet state in case of error ldi EEaddr,0x02;store state in EEprom mov EEdwr,temp rcall EEWrite ldi EEaddr,0x01;store user config settings mov EEdwr,uconfig rcall EEWrite rjmp main ;go back to main prog stenter:cpi dbstate,st0;debounce state machine table for push buttons breq _st0 cpi dbstate,st1 breq _st1 cpi dbstate,st2 breq _st2 cpi dbstate,st3 breq _st3 dberror:rjmp dberror _st0: in temp, PINB;load input values cpi temp, 0xFF;check for any button presses breq _st0no ;if no press, return to itself ldi dbstate,st1;go to next state mov press,temp;move button value into press register _st0no: ret _st1: in temp,PINB;if current button doesn't equal last button pressed cp temp,press brne _st1no ;go back to state 0 ldi dbstate,st2;else go to state 2 rjmp stenter _st1no: ldi dbstate,st0;load state for state 0 ser press ret _st2: in temp,PINB;if current button equals last button pressed cp temp,press breq _st2yes ;go back to itself ldi dbstate,st3;else go to state 3 _st2yes:rjmp stenter _st3: in temp,PINB;if current button equals last button pressed cp temp,press breq _st3yes ;go back to state 2 ldi dbstate,st0;else return to state 0 ser press ret _st3yes:ldi dbstate,st2;load state for state 2 rjmp stenter to_val2:rjmp to_val ;Program state ;wait for 'p' to start programming prog: ser temp out PORTA,temp;clear all LED's to signal program mode rcall stenter ;poll for button press cpi press, button3;toggle program mode breq to_val2 ;jump back to disarm state if button pressed cpi RXchar, go;wait for go signal - a 'p' on the keyboard brne prog msg: ldi RXchar,stop;reset RXchar - run once and wait ;set up the transmit pointer for the first message ldi ZL, LOW(text1<<1) ;shifted becuase pgm memory is words ldi ZH, HIGH(text1<<1); lpm ;put the char in r0 out UDR, r0 ;put the character in the UART buffer ser TXflash ;string is in flash memory ser TXbusy ;and set the TX busy flag sbi UCR, UDRIE;enable the TXempty interrupt rcall TXwait ;chill until done ldi ZL, LOW(menu1<<1) ;shifted becuase pgm memory is words ldi ZH, HIGH(menu1<<1); lpm ;put the char in r0 out UDR, r0 ;put the character in the UART buffer ser TXflash ;string is in flash memory ser TXbusy ;and set the TX busy flag sbi UCR, UDRIE;enable the TXempty interrupt rcall TXwait ;chill until done ldi ZL, LOW(menu2<<1) ;shifted becuase pgm memory is words ldi ZH, HIGH(menu2<<1); lpm ;put the char in r0 out UDR, r0 ;put the character in the UART buffer ser TXflash ;string is in flash memory ser TXbusy ;and set the TX busy flag sbi UCR, UDRIE;enable the TXempty interrupt rcall TXwait ;chill until done ldi ZL, LOW(menu3<<1) ;shifted becuase pgm memory is words ldi ZH, HIGH(menu3<<1); lpm ;put the char in r0 out UDR, r0 ;put the character in the UART buffer ser TXflash ;string is in flash memory ser TXbusy ;and set the TX busy flag sbi UCR, UDRIE;enable the TXempty interrupt rcall TXwait ;chill until done ldi ZL, LOW(menu4<<1) ;shifted becuase pgm memory is words ldi ZH, HIGH(menu4<<1); lpm ;put the char in r0 out UDR, r0 ;put the character in the UART buffer ser TXflash ;string is in flash memory ser TXbusy ;and set the TX busy flag sbi UCR, UDRIE;enable the TXempty interrupt rcall TXwait ;chill until done ldi ZL, LOW(menu5<<1) ;shifted becuase pgm memory is words ldi ZH, HIGH(menu5<<1); lpm ;put the char in r0 out UDR, r0 ;put the character in the UART buffer ser TXflash ;string is in flash memory ser TXbusy ;and set the TX busy flag sbi UCR, UDRIE;enable the TXempty interrupt rcall TXwait ;chill until done ;wait for input to change settings prog2: cpi RXchar, one;siren duration breq m1 cpi RXchar, two;auto arm/lock breq m2 cpi RXchar, three;quiet chirp breq m3 cpi RXchar, go;quit breq quit rjmp prog2 ;rjmp to fix branch out of reach m1_br: rjmp m1 m2_br: rjmp m2 m3_br: rjmp m3 to_val: ldi EEaddr,0x01;store user config in EEprom mov EEdwr,uconfig rcall EEWrite ldi state, valet;load valet state ldi EEaddr,0x02 mov EEdwr,state rcall EEWrite ;store state in EEprom clr temp ;reset Timer 1/Turn off out TCCR1B,temp out TCNT1H,temp out TCNT1L,temp rjmp main ;go back to main program quit: ldi ZL, LOW(resp5<<1) ;ptr to RAM ldi ZH, HIGH(resp5<<1) lpm ;put the char in r0 out UDR, r0 ;put the character in the UART buffer ser TXflash ;string is in flash memory ser TXbusy ;and set the TX busy flag sbi UCR, UDRIE;enable the TXempty interrupt rcall TXwait ;chill until done ldi RXchar, stop ldi temp, sdur ;setup siren duration and temp, uconfig cpi temp, sdur ;determine specified duration breq s6 ldi temp,sec1 ;30 second duration rjmp rel2 s6: ldi temp,sec2 ;60 second duration rel2: mov reload, temp mov count30,reload rjmp to_val ;exit into valet mode m1: ldi temp, sdur eor uconfig, temp sbrc uconfig, 0 rjmp sixty rjmp thirty m2: ldi temp, aarm eor uconfig, temp sbrc uconfig, 1 rjmp yes rjmp no m3: ldi temp, chirp eor uconfig, temp sbrc uconfig, 2 rjmp yes rjmp no yes: ldi ZL, LOW(resp3<<1) ;ptr to RAM ldi ZH, HIGH(resp3<<1) lpm ;put the char in r0 out UDR, r0 ;put the character in the UART buffer ser TXflash ;string is in flash memory ser TXbusy ;and set the TX busy flag sbi UCR, UDRIE;enable the TXempty interrupt rcall TXwait ;chill until done rjmp msg no: ldi ZL, LOW(resp4<<1) ;ptr to RAM ldi ZH, HIGH(resp4<<1) lpm ;put the char in r0 out UDR, r0 ;put the character in the UART buffer ser TXflash ;string is in flash memory ser TXbusy ;and set the TX busy flag sbi UCR, UDRIE;enable the TXempty interrupt rcall TXwait ;chill until done rjmp msg thirty: ldi ZL, LOW(resp1<<1) ;ptr to RAM ldi ZH, HIGH(resp1<<1) lpm ;put the char in r0 out UDR, r0 ;put the character in the UART buffer ser TXflash ;string is in flash memory ser TXbusy ;and set the TX busy flag sbi UCR, UDRIE;enable the TXempty interrupt rcall TXwait ;chill until done rjmp msg sixty: ldi ZL, LOW(resp2<<1) ;ptr to RAM ldi ZH, HIGH(resp2<<1) lpm ;put the char in r0 out UDR, r0 ;put the character in the UART buffer ser TXflash ;string is in flash memory ser TXbusy ;and set the TX busy flag sbi UCR, UDRIE;enable the TXempty interrupt rcall TXwait ;chill until done rjmp msg ;***************************** ;interrupt routines ; UART needs a character TXempty:in savSREG, SREG;save processor status tst TXflash ;Is the string in flash memory? breq TXram ;If not, it is in RAM inc ZL ;get the next char from flash lpm ;and put it in r0 rjmp TXfls TXram: inc ZL ;get the next char from RAM ld r0,Z TXfls: tst r0 ;if char is zero then exit breq TXend out UDR, r0 ;otherwise transmit it rjmp TXexit ;exit until next char TXend: clr TXbusy ;no more chars cbi UCR, UDRIE;clear the TXempty interrupt TXexit: out SREG, savSREG;restore proc status reti ;back to pgm ;TX done -- buffer is empty -- unused here TXdone: in savSREG, SREG;save processor status out SREG, savSREG;restore proc status reti ;back to pgm ;UART read a character RXdone: in savSREG, SREG;save processor status in RXchar, UDR ;get the character out SREG, savSREG;restore proc status reti ;back to pgm ;T0overflow interrupt used for LED output t0ovfl: in savSREG, SREG;save processor status dec count brne wait ldi wreg,0b10000000 in LED, PORTA ;get LED pattern eor LED, wreg ;invert current LED Pattern out PORTA, LED ;output LED pattern ldi count, 8 ;reset counter wait: ldi wreg, 6 out TCNT0,wreg ;Reset Counter to 6 out SREG, savSREG;restore proc status reti ;back to pgm t1ovfl: dec count30 brne wait2 clt ;clear T bit mov count30,reload;reload counter clr wreg out TCCR1B,wreg;turn off timer 1 wait2: clr wreg out TCNT1H,wreg out TCNT1L,wreg reti ;back to pgm ;***************************** ;subroutine TXwait: tst TXbusy ;now wait for the tranmission to finish brne TXwait ret ;eeprom write subroutine EEWrite:sbic EECR,EEWE;if EEWE not clear rjmp EEWrite ; wait more out EEAR,EEaddr;output address out EEDR,EEdwr;output data sbi EECR,EEMWE;set master write enable sbi EECR,EEWE;set EEPROM Write strobe ;This instruction takes 4 clock cycles since ;it halts the CPU for two clock cycles ret ;eeprom read subroutine EERead: sbic EECR,EEWE;if EEWE not clear rjmp EERead ; wait more out EEAR,EEaddr;output address sbi EECR,EERE;set EEPROM Read strobe ;This instruction takes 4 clock cycles since ;it halts the CPU for two clock cycles in EEdrd,EEDR;get data ret ;single siren chirp routine SChirp: ldi temp,0x4E out TCNT1H,temp ldi temp,0x20 out TCNT1L,temp sbrs uconfig, 2;determine quiet chirp settings, on = skip sbi PORTC, 4;turn on siren set ldi temp,1 mov count30,temp ldi temp,2 out TCCR1B,temp loop: brts loop set cbi PORTC, 4 ret ;silent chirp pause delay Wchirp: ldi temp,0x4E out TCNT1H,temp ldi temp,0x20 out TCNT1L,temp cbi PORTC,4 set ldi temp,1 mov count30,temp ldi temp,2 out TCCR1B,temp tloop: brts tloop set ret ;------------------- EEPROM LISTING --------------- .include "c:\avrtools\appnotes\4414def.inc" .device AT90S4414 .eseg eevar: .db 0x00,0x02,0x01 |