;-------------------------------------------------------------------------; ; COMBO.ASM A combination lock that remembers code needed to open ; ;-------------------------------------------------------------------------; LIST P=16F84 ; tells which processor is used INCLUDE "p16f84.inc" ; defines various registers etc. Look it over. ERRORLEVEL -224 ; supress annoying message because of tris ERRORLEVEL -302 ; " " " " page change __CONFIG _PWRTE_ON & _LP_OSC & _WDT_OFF ; configuration switches #define PB1 PORTB, 4 ; Pushbutton #1, generates a '0' bit in combo #define PB2 PORTB, 5 ; Pushbutton #2, generates a '1' bit in combo #define LED1 PORTB, 3 ; LED #1 #define LED2 PORTB, 0 ; LED #2 ; register usage: CBLOCK H'C' combo ; holds combination count ; general count register codevalue ; holds code value ENDC ORG 0 ; start a program memory location zero goto main ; jump over other routines ;-------------------------------------------------------------------------; ; Initialize the ports etc. : ;-------------------------------------------------------------------------; init: movlw B'00000000' ; all bits low in W tris PORTA ; contents of W copied to PORT A ... movlw B'00110000' ; Rb4,RB5 inputs, all other output tris PORTB ; into PORT B clrf PORTB ; LEDs blanked movlw 0 option ; Port B pullups enabled return ;-------------------------------------------------------------------------; ; Read a byte from the data EEPROM at address given in W ; ;-------------------------------------------------------------------------; readee movwf EEADR ; set up eeprom address from W bsf STATUS,RP0 ; change to page 1 bsf EECON1,RD ; set the read bit bcf STATUS,RP0 ; back to page 0 movf EEDATA,W ; return value in W return ;-------------------------------------------------------------------------; ; This routine writes a byte to data EEPROM ; ; set up EEADR and EEDATA before entry ; ;-------------------------------------------------------------------------; writee: bsf STATUS,RP0 ; enter page 1 clrf EECON1 bsf EECON1,WREN ; enable write movlw H'55' ; magic sequence movwf EECON2 movlw H'AA' movwf EECON2 bsf EECON1,WR eeloop: btfsc EECON1,WR ; wait for WR to go low goto eeloop ; not yet bsf EECON1,WREN bcf EECON1,EEIF ; clear the interrupt flag bcf STATUS,RP0 ; return to page 0 movlw D'10' ; delay to 'burn' in call nmsec return ;-------------------------------------------------------------------------; ; Enter Code ; ;-------------------------------------------------------------------------; entercode: movlw 1 ; flash once call flashleds movlw 8 ; set up to count 8 presses movwf count waitboth: btfss PB1 ; wait until pushbutton 1 up goto waitboth btfss PB2 ; and pushbutton 2 up goto waitboth call msec40 ; bypass any bouncing bcf LED1 bcf LED2 eitherbutton: ; wait until either button pressed comf PORTB, W ; compliment of Port B in W andlw B'00110000' ; look at buttons, (will give 0's if up) btfsc STATUS, Z ; skip if either pressed goto eitherbutton ; try again bcf STATUS, C ; clear carry btfss PB1 ; if button one pressed leave carry clear goto PB1pressed bsf STATUS, C ; else set carry goto $ + 3 ; skip over PB1pressed bsf LED1 ; turn LED1 on goto $ + 2 ; skip over bsf LED2 ; turn LED2 on rrf combo, f ; roll result into combo high order bit decfsz count, f ; more presses necessary goto waitboth ; next press movf combo, W ; transfer result to W return ;-------------------------------------------------------------------------; ; Delay Subroutines ; ;-------------------------------------------------------------------------; onesecond: ; a subroutine that delays for 1 seconds call msec250 call msec250 call msec250 call msec250 return msec40 movlw D'40' ; 40 msec delay entry point goto nmsec msec250: ; a subroutine to delay 250 msec movlw D'250' ; W is changed but no separate register needed nmsec: ; could call it here with # msec in W nop ; each nop is 0.122 milliseconds nop nop ; each total loop is 8 X 0.122 = 0.976 msec nop addlw H'FF' ; same as subtracting 1 from W btfss STATUS, Z ; skip if result is zero goto nmsec ; this is 2 X 0.122 msec return ; back to calling point ;-------------------------------------------------------------------------; ; Flash the LEDs, number of flashes in W on entry ; ;-------------------------------------------------------------------------; flashleds: movwf count flashloop: movlw H'F' movwf PORTB call onesecond + 2 ; 1/2 sec on movlw 0 movwf PORTB call onesecond + 2 ; 1/2 sec off decfsz count, f goto flashloop return ;-------------------------------------------------------------------------; ; Get combo value and place it in EEPROM location 0 ; ;-------------------------------------------------------------------------; setcombo: call entercode ; get desired press combination movwf EEDATA ; set up data and address movlw 0 movwf EEADR call writee ; save combo in EEPROM movlw 2 ; flash leds 2 times call flashleds ; ( one additional when entering main ) return ;-------------------------------------------------------------------------; ; The Main routine ; ;-------------------------------------------------------------------------; main: call init ; initialize registers etc. movf PORTB, W ; check if both buttons pressed on power-up andlw B'00110000' ; look at buttons, (will give 0's if down) btfsc STATUS, Z ; skip if both not presssed call setcombo ; if both press set the combination movlw 0 ; get combo from EEPROM address 0 call readee movwf codevalue ; save it mainloop: call entercode subwf codevalue, W ; is it same as code? btfss STATUS, Z ; zero set if yes goto mainloop movlw 5 ; sucess, unlocking procedure would ... call flashleds ; be placed here. goto mainloop org 2100 ; this is location of EEPROM data dw H'33' ; the initial value of location 0 ... ; is set to B'00110011' end ; end of program
The correct sequence is held in location 0 of the EEPROM in the 16F84. If both pushbuttons are held down as power is supplied the program allows entry of a new combination. Holding the value in EEPROM means that the program can remember the sequence even if the power is turned off.
Actual operation of a lock is not programmed. Instead, after each eight presses, all 4 LEDs flash once. Five additional flashes occur if the sequence entered matches the correct combination After entry of a new combination, two additional flashes signal storage of the new value.
256 combinations may not seem like many. How about adding a third or even forth button. How would you handle this?
Questions: