Program #6 - Combination Lock with Memory

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

A Combination Lock

This program impliments a combination lock. Two pushbuttons are given eight presses. The order of presses determines the combination. One button represents a '0', the other a '1'. There are 256 different binary combinations.

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.

Reading and Writing EEPROM

The subroutines that read and store values in EEPROM were copied from the '84 data sheet. Notice the values that have to be set up before the read or write takes place. Notice also that the write takes 10 milliseconds to 'burn' the value in.

Other Applications

Having memory that doesn't disappear when the power is removed is quite handy. A clock program could be assigned a changable alarm time or even many alarm times. A countdown timer could remember one or many starting times. A few telephone numbers or whatever could be stored. Much of the coding involves just getting the data into program.

Entering a combination

In the subroutine 'entercode', carry is used along with the 'rrf' instruction to generate a binary number whose bits represent the combination. Notice how carry is first cleared and then set only if PB1 is not pressed. Since you only get to this point if one button is pressed and it is not PB1, it must be PB2 that is pressed. The resulting carry is pushed into the register 'combo' from the high order end. Eight presses and the first press ends up as the least significant bit, (LSB).

Your turn

You might not want the lights displayed when the new combination is entered. Can you make the changes?

256 combinations may not seem like many. How about adding a third or even forth button. How would you handle this?

Code:

Interested:

Questions:

Comments: