;******************************************** ; ; Security Entrance System ; ; Abram Connelly and Matt Harren ; EE 476 Spring '00 ; ;******************************************** .nolist .include "c:\avrtools\appnotes\8535def.inc" .list ;portC for keyboard ;portD for magno card: d5 data, d6 clock, d7 card detect ;portA for lcd ;portB for LEDS .equ READER =Pind .def save =r1 .def RXready =r4 .def eepin =r5 .def char =r6 .def reload =r7 .def failedattempt =r8 .def buttnum =r9 .def lcdcharcnt =r10 .def lcdstat =r11 .def usertemp =r12 .def temp =r16 .def mainstate =r17 .def TXbusy =r18 .def RXchar =r19 .def bitnum =r20 .def TXflash =r21 .def flash =r21 .def perm =r21 ;permissions level of user .def curnum =r22 .def newperm =r22 ;new permissions level of user, as selected by an administrator .def tblpos =r23 .def mode =r24 .def key =r24 ;saved before use .def timeout =r25 .def ssread =r26 ;start sentinel read yet? ;r28 thru r31 reserved for z and y. ;EEPROM access temps. Saved before use .def chrctr =r22 .def IDctr =r23 .def match =r24 ;***********temporary ;.def charcnt =r18 ;Char position on the display ;.def chr =r19 ;a variable character to print ;******************** .equ baud96 =25 .equ asciizero ='0' .equ Deleted =0 ;permissions levels. Should be numbered by increasing power .equ Disabled =1 ; (i.e. everyone with permission >= Access will get access) .equ Access =2 .equ Admin =3 .equ maxIDs =60 ;******lcd stuff .equ lcdrs =Pa6 .equ lcdrw =Pa5 .equ lcde =Pa4 .equ lcdoutput =porta .equ lcdinput =pina .equ lcdcontrol =ddra ;******kb .equ kboutput =portc .equ kbinput =pinc .equ kbcontrol =ddrc ;******states .equ wait4clockHigh =3 ;wait for rising edge .equ nocard =4 ;if no card, print data, lookup in EEPROM .equ carddetect =7 ;test card detect bit .equ clock =6 ;wait for falling edge of clock .equ data =5 ;test for the first '1' .equ fullchar =0 ;read a bit of data .equ sstest =1 ;test if already seen ss .equ indb =2 ;test if card is in database .equ sysadmin =8 ;test if the user is a sysadmin .equ getNewPerm =9 ;wait for administrator to specify new permissions label .equ writeID =10 ;add card to DB, or modify existing entry ;******modes .equ normal =1 ;normal, lockdown, and learn modes .equ learn =3 .equ lockdown =2 ;*******door etc. .equ accessLED =6 ;output pins on port B(active low) .equ alarmLED =7 .equ maxattempts =3 .macro lcdprintflash rcall lcdclr push zl push zh push flash ldi zl, low(@0<<1) ldi zh, high(@0<<1) ser flash rcall lcdputstring pop flash pop zh pop zl .endmacro .macro lcdprintram push zl push zh push flash ldi zl, low(@0) ldi zh, high(@0) clr flash rcall lcdputstring pop flash pop zh pop zl .endmacro .macro flashprint cli push zl push zh push txflash push txbusy push r0 ;make sure to disable the timer1 isr in case ; it hasn't finished flashprintbrief in temp, timsk andi temp, ~exp2(toie1) out timsk, temp sei ldi zl, low(@0<<1) ldi zh, high(@0<<1) ser flash rcall lcdputstring ldi zl, low(@0<<1) ldi zh, high(@0<<1) lpm out udr, r0 ser txflash ser txbusy sbi ucr, udrie rcall txwait ldi zl, low(CRLF<<1) ldi zh, high(CRLF<<1) lpm out udr, r0 ser txflash ser txbusy sbi ucr, udrie rcall txwait pop r0 pop txbusy pop txflash pop zh pop zl .endmacro .macro flashprintbrief push zl push zh push txflash push txbusy push r0 ldi zl, low(@0<<1) ldi zh, high(@0<<1) ser flash rcall lcdputstring ldi zl, low(@0<<1) ldi zh, high(@0<<1) lpm out udr, r0 ser txflash ser txbusy sbi ucr, udrie rcall txwait ldi zl, low(CRLF<<1) ldi zh, high(CRLF<<1) lpm out udr, r0 ser txflash ser txbusy sbi ucr, udrie rcall txwait cli clr temp out tcnt1h, temp out tcnt1l, temp in temp, tifr ori temp, exp2(tov1) out tifr, temp in temp, timsk ori temp, exp2(toie1) out timsk, temp sei pop r0 pop txbusy pop txflash pop zh pop zl .endmacro .macro ramprint push zl push zh push txflash push txbusy ldi zl, low(@0) ldi zh, high(@0) ld r0, z out udr, r0 clr txflash ser txbusy sbi ucr, udrie rcall txwait pop txbusy pop txflash pop zh pop zl .endmacro .MACRO getkey cli push temp push zl push zh push key push r0 ldi temp, 0x0f out kbcontrol, temp ldi temp, 0xf0 out kboutput, temp nop nop nop nop nop nop nop nop in temp, kbinput mov key, temp ldi temp, 0xf0 out kbcontrol, temp ldi temp, 0x0f out kboutput, temp nop nop nop nop nop nop nop nop in temp, kbinput or key, temp ; ldi temp, 0xff ; out ddrb, temp ; mov temp, key ; com temp ; out portb, key ldi zl, low(keytbl<<1) ldi zh, high(keytbl<<1) ldi temp, 0 tbllp: lpm cp key, r0 breq tbldone inc temp cpi temp, 12 breq tbldone adiw zl, 1 rjmp tbllp tbldone: mov @0, temp pop r0 pop key pop zh pop zl pop temp sei .ENDMACRO .dseg tempbuffer: .byte 4 table: .byte 100 .eseg database: .db "384533", Admin, 0x0 ;Matt has permission "Admin" ;60 empty locations .db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 .db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 .db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 .db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 .db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 .db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 .db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 .db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 .db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 .db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 .db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 .db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 .db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 .db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 .db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 numusers: .db 1 .cseg .org $0000 rjmp reset ;reset reti ;irq0 reti ;irq1 reti ;timer2 compare reti ;timer2 overflow reti ;timer1 capt reti ;timer1a reti ;timer1b rjmp timer1 ;timer1 overflow rjmp timer0 ;timer0 overflow reti ;spi transfer complete rjmp RXdone ;uart rx rjmp TXempty ;udr empty rjmp TXdone ;uart tx complete reti ;ADC complete reti ;EEPROM ready reti ;analog comparitor reset: ldi temp, low(ramend) out spl, temp ldi temp, high(ramend) out sph, temp ;initialize timer0 for 1mSec ticks ldi temp, 0b00000001 ;for 8535 out timsk, temp ldi temp, 3 out tccr0, temp ldi temp, 4 out tccr1b, temp ldi temp, 256-62 mov reload, temp out tcnt0, reload ;initialize portb ser temp out ddrb, temp out portb, temp ;clear the LEDs ;initialize portc ; clr temp ; out ddrc, temp ;all inputs ; out portc, temp ;no pullups ;initalize portd in temp, ddrd andi temp, 0b00011111 out ddrd, temp ;bits 5, 6, 7 inputs in temp, portd andi temp, 0b00011111 out portd, temp ;no pullups ;initialize for rx isr clr rxready clr rxchar ;initialize for tx isr clr txbusy ldi temp, 0b10111000 out ucr, temp ldi temp, baud96 out ubrr, temp ;general initialization; ldi bitnum, 1 ldi mainstate, carddetect ldi mode, normal ldi curnum, 0 ldi tblpos, 0 ldi ssread, 0 ;ss not seen yet sei ;lcd initialize rcall lcdinit rcall lcdclr rcall lcdclr flashprintbrief teststring ldi zl, low(table) ldi zh, high(table) ldi timeout, 100 rcall delay ;************************************ ; State dispatch ;************************************ main: ; in temp, portb ; mov temp, mainstate ; com temp ; out portb, temp cpi mainstate, carddetect breq carddetectCode cpi mainstate, clock breq clockCode cpi mainstate, wait4clockhigh breq wait4clockhighCode cpi mainstate, sstest breq sstestCode cpi mainstate, data breq dataCode cpi mainstate, fullchar breq fullcharCode cpi mainstate, noCard breq noCardCode cpi mainstate, getNewPerm brne skipgetNewPerm rjmp getNewPermCode skipgetNewPerm: cpi mainstate, indb brne skipindb rjmp indbCode skipindb: cpi mainstate, sysadmin brne skipsysad rjmp sysAdminCode skipsysad: cpi mainstate, writeID brne spin rjmp writeIDCode spin: ; ldi temp, 0x55 ; out portb, temp ; mov temp, mainstate ; com temp ; out portb, temp ; rjmp spin rjmp Reset ;bad state; reset ;***** carddetectCode: ldi mainstate, clock ;if card is detected, goto clock ; ldi mainstate, 0xf5 ;if card is detected, goto clock sbic READER, carddetect ; else goto nocard ldi mainstate, nocard ;(card is detected when carddetect is low) rjmp main ;***** clockCode: sbic reader, carddetect rjmp reallywrong sbis READER, clock ;wait till clock goes low (active) ldi mainstate, sstest ; then go to sstest rjmp main reallywrong: ldi mainstate, nocard rjmp main ;***** sstestCode: ldi mainstate, data cpi ssread, 0 breq main ;if ss not seen, goto data ldi mainstate, fullchar sbis READER, data ;if data line is low, (bit is '1') or curnum, bitnum ; set bit 'bitnum' high lsl bitnum rjmp main ;***** fullcharCode: ldi mainstate, wait4clockhigh cpi bitnum, 0b00100000 brne main ;read 5 chars? store and clear cpi curnum, 31 ; curnum = end Sentinel? brne notend rjmp main notend: andi curnum, 0x0f subi curnum, -('0') st z+, curnum clr curnum ldi bitnum, 1 rjmp main ;***** wait4clockhighCode: sbic READER, clock ldi mainstate, carddetect rjmp main ;***** dataCode: ldi mainstate, wait4clockhigh sbic READER, data rjmp main ldi curnum, 1 ldi bitnum, 2 ldi ssread, 1 rjmp main ;***** nocardCode: ldi mainstate, carddetect cpi ssread, 1 ; brne endnocard2 ;jump back 3 lines, then jump to main breq ssskip rjmp endnocard ssskip: clr ssread ldi mainstate, indb cpi mode, learn breq dolearn rjmp continue dolearn: ;learn mode rcall lcdclr flashprint learnopt1 flashprint learnopt2 flashprint learnopt3 flashprint learnopt4 ldi mainstate, getNewPerm ldi mode, normal continue: ldi zl, low(table+15) ldi zh, high(table+15) ldi temp, 0x0d st z+, temp ldi temp, 0x0a st z+, temp clr temp st z+, temp ldi zl, low(table) ldi zh, high(table) ld r0, z+ ;read first char to check for start senitel adiw zl, 8 ;start printing at z+9, to skip the ss and the first 8 chars of data clr txflash mov temp, r0 ld r0, z ;load first character being printed cpi temp, 0x3b; ;first character = start sentinel? breq ok ldi mainstate, carddetect ;bad read, print an error and go back to carddetect rcall lcdclr flashprintbrief error rjmp skipnocard ; ser txflash ;if not, print error message from flash ; ldi zl, low(error<<1) ; ldi zh, high(error<<1) ; lpm ok: ramprint table ; out udr, r0 ; ser txbusy ; sbi ucr, udrie ; rcall txwait skipnocard: clr curnum ldi bitnum, 1 ldi zl, low(table) ldi zh, high(table) endnocard: rjmp main ;***** getNewPermCode: getKey buttnum mov temp, buttnum cpi temp, 12 breq exitGNP cpi temp, 4 brsh invalid mov newperm, temp ldi mainstate, writeID rjmp exitGNP invalid: rcall lcdclr flashprintbrief badchoice exitGNP: rjmp main ;***** ;Writes the ID at table+9 to the database, with permsission newperm writeIDcode: ldi temp, low(numusers) ;eear = numusers out eearl, temp ldi temp, high(numusers) out eearh, temp sbi eecr, EERE ;read the permissions byte in usertemp, eedr ; store the permissions in perm ldi zl, low(table) ldi zh, high(table) adiw zl, 9 rcall getperm cpi perm, 1 brge rewrite ;person is already in database; rewrite with new perm mov temp, usertemp cpi temp, maxIDs brlt write flashprintbrief toomany rjmp exitwriteID write: ldi zl, low(table) ldi zh, high(table) adiw zl, 15 ;store newperm at table+15 st z+, newperm clr temp st z+, temp subi zl, 8 sbc zh, temp rcall writeEEPROM ;write ID at Z to database, with the permission inc usertemp rjmp exitwrite rewrite: cli out eedr, newperm sbi eecr, EEMWE ;enable writes sbi eecr, EEWE ;begin writing sei EEspin2: sbic eecr, EEWE rjmp EEspin2 cpi newperm, 0 brne exitwrite dec usertemp ;an account is being deleted exitwrite: rcall lcdclr flashprint id ramprint (table+9) lcdprintram (table+9) flashprint written ldi zl, low(tempbuffer) ldi zh, high(tempbuffer) clr temp subi newperm, -'0' st z+, newperm st z, temp ramprint tempbuffer lcdprintram tempbuffer flashprintbrief Null ldi temp, low(numusers) ;eear = numusers out eearl, temp ldi temp, high(numusers) out eearh, temp out eedr, usertemp sbi eecr, EEMWE ;enable writes sbi eecr, EEWE ;write the new number of users EEspin3: sbic eecr, EEWE rjmp EEspin3 exitwriteID: ldi mode, normal ldi mainstate, carddetect ldi zl, low(table) ldi zh, high(table) rjmp main ;***** sysAdminCode: getKey buttnum mov temp, buttnum ; com temp ; out portb, temp ; com temp cpi temp, 4 brge sysnobutt cpi temp, 0 brne getmode sysnobutt: rjmp main getmode: ldi mainstate, carddetect cpi temp, 1 brne no1 ldi mode, normal sbi portb, alarmLED rcall lcdclr flashprintbrief normalmsg rjmp sysnobutt No1: cpi temp, 2 brne no2 ldi mode, lockdown sbi portb, accessLED rcall lcdclr flashprintbrief lockmsg rjmp sysnobutt No2: cpi temp, 3 brne no3 ldi mode, learn rcall lcdclr flashprint learnmsg No3: ;sysnobutt: rjmp main ;***** indbCode: ldi zl, low(table) ldi zh, high(table) adiw zl, 9 ld r0, z out udr, r0 clr txflash ser txbusy sbi ucr, udrie rcall txwait ldi zl, low(table) ldi zh, high(table) adiw zl, 9 rcall getperm ldi zl, low(table) ldi zh, high(table) adiw zl, 9 clr temp st z, temp cpi perm, 0x3 breq printsys rjmp L1 printsys: rcall lcdclr flashprint sysopt1 flashprint sysopt2 flashprint sysopt3 flashprint sysopt4 ldi mainstate, sysadmin clr failedattempt rjmp exit L1: ldi mainstate, carddetect cpi mode, lockdown brne notlocked rcall lcdclr flashprintbrief locked rjmp exit notlocked: cpi perm, 0x2 brne L2 clr failedattempt rcall lcdclr cbi Portb, accessLED ;cleared in 4s by the timer1 ISR flashprintbrief accessmsg ; cli ; cbi Portb, accessLED ; clr temp ; out tcnt1h, temp ; ldi temp, 1 ; out tcnt1l, temp ; in temp, tifr ; ori temp, exp2(tov1) ; out tifr, temp ; in temp, timsk ; ori temp, exp2(toie1) ; out timsk, temp ; sei rjmp exit L2: inc failedattempt ldi mainstate, carddetect rcall lcdclr flashprintbrief noaccessmsg mov temp, failedattempt cpi temp, maxattempts brne exit cbi Portb, alarmLED sbi Portb, accessLED ldi mode, lockdown rcall lcdclr flashprint alarmmsg ; ser txflash ; ldi zl, low(noaccessmsg<<1) ; ldi zh, high(noaccessmsg<<1) ; lpm ; out udr, r0 ; ser txbusy ; sbi ucr, udrie ; rcall txwait exit: ldi zl, low(table) ldi zh, high(table) ; com perm ; out portb, perm rjmp main ;**************************** ; UART Routines ;**************************** txwait: tst txbusy brne txwait ret txempty: in save, sreg tst txflash breq txram adiw zl, 1 lpm rjmp txfls txram: adiw zl, 1 ld r0, z txfls: tst r0 breq txend out udr, r0 rjmp txexit txend: clr txbusy cbi ucr, udrie txexit: out sreg, save reti txdone: in save, sreg out sreg, save reti rxdone: in save, sreg push temp in rxchar, udr ser temp mov rxready, temp pop temp out sreg, save reti ;**************************** ; EEPROM Routines ;**************************** ;writes 8 chars starting at z in RAM to y in eeprom, (6 ID numbers followed by permission level and 0(filler)) writeEEPROM: cli push yl push yh push chrctr push temp rcall findempty out eearl, yl out eearh, yh ldi chrctr, 8 writeChar: ld temp, z+ out eedr, temp sbi eecr, EEMWE ;enable writes sbi eecr, EEWE ;begin writing EEspin: sbic eecr, EEWE rjmp EEspin adiw yl, 1 out eearl, yl ;increment the address out eearh, yh dec chrctr brne writeChar pop temp pop chrctr pop yh pop yl sei ret ;finds the location of an empty location in the database, returns pointer in y ;returns -1 on failure findempty: push IDctr ldi yl, low(database) ;y = database ldi yh, high(database) ldi IDctr, maxIDs ;look at at most maxIDs IDs adiw yl, 6 ;look at the permissions (stored 6 characters after the start of the field) loopempty: out eearl, yl out eearh, yh sbi eecr, EERE ;read a char in temp, eedr cpi temp, 0 ;if temp = 0, this location is empty breq foundone adiw yl, 8 dec IDctr brne loopempty ser yh ;failure ser yl rjmp exitfind foundone: subi yl, 6 ;subtract 6 from y to point to the start of the field sbc yh, temp exitfind: pop IDctr ret ;reads EEPROM, looking for an ID matching z thru z+5 in RAM ;if found, returns the permission in perm and the address of the permissions byte in EEAR. ;if not found, returns -1 as the permission getperm: push yl push yh push chrctr push IDctr push char push match push zl push zh ldi perm, -1 ;default to "no match found" ldi temp, low(database) ;eear = y = database mov yl, temp out eearl, yl ldi temp, high(database) mov yh, temp out eearh, yh ldi chrctr, 6 ldi IDctr, maxIDs ;look at at most maxIDs IDs ser match readChar: sbi eecr, EERE ;read a char in char, eedr ;char = character from EEPROM ld temp, z+ ;temp = character from RAM cpse temp, char ;if they are the same, ok clr match ; else no match adiw yl, 1 out eearl, yl ;increment the address out eearh, yh dec chrctr brne readChar cpi match, 0 ;if a match was found brne success ; we're done dec IDctr ;no match found? decide if we should continue testing breq exitget ; if IDctr = 0, give up ;otherwise, look at the next ID ldi chrctr, 6 ;restore chrctr clr temp ; pop zh ; pop zl ; push zl ; push zh subi zl, 6 ;restore Z sbc zh, temp adiw yl, 2 ; increment y by 2 to account for the 2 bytes of overhead per ID out eearl, yl out eearh, yh ser match rjmp readChar success: sbi eecr, EERE ;read the permissions byte in perm, eedr ; store the permissions in perm exitget: pop zh pop zl pop match pop char pop IDctr pop chrctr pop yh pop yl ret ;**************************** ; Timer Routines ;**************************** ; subroutine waits for time equal to value in register timeout ;the register 'timeout' should be loaded before the call delay: tst timeout brne delay ret timer0: in save, SREG out TCNT0, Reload ; keeps clock ticking at 1 mSec dec timeout ;subtract another mSec out SREG, save reti ;back to backgound tasks timer1: in save, SREG push save push temp in temp, timsk andi temp, ~exp2(toie1) out timsk, temp sbi portb, accessLED sei rcall lcdclr cpi mode, lockdown breq tim1lockmsg flashprint prompt rjmp timer1exit tim1lockmsg: flashprint lockmsg timer1exit: pop temp pop save out SREG, save reti ;back to backgound tasks ;**************************** ; LCD Routines ;**************************** ;load zl/h with null terminated message ; flash set, its in flash ; flash clear, its in dseg lcdputstring: tst flash breq lcdputram lpm ;r0 rjmp skippy lcdputram: ld r0, z skippy: mov temp, r0 cpi temp, 32 brlt lpsexit mov temp, lcdcharcnt cpi temp, 20 brne checknext ldi temp, 0xc0 rcall lcdcmd checknext: cpi temp, 40 brne checknext2 ldi temp, 0x94 rcall lcdcmd checknext2: cpi temp, 60 brne writeit ldi temp, 0xd4 rcall lcdcmd writeit: mov temp, lcdcharcnt cpi temp, 80 brne reallywrite rcall lcdclr clr temp mov lcdcharcnt, temp reallywrite: mov temp, r0 rcall lcdput adiw zl, 1 inc lcdcharcnt rjmp lcdputstring lpsexit: ret ;================================================ ; Clear entire LCD and delay for a bit lcdclr: push temp ldi temp,1 ;Clear LCD command rcall lcdcmd ldi timeout,3 ;Delay 3 mS for clear command rcall delay clr temp mov lcdcharcnt, temp pop temp ret ;================================================ ; Initialize LCD module lcdinit: cbi PORTB,0 ;Turn on LED 0 ldi temp,0 ;Setup port pins out lcdoutput,temp ;Pull all pins low ldi temp,0xff ;All pins are outputs out lcdcontrol,temp ldi timeout,15 ;Wait at least 15 mS at power up rcall delay ; LCD specs call for 3 repetitions as follows: ;first rep ldi temp,3 ;Function set out lcdoutput,temp ;to 8-bit mode nop ;nop is data setup time sbi lcdoutput,lcde ;Toggle enable line nop cbi lcdoutput,lcde ldi timeout,15 ;Wait at least 15 mS rcall delay ;second rep ldi temp,3 ;Function set out lcdoutput,temp nop sbi lcdoutput,lcde ;Toggle enable line nop cbi lcdoutput,lcde ldi timeout,15 ;Wait at least 15 ms rcall delay ;third rep ldi temp,3 ;Function set out lcdoutput,temp nop sbi lcdoutput,lcde ;Toggle enable line nop cbi lcdoutput,lcde ldi timeout,15 ;Wait at least 15 ms rcall delay ;Now change to 4-wire interface mode ldi temp,2 ;Function set, 4 wire databus out lcdoutput,temp nop sbi lcdoutput,lcde ;Toggle enable line nop cbi lcdoutput,lcde ; Finally, at this point, ; the normal 4 wire command routine (lcdcmd) 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 sbi PORTB,0 ;Turn off LED 0 ret ;============================================ ; Wait for LCD to go unbusy lcdwait: cbi PORTB,1 ;Turn on LED 1 ldi temp,0xF0 ;Make 4 data lines inputs out lcdcontrol,temp sbi lcdoutput,lcdrw ;Set r/w pin to read cbi lcdoutput,lcdrs ;Set register select to command waitloop: sbi lcdoutput,lcde ;Toggle enable line nop cbi lcdoutput,lcde in lcdstat,lcdinput ;Read busy flag ;Read, and ignore lower nibble sbi lcdoutput,lcde ;Toggle enable line nop cbi lcdoutput,lcde sbrc lcdstat,3 ;Loop until done rjmp waitloop sbi PORTB,1 ;Turn off LED 1 ret ;============================================= ; Send command in temp to LCD lcdcmd: push temp ;Save character rcall lcdwait ldi temp,0xFF ;Make all port D pins outputs out lcdcontrol,temp pop temp ;Get character back push temp ;Save another copy swap temp ;Get upper nibble andi temp,0x0F ;Strip off upper bits out lcdoutput,temp ;Put on port nop ;wait for data setup time sbi lcdoutput,lcde ;Toggle enable line nop cbi lcdoutput,lcde pop temp ;Recall character andi temp,0x0F ;Strip off upper bits out lcdoutput,temp ;Put on port nop sbi lcdoutput,lcde ;Toggle enable line nop cbi lcdoutput,lcde ret ;============================================= ; Send character data in temp to LCD lcdput: push temp ;Save character rcall lcdwait ldi temp,0xFF ;Make all port D pins outputs out lcdcontrol,temp pop temp ;Get character back push temp ;Save another copy swap temp ;Get upper nibble andi temp,0x0F ;Strip off upper bits out lcdoutput,temp ;Put on port sbi lcdoutput,lcdrs ;Register select set for data nop sbi lcdoutput,lcde ;Toggle enable line nop cbi lcdoutput,lcde pop temp ;Recall character andi temp,0x0F ;Strip off upper bits out lcdoutput,temp ;Put on port sbi lcdoutput,lcdrs ;Register select set for data nop sbi lcdoutput,lcde ;Toggle enable line nop cbi lcdoutput,lcde ret ;************************************** ; Constants ;************************************** keytbl: .db 0b11010111, 0b11101110, 0b11011110, 0b10111110 .db 0b11101101, 0b11011101, 0b10111101, 0b11101011 .db 0b11011011, 0b10111011, 0b11100111, 0b10110111 ; 0 1 2 3 ; 4 5 6 7 ; 8 9 * # ('*' = 10, '#' = 11) ; Strings are <= 20 chars long, to fit on the LCD. teststring: .db " Ready", 0x00 accessmsg: .db "Access allowed. " .db "Have a nice day! ", 0x00 noaccessmsg:.db " Access denied. ", 0x00 error: .db "Unable to read card." .db "Try swiping the " .db "other way. ", 0x00 sysopt1: .db "What's up, doc? ", 0x00 sysopt2: .db "1 Normal mode. ", 0x00 sysopt3: .db "2 Lockdown mode. ", 0x00 sysopt4: .db "3 Learn mode. ", 0x00 locked: .db "System is locked. " .db "Go away. ", 0x00 lockmsg: .db "System is locked. ", 0x00 normalmsg: .db "System is back in " .db "normal mode. ", 0x00 learnmsg: .db "Swipe the card to " .db "add or modify. ", 0x00 id: .db "ID ", 0x00 written: .db " written " .db "with permission ", 0x00 CRLF: .db 0x0d, 0x0a, 0x00 Null: .db 0x00 learnopt1: .db "0: Delete account ", 0x00 learnopt2: .db "1: Disable account ", 0x00 learnopt3: .db "2: Give normal perm.", 0x00 learnopt4: .db "3: Give admin perm. ", 0x00 badchoice: .db "Umm... that wasn't " .db "one of the choices ", 0x00 alarmmsg: .db "Alarm set. ", 0x00 prompt: .db "Please swipe card. ", 0x00 toomany: .db "Too many users. " .db "Write failed. ", 0x00