;-------------------------------------------------------------------------;
; 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: