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