Combination Lock using PIC 16f628

Discussion in 'Embedded Systems and Microcontrollers' started by draeberg, Apr 24, 2008.

  1. draeberg

    Thread Starter New Member

    Apr 24, 2008
    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 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!
  2. draeberg

    Thread Starter New Member

    Apr 24, 2008
    Here is our assembler code:

    Code ( (Unknown Language)):
    2.  LIST p=16F628  
    3.  include ""
    4.  ERRORLEVEL 0, -302 ;suppress bank selection messages
    5.  __config 0x3D18
    7.   cblock 0x20   ;start of general purpose registers
    8.    count   ;used in looping routines
    9.    count1   ;used in delay routine
    10.    counta   ;used in delay routine
    11.    countb   ;used in delay routine
    12.    tmp1   ;temporary storage
    13.    tmp2
    14.    templcd   ;temp store for 4 bit mode
    15.    templcd2
    16.    key   ;which key was pressed
    17.    rows   ;counter for number of rows
    18.    code1   ;registers for secret code
    19.    code2
    20.    code3
    21.    code4
    22.    key1   ;registers for keyed attempts
    23.    key2
    24.    key3
    25.    key4
    26.   endc
    27. LCD_PORT Equ PORTA
    28. LCD_TRIS Equ TRISA
    29. LCD_RS  Equ 0x04   ;LCD handshake lines
    30. LCD_RW  Equ 0x06
    31. LCD_E  Equ 0x07
    32. KEY_PORT Equ PORTB   ;keypad port
    33. KEY_TRIS Equ TRISB
    34. Col1  Equ 0   ;pins used for keypad inputs
    35. Col2  Equ 1
    36. Col3  Equ 2
    37. Col4  Equ 3
    38.   org 0x0000
    39.   goto Start
    40. Key_Table   ADDWF   PCL       , f ;translation table for keypad
    41.              RETLW   0x31 ;1
    42.              RETLW   0x34 ;4
    43.              RETLW   0x37 ;7
    44.              RETLW   0x2a ;*
    45.              RETLW   0x32 ;2
    46.              RETLW   0x35 ;5
    47.              RETLW   0x38 ;8
    48.              RETLW   0x30 ;0
    49.              RETLW   0x33 ;3
    50.              RETLW   0x36 ;6
    51.              RETLW   0x39 ;9
    52.              RETLW   0x23 ;#
    53.              RETLW   0x43 ;C
    54.              RETLW   0x44 ;D
    55.              RETLW   0x45 ;E
    56.              RETLW   0x46 ;F
    58. HEX_Table   ADDWF   PCL       , f  ;hex table for LCD routines
    59.              RETLW   0x30
    60.              RETLW   0x31
    61.              RETLW   0x32
    62.              RETLW   0x33
    63.              RETLW   0x34
    64.              RETLW   0x35
    65.              RETLW   0x36
    66.              RETLW   0x37
    67.              RETLW   0x38
    68.              RETLW   0x39
    69.              RETLW   0x41
    70.              RETLW   0x42
    71.              RETLW   0x43
    72.              RETLW   0x44
    73.              RETLW   0x45
    74.              RETLW   0x46
    76. Text  addwf PCL, f
    77.   retlw 'S'
    78.   retlw 'k'
    79.   retlw 'r'
    80.   retlw 'i'
    81.   retlw 'v'
    82.   retlw ' '
    83.   retlw 'k'
    84.   retlw 'o'
    85.   retlw 'd'
    86.   retlw 'e'
    87.   retlw '!'
    88.   retlw '.'
    89.   retlw 0x00
    90. Wrong_Text addwf PCL, f
    91.   retlw 'F'
    92.   retlw 'o'
    93.   retlw 'r'
    94.   retlw 'k'
    95.   retlw 'e'
    96.   retlw 'r'
    97.   retlw 't'
    98.   retlw ' '
    99.   retlw 'k'
    100.   retlw 'o'
    101.   retlw 'd'
    102.   retlw 'e'
    103.   retlw 0x00
    104. Correct_Text addwf PCL, f
    105.   retlw 'K'
    106.   retlw 'o'
    107.   retlw 'r'
    108.   retlw 'r'
    109.   retlw 'e'
    110.   retlw 'k'
    111.   retlw 't'
    112.   retlw ' '
    113.   retlw 'k'
    114.   retlw 'o'
    115.   retlw 'd'
    116.   retlw 'e'
    117.   retlw '.'
    118.   retlw 0x00
    119. Start  movlw 0x07
    120.   movwf CMCON   ;turn comparators off (make it like a 16F84)
    121. Initialise movlw '0'   ;set 4 digit secret code
    122.   movwf code1
    123.   movlw '0'
    124.   movwf code2
    125.   movlw '0'
    126.   movwf code3
    127.   movlw '0'
    128.   movwf code4
    130. SetPorts bsf  STATUS,  RP0 ;select bank 1
    131.   movlw 0x00   ;make all pins outputs
    132.   movwf LCD_TRIS
    133.   movlw 0x0F   ;set keypad pins
    134.   movwf KEY_TRIS  ;half in, half out
    135.   movwf TRISB
    136.   bcf  STATUS,  RP0 ;select bank 0
    137. Init  call LCD_Init  ;setup LCD
    139.   clrf count   ;set counter register to zero
    140. Message  movf count, w  ;put counter value in W
    141.   call Text   ;get a character from the text table
    142.   xorlw 0x00   ;is it a zero?
    143.   btfsc STATUS, Z
    144.   goto Main
    145.   call LCD_Char
    146.   incf count, f
    147.   goto Message
    148. Wrong  call LCD_Clr
    149.   clrf count   ;set counter register to zero
    150. Message1 movf count, w  ;put counter value in W
    151.   call Wrong_Text  ;get a character from the text table
    152.   xorlw 0x00   ;is it a zero?
    153.   btfsc STATUS, Z
    154.   goto Wrong_Wait
    155.   call LCD_Char
    156.   incf count, f
    157.   goto Message1
    158. Wrong_Wait call Delay255
    159.   call Delay255
    160.   call Delay255
    161.   call Delay255
    162.   goto Init
    163. Correct  call LCD_Clr
    164.   clrf count   ;set counter register to zero
    165. Message2 movf count, w  ;put counter value in W
    166.   call Correct_Text  ;get a character from the text table
    167.   xorlw 0x00   ;is it a zero?
    168.   btfsc STATUS, Z
    169.   goto Correct_Wait
    170.   call LCD_Char
    171.   incf count, f
    172.   goto Message2
    173. Correct_Wait call Delay255
    174.   call Delay255
    175.   call Delay255
    176.   call Delay255
    177.   goto Init
    178. Main  movlw d'1'
    179.   call LCD_Line2W  ;move to 2nd row, 2nd column
    180.   call LCD_CurOn
    181.   call Chk_Keys  ;wait for key
    182.   movwf key1   ;store first digit
    183.   call LCD_Char
    184.   call Chk_Keys  ;wait for key
    185.   movwf key2   ;store second digit
    186.   call LCD_Char
    187.   call Chk_Keys  ;wait for key
    188.   movwf key3   ;store third digit
    189.   call LCD_Char
    190.   call Chk_Keys  ;wait for key
    191.   movwf key4   ;store fourth digit
    192.   call LCD_Char
    193.   call LCD_CurOff
    195. Chk_Code movf code1, w  ;test first digit
    196.   subwf key1, w
    197.   btfss STATUS, Z
    198.   goto Wrong
    199.   movf code2, w  ;test second digit
    200.   subwf key2, w
    201.   btfss STATUS, Z
    202.   goto Wrong
    203.   movf code3, w  ;test third digit
    204.   subwf key3, w
    205.   btfss STATUS, Z
    206.   goto Wrong
    207.   movf code4, w  ;test fourth digit
    208.   subwf key4, w
    209.   btfss STATUS, Z
    210.   goto Wrong
    211.   goto Correct
    212. ;Keypad subroutines
    213. Chk_Keys movlw 0x00   ;wait until no key pressed
    214.   movwf KEY_PORT  ;set all output pins low
    215.   movf KEY_PORT, W
    216.   andlw 0x0F   ;mask off high byte
    217.   sublw 0x0F
    218.   btfsc STATUS, Z  ;test if any key pressed
    219.   goto Keys   ;if none, read keys
    220.   call Delay20
    221.   goto Chk_Keys  ;else try again
    222. Keys    call    Scan_Keys
    223.              movlw   0x10   ;check for no key pressed
    224.              subwf   key, w
    225.              btfss   STATUS, Z
    226.              goto    Key_Found
    227.   call Delay20
    228.   goto Keys
    229. Key_Found       movf    key, w
    230.   andlw 0x0f
    231.   call Key_Table  ;lookup key in table
    232.   movwf key   ;save back in key
    233.   return    ;key pressed now in W
    234. Scan_Keys   clrf    key
    235.   movlw 0xF0   ;set all output lines high
    236.              movwf   KEY_PORT
    237.              movlw   0x04
    238.              movwf   rows   ;set number of rows
    239.              bcf     STATUS, C  ;put a 0 into carry
    240. Scan    rrf     KEY_PORT, f
    241.              bsf     STATUS, C  ;follow the zero with ones
    242. ;comment out next two lines for 4x3 numeric keypad.
    243.              btfss   KEY_PORT, Col4
    244.              goto    Press
    245.              incf    key, f
    246.              btfss   KEY_PORT, Col3
    247.              goto    Press
    248.              incf    key, f
    249.              btfss   KEY_PORT, Col2
    250.              goto    Press
    251.              incf    key, f
    252.              btfss   KEY_PORT, Col1
    253.              goto    Press
    254.              incf    key, f
    255.              decfsz  rows, f
    256.              goto    Scan
    257. Press    return
    258. ;end of keypad subroutines.
    259. ;LCD routines
    260. ;Initialise LCD
    261. LCD_Init call  LCD_Busy  ;wait for LCD to settle
    262.   movlw 0x20   ;Set 4 bit mode
    263.   call LCD_Cmd
    264.   movlw 0x28   ;Set display shift
    265.   call LCD_Cmd
    266.   movlw 0x06   ;Set display character mode
    267.   call LCD_Cmd
    268.   movlw 0x0c   ;Set display on/off and cursor command
    269.   call LCD_Cmd   ;Set cursor off
    270.   call LCD_Clr   ;clear display
    271.   retlw 0x00
    272. ; command set routine
    273. LCD_Cmd  movwf templcd
    274.   swapf templcd, w ;send upper nibble
    275.   andlw 0x0f   ;clear upper 4 bits of W
    276.   movwf LCD_PORT
    277.   bcf LCD_PORT, LCD_RS ;RS line to 1
    278.   call Pulse_e   ;Pulse the E line high
    279.   movf templcd, w ;send lower nibble
    280.   andlw 0x0f   ;clear upper 4 bits of W
    281.   movwf LCD_PORT
    282.   bcf LCD_PORT, LCD_RS ;RS line to 1
    283.   call Pulse_e   ;Pulse the E line high
    284.   call  LCD_Busy
    285.   retlw 0x00
    286. LCD_CharD addlw 0x30   ;add 0x30 to convert to ASCII
    287. LCD_Char movwf templcd
    288.   swapf templcd, w ;send upper nibble
    289.   andlw 0x0f   ;clear upper 4 bits of W
    290.   movwf LCD_PORT
    291.   bsf LCD_PORT, LCD_RS ;RS line to 1
    292.   call Pulse_e   ;Pulse the E line high
    293.   movf templcd, w ;send lower nibble
    294.   andlw 0x0f   ;clear upper 4 bits of W
    295.   movwf LCD_PORT
    296.   bsf LCD_PORT, LCD_RS ;RS line to 1
    297.   call Pulse_e   ;Pulse the E line high
    298.   call  LCD_Busy
    299.   retlw 0x00
    300. LCD_Line1 movlw 0x80   ;move to 1st row, first column
    301.   call LCD_Cmd
    302.   retlw 0x00
    303. LCD_Line2 movlw 0xc0   ;move to 2nd row, first column
    304.   call LCD_Cmd
    305.   retlw 0x00
    306. LCD_Line1W addlw 0x80   ;move to 1st row, column W
    307.   call LCD_Cmd
    308.   retlw 0x00
    309. LCD_Line2W addlw 0xc0   ;move to 2nd row, column W
    310.   call LCD_Cmd
    311.   retlw 0x00
    312. LCD_CurOn movlw 0x0d   ;Set display on/off and cursor command
    313.   call LCD_Cmd
    314.   retlw 0x00
    315. LCD_CurOff movlw 0x0c   ;Set display on/off and cursor command
    316.   call LCD_Cmd
    317.   retlw 0x00
    318. LCD_Clr  movlw 0x01   ;Clear display
    319.   call LCD_Cmd
    320.   retlw 0x00
    321. LCD_HEX  movwf tmp1
    322.   swapf tmp1, w
    323.   andlw 0x0f
    324.   call HEX_Table
    325.   call LCD_Char
    326.   movf tmp1, w
    327.   andlw 0x0f
    328.   call HEX_Table
    329.   call LCD_Char
    330.   retlw 0x00
    331. Delay255 movlw 0xff   ;delay 255 mS
    332.   goto d0
    333. Delay100 movlw d'100'   ;delay 100mS
    334.   goto d0
    335. Delay50  movlw d'50'   ;delay 50mS
    336.   goto d0
    337. Delay20  movlw d'20'   ;delay 20mS
    338.   goto d0
    339. Delay5  movlw 0x05   ;delay 5.000 ms (4 MHz clock)
    340. d0  movwf count1
    341. d1  movlw 0xC7   ;delay 1mS
    342.   movwf counta
    343.   movlw 0x01
    344.   movwf countb
    345. Delay_0
    346.   decfsz counta, f
    347.   goto $+2
    348.   decfsz countb, f
    349.   goto Delay_0
    350.   decfsz count1 ,f
    351.   goto d1
    352.   retlw 0x00
    353. Pulse_e  bsf LCD_PORT, LCD_E
    354.   nop
    355.   bcf LCD_PORT, LCD_E
    356.   retlw 0x00
    357. LCD_Busy
    358.   bsf STATUS, RP0  ;set bank 1
    359.   movlw 0x0f   ;set Port for input
    360.   movwf LCD_TRIS
    361.   bcf STATUS, RP0  ;set bank 0
    362.   bcf LCD_PORT, LCD_RS ;set LCD for command mode
    363.   bsf LCD_PORT, LCD_RW ;setup to read busy flag
    364.   bsf LCD_PORT, LCD_E
    365.   swapf LCD_PORT, w  ;read upper nibble (busy flag)
    366.   bcf LCD_PORT, LCD_E  
    367.   movwf templcd2
    368.   bsf LCD_PORT, LCD_E  ;dummy read of lower nibble
    369.   bcf LCD_PORT, LCD_E
    370.   btfsc templcd2, 7  ;check busy flag, high = busy
    371.   goto LCD_Busy  ;if busy check again
    372.   bcf LCD_PORT, LCD_RW
    373.   bsf STATUS, RP0  ;set bank 1
    374.   movlw 0x00   ;set Port for output
    375.   movwf LCD_TRIS
    376.   bcf STATUS, RP0  ;set bank 0
    377.   return
    378. ;end of LCD routines
    380.   end
  3. marcosj

    New Member

    Apr 23, 2008
    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? :)

  4. draeberg

    Thread Starter New Member

    Apr 24, 2008
    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.
  5. marcosj

    New Member

    Apr 23, 2008
    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:
    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
    show message of lock mode
    show message of unlock mode

    Also any time a wrong code is entered do:
    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


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

  6. jegonz


    Jan 25, 2008
    < 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...