Combination Lock using PIC 16f628

Thread Starter

draeberg

Joined Apr 24, 2008
7
We have successfully hooked up a PIC 16f628 with a matrix keypad (3x4) and an LCD (2x16 char.). Now we are pretty much stuck. Purpose of the project is to combine a keypad and an LCD with the PIC to produce combination lock which will switch between locked mode and "unlocked". So far we managed to make it distinguish between correct and wrong password entries, but we have no idea of how to make it change between lock and unlock mode.

As a source of inspiration we have used Nigel Goodwins homepage http://www.winpicprog.co.uk. By the way it is a great webpage and lot of our understanding comes from that page. Our .asm code is based on turorial 9.2.

A minor idea we also had in mind, was the idea of making it possible that when the code has been entered more than 3 times the system should stop or something like that...

All help and any idea is appreciated!
 

Thread Starter

draeberg

Joined Apr 24, 2008
7
Here is our assembler code:

Rich (BB code):
 LIST p=16F628  
 include "P16F628.inc" 
 ERRORLEVEL 0, -302 ;suppress bank selection messages
 __config 0x3D18
 
  cblock 0x20   ;start of general purpose registers
   count   ;used in looping routines
   count1   ;used in delay routine
   counta   ;used in delay routine
   countb   ;used in delay routine
   tmp1   ;temporary storage
   tmp2
   templcd   ;temp store for 4 bit mode
   templcd2
   key   ;which key was pressed
   rows   ;counter for number of rows
   code1   ;registers for secret code
   code2
   code3
   code4
   key1   ;registers for keyed attempts
   key2
   key3
   key4
  endc
LCD_PORT Equ PORTA
LCD_TRIS Equ TRISA
LCD_RS  Equ 0x04   ;LCD handshake lines
LCD_RW  Equ 0x06
LCD_E  Equ 0x07
KEY_PORT Equ PORTB   ;keypad port
KEY_TRIS Equ TRISB
Col1  Equ 0   ;pins used for keypad inputs
Col2  Equ 1
Col3  Equ 2
Col4  Equ 3
  org 0x0000
  goto Start
Key_Table   ADDWF   PCL       , f ;translation table for keypad
             RETLW   0x31 ;1
             RETLW   0x34 ;4
             RETLW   0x37 ;7
             RETLW   0x2a ;*
             RETLW   0x32 ;2
             RETLW   0x35 ;5
             RETLW   0x38 ;8
             RETLW   0x30 ;0
             RETLW   0x33 ;3
             RETLW   0x36 ;6
             RETLW   0x39 ;9
             RETLW   0x23 ;#
             RETLW   0x43 ;C
             RETLW   0x44 ;D
             RETLW   0x45 ;E
             RETLW   0x46 ;F
 
HEX_Table   ADDWF   PCL       , f  ;hex table for LCD routines
             RETLW   0x30
             RETLW   0x31
             RETLW   0x32
             RETLW   0x33
             RETLW   0x34
             RETLW   0x35
             RETLW   0x36
             RETLW   0x37
             RETLW   0x38
             RETLW   0x39
             RETLW   0x41
             RETLW   0x42
             RETLW   0x43
             RETLW   0x44
             RETLW   0x45
             RETLW   0x46
 
Text  addwf PCL, f
  retlw 'S'
  retlw 'k'
  retlw 'r'
  retlw 'i'
  retlw 'v'
  retlw ' '
  retlw 'k'
  retlw 'o'
  retlw 'd'
  retlw 'e'
  retlw '!'
  retlw '.'
  retlw 0x00
Wrong_Text addwf PCL, f
  retlw 'F'
  retlw 'o'
  retlw 'r'
  retlw 'k'
  retlw 'e'
  retlw 'r'
  retlw 't'
  retlw ' '
  retlw 'k'
  retlw 'o'
  retlw 'd'
  retlw 'e'
  retlw 0x00
Correct_Text addwf PCL, f
  retlw 'K'
  retlw 'o'
  retlw 'r'
  retlw 'r'
  retlw 'e'
  retlw 'k'
  retlw 't'
  retlw ' '
  retlw 'k'
  retlw 'o'
  retlw 'd'
  retlw 'e'
  retlw '.'
  retlw 0x00
Start  movlw 0x07
  movwf CMCON   ;turn comparators off (make it like a 16F84)
Initialise movlw '0'   ;set 4 digit secret code
  movwf code1
  movlw '0'
  movwf code2
  movlw '0'
  movwf code3
  movlw '0'
  movwf code4
 
SetPorts bsf  STATUS,  RP0 ;select bank 1
  movlw 0x00   ;make all pins outputs
  movwf LCD_TRIS
  movlw 0x0F   ;set keypad pins
  movwf KEY_TRIS  ;half in, half out
  movwf TRISB
  bcf  STATUS,  RP0 ;select bank 0
Init  call LCD_Init  ;setup LCD
 
  clrf count   ;set counter register to zero
Message  movf count, w  ;put counter value in W
  call Text   ;get a character from the text table
  xorlw 0x00   ;is it a zero?
  btfsc STATUS, Z
  goto Main
  call LCD_Char
  incf count, f
  goto Message
Wrong  call LCD_Clr
  clrf count   ;set counter register to zero
Message1 movf count, w  ;put counter value in W
  call Wrong_Text  ;get a character from the text table
  xorlw 0x00   ;is it a zero?
  btfsc STATUS, Z
  goto Wrong_Wait
  call LCD_Char
  incf count, f
  goto Message1
Wrong_Wait call Delay255
  call Delay255
  call Delay255
  call Delay255
  goto Init
Correct  call LCD_Clr
  clrf count   ;set counter register to zero
Message2 movf count, w  ;put counter value in W
  call Correct_Text  ;get a character from the text table
  xorlw 0x00   ;is it a zero?
  btfsc STATUS, Z
  goto Correct_Wait
  call LCD_Char
  incf count, f
  goto Message2
Correct_Wait call Delay255
  call Delay255
  call Delay255
  call Delay255
  goto Init
Main  movlw d'1'
  call LCD_Line2W  ;move to 2nd row, 2nd column
  call LCD_CurOn
  call Chk_Keys  ;wait for key
  movwf key1   ;store first digit
  call LCD_Char
  call Chk_Keys  ;wait for key
  movwf key2   ;store second digit
  call LCD_Char
  call Chk_Keys  ;wait for key
  movwf key3   ;store third digit
  call LCD_Char
  call Chk_Keys  ;wait for key
  movwf key4   ;store fourth digit
  call LCD_Char
  call LCD_CurOff
 
Chk_Code movf code1, w  ;test first digit
  subwf key1, w
  btfss STATUS, Z
  goto Wrong
  movf code2, w  ;test second digit
  subwf key2, w
  btfss STATUS, Z
  goto Wrong
  movf code3, w  ;test third digit
  subwf key3, w
  btfss STATUS, Z
  goto Wrong
  movf code4, w  ;test fourth digit
  subwf key4, w
  btfss STATUS, Z
  goto Wrong
  goto Correct
;Keypad subroutines
Chk_Keys movlw 0x00   ;wait until no key pressed
  movwf KEY_PORT  ;set all output pins low
  movf KEY_PORT, W
  andlw 0x0F   ;mask off high byte
  sublw 0x0F
  btfsc STATUS, Z  ;test if any key pressed
  goto Keys   ;if none, read keys
  call Delay20
  goto Chk_Keys  ;else try again
Keys    call    Scan_Keys
             movlw   0x10   ;check for no key pressed
             subwf   key, w
             btfss   STATUS, Z
             goto    Key_Found
  call Delay20
  goto Keys
Key_Found       movf    key, w
  andlw 0x0f
  call Key_Table  ;lookup key in table 
  movwf key   ;save back in key
  return    ;key pressed now in W
Scan_Keys   clrf    key
  movlw 0xF0   ;set all output lines high
             movwf   KEY_PORT
             movlw   0x04
             movwf   rows   ;set number of rows
             bcf     STATUS, C  ;put a 0 into carry
Scan    rrf     KEY_PORT, f
             bsf     STATUS, C  ;follow the zero with ones
;comment out next two lines for 4x3 numeric keypad.
             btfss   KEY_PORT, Col4
             goto    Press
             incf    key, f
             btfss   KEY_PORT, Col3
             goto    Press
             incf    key, f
             btfss   KEY_PORT, Col2
             goto    Press
             incf    key, f
             btfss   KEY_PORT, Col1
             goto    Press
             incf    key, f
             decfsz  rows, f
             goto    Scan
Press    return
;end of keypad subroutines.
;LCD routines
;Initialise LCD
LCD_Init call  LCD_Busy  ;wait for LCD to settle
  movlw 0x20   ;Set 4 bit mode
  call LCD_Cmd
  movlw 0x28   ;Set display shift
  call LCD_Cmd
  movlw 0x06   ;Set display character mode
  call LCD_Cmd
  movlw 0x0c   ;Set display on/off and cursor command
  call LCD_Cmd   ;Set cursor off
  call LCD_Clr   ;clear display
  retlw 0x00
; command set routine
LCD_Cmd  movwf templcd
  swapf templcd, w ;send upper nibble
  andlw 0x0f   ;clear upper 4 bits of W
  movwf LCD_PORT
  bcf LCD_PORT, LCD_RS ;RS line to 1
  call Pulse_e   ;Pulse the E line high
  movf templcd, w ;send lower nibble
  andlw 0x0f   ;clear upper 4 bits of W
  movwf LCD_PORT
  bcf LCD_PORT, LCD_RS ;RS line to 1
  call Pulse_e   ;Pulse the E line high
  call  LCD_Busy
  retlw 0x00
LCD_CharD addlw 0x30   ;add 0x30 to convert to ASCII
LCD_Char movwf templcd
  swapf templcd, w ;send upper nibble
  andlw 0x0f   ;clear upper 4 bits of W
  movwf LCD_PORT
  bsf LCD_PORT, LCD_RS ;RS line to 1
  call Pulse_e   ;Pulse the E line high
  movf templcd, w ;send lower nibble
  andlw 0x0f   ;clear upper 4 bits of W
  movwf LCD_PORT
  bsf LCD_PORT, LCD_RS ;RS line to 1
  call Pulse_e   ;Pulse the E line high
  call  LCD_Busy
  retlw 0x00
LCD_Line1 movlw 0x80   ;move to 1st row, first column
  call LCD_Cmd
  retlw 0x00
LCD_Line2 movlw 0xc0   ;move to 2nd row, first column
  call LCD_Cmd
  retlw 0x00
LCD_Line1W addlw 0x80   ;move to 1st row, column W
  call LCD_Cmd
  retlw 0x00
LCD_Line2W addlw 0xc0   ;move to 2nd row, column W
  call LCD_Cmd
  retlw 0x00
LCD_CurOn movlw 0x0d   ;Set display on/off and cursor command
  call LCD_Cmd
  retlw 0x00
LCD_CurOff movlw 0x0c   ;Set display on/off and cursor command
  call LCD_Cmd
  retlw 0x00
LCD_Clr  movlw 0x01   ;Clear display
  call LCD_Cmd
  retlw 0x00
LCD_HEX  movwf tmp1
  swapf tmp1, w
  andlw 0x0f
  call HEX_Table
  call LCD_Char
  movf tmp1, w
  andlw 0x0f
  call HEX_Table
  call LCD_Char
  retlw 0x00
Delay255 movlw 0xff   ;delay 255 mS
  goto d0
Delay100 movlw d'100'   ;delay 100mS
  goto d0
Delay50  movlw d'50'   ;delay 50mS
  goto d0
Delay20  movlw d'20'   ;delay 20mS
  goto d0
Delay5  movlw 0x05   ;delay 5.000 ms (4 MHz clock)
d0  movwf count1
d1  movlw 0xC7   ;delay 1mS
  movwf counta
  movlw 0x01
  movwf countb
Delay_0
  decfsz counta, f
  goto $+2
  decfsz countb, f
  goto Delay_0
  decfsz count1 ,f
  goto d1
  retlw 0x00
Pulse_e  bsf LCD_PORT, LCD_E
  nop
  bcf LCD_PORT, LCD_E
  retlw 0x00
LCD_Busy
  bsf STATUS, RP0  ;set bank 1
  movlw 0x0f   ;set Port for input
  movwf LCD_TRIS
  bcf STATUS, RP0  ;set bank 0
  bcf LCD_PORT, LCD_RS ;set LCD for command mode
  bsf LCD_PORT, LCD_RW ;setup to read busy flag
  bsf LCD_PORT, LCD_E
  swapf LCD_PORT, w  ;read upper nibble (busy flag)
  bcf LCD_PORT, LCD_E  
  movwf templcd2 
  bsf LCD_PORT, LCD_E  ;dummy read of lower nibble
  bcf LCD_PORT, LCD_E
  btfsc templcd2, 7  ;check busy flag, high = busy
  goto LCD_Busy  ;if busy check again
  bcf LCD_PORT, LCD_RW
  bsf STATUS, RP0  ;set bank 1
  movlw 0x00   ;set Port for output
  movwf LCD_TRIS
  bcf STATUS, RP0  ;set bank 0
  return
;end of LCD routines
 
  end
 

marcosj

Joined Apr 23, 2008
4
I didn't read all the code, but what I undestood was your problem is:

You enter a password (fixed lenght 4 chars, without an Enter)
after you entered the password, it checks if it's correct

then you should unlock the thing (what is it? is a hardware lock?)

then you are un unlocked state, until you do something to lock it, that's how it works in digital door locks, when you close it, a sensor locks it. for example you could have a key convination to lock it, or a diferrent password, because you are in a different mode, they need different passwords.

Also, any time you read a wrong code in lock mode, you should decrease a counter, which initiali is 3, if it reachs 0, then you enter a special mode. In this mode, maybe what you can do is to wait 5 minutes, and show it on the display, a backwards counter, when it finishs the count, you are back at normal mode, and you can try another time with a password.

Does any of these thing have anything to do with what you asked? :)

MARCOS
 

Thread Starter

draeberg

Joined Apr 24, 2008
7
You understand it perfectly. When you ente the code **** it will automaticly call "correct code" to be displayed without any need for pressing a key, for an instance the #-key could be used. But that I do not know how to actually program. Anyway what we are seeking is the possibilty to make the PIC go into a "lock"-stage when the correct code is entered, and when in it the correct code has to be entered again to unlock it. It could be cool and very useful. The thing about connecting it to a sensor or something like it is unnecessary, it just has to simulate it. Also the PIC has no more ports that can be used, as all the pins are used.
 

marcosj

Joined Apr 23, 2008
4
You should practice programming and all of that, get a goot tutorial, there area a lot of then, and have fun.
What I can give you, are a few tips:

Add a variable "lockstate" (between cblock and endc), and other "wrongtrys"

When you check the code entered is OK, then change the state of lockstate, like this:
Correct
monlw 3
monwf wrongtrys ;you have 3 new oportunities to try

movf lockstate,w
xorlw 1
movwf lockstate
this changes lockstate from 1 to 0 any time you entered the password
then It's your job to show a different message for each state. Use like this

btfss lockstate,0 ;if bit 0 of lockstate is on
goto showmsgUnLock
showMsgLock:
show message of lock mode
....
showMsgUnLock:
show message of unlock mode

Also any time a wrong code is entered do:
Wrong
btfss lockstate,0
goto noOutOfTries ;if bit 0 of lockstate is off, unlocked, it doesn't matter

decf wrongtrys,f ;dec try count
btfsc STATUS,Z ;
goto noOutOfTries
;you tried 3 times wrong, now you must wait some minutes
monlw 3
monwf wrongtrys ;you have 3 new oportunities to try

noOutOfTries


Of course you must learn how to show messages and some details of this. I hope it helps.

MARCOS
 

jegonz

Joined Jan 25, 2008
19
< You understand it perfectly. When you ente the code **** it will automaticly call "correct code" to be displayed without any need for pressing a key, for an instance the #-key could be used. >

For this, since you have a fixed lenght of the password, then just put a counter that increments at each key pressed. And then when the value is higher than the fixlenght then checks it to see if it is correct or not. With this you don´t need to press anyother key....
I hope I understood you question...
 
Top