Shop OBEX P1 Docs P2 Docs Learn Events
Password help w/ Keypad & LCD — Parallax Forums

Password help w/ Keypad & LCD

CambodiaCambodia Posts: 2
edited 2015-02-27 11:24 in BASIC Stamp
Hello! A friend of mine and I are having issues getting any code dealing with passwords and keypads to work. I have looked online and on this forum for weeks without luck. Could anyone help us? We’re using a 4x4 Matrix Membrane Keypad in pins 0-7 and a Parallax 2 x 16 Serial LCD (Non-Backlit) in pin 15. We know these two codes work:

LCD Code
' {$STAMP BS2}
' {$PBASIC 2.5}

TxPin     CON   15
n9600     CON   84

HIGH TxPin                       ' Set serial pin port high
PAUSE 100                        ' Pause to initialize
SEROUT TxPin, n9600, [12, 17]    ' Clear, turn on backlight
SEROUT TxPin, n9600, ["Hello, world...", 13] ' Print text, line feed
SEROUT TxPin, n9600, ["from Parallax!"]
SEROUT TxPin, n9600, [212, 220]  ' Quarter A note
PAUSE 3000                       ' Wait 3 seconds
SEROUT TxPin, n9600, [18]        ' Turn backlight off

Keypad Code
' {$STAMP BS2}
' {$PBASIC 2.5}


row         VAR  Nib                        ' Variable space for row counting
column      VAR  Nib                        ' Variable space for column counting
keypad      VAR  Word                       ' Variable space to store keypad output
keypadOld   VAR  Word                       ' Variable space to store old keypad output
temp        VAR  Nib                        ' Variable space for polling column states

DEBUG CLS                                   ' Clear Debug Terminal
GOSUB Update                                ' Display keypad graphic

DO
  GOSUB ReadKeypad                          ' Read keypad button states
  DEBUG HOME, BIN16 keypad, CR, CR,         ' Display 16-bit keypad value
              BIN4 keypad >> 12,CR,         ' Display 1st row 4-bit keypad value
              BIN4 keypad >> 8, CR,         ' Display 2nd row 4-bit keypad value
              BIN4 keypad >> 4, CR,         ' Display 3rd row 4-bit keypad value
              BIN4 keypad                   ' Display 4th row 4-bit keypad value

  IF keypad <> keypadOld THEN               ' If different button is pressed,
    GOSUB Update                            ' update the keypad graphic to clear
  ENDIF                                     ' old display

  IF keypad THEN                            ' Display button pressed in graphic
    GOSUB display
  ENDIF

  keypadOld = keypad                        ' Store keypad value in variable keypadOld
LOOP



' -----[ Subroutine - ReadKeypad ]-------------------------------------------------
' Read keypad button states
ReadKeypad:
  keypad = 0
  OUTL   = %00000000                        ' Initialize IO
  DIRL   = %00000000

  FOR row = 0 TO 3
    DIRB = %1111                            ' Set columns (P7-P4) as outputs
    OUTB = %0000                            ' Pull columns low (act as pull down)
    OUTA = 1 << Row                         ' Set rows high one by one
    DIRA = 1 << Row

    temp = 0                                ' Reset temp variable to 0
    FOR column = 0 TO 3
      INPUT (column + 4)                    ' Set columns as inputs one by one
      temp = temp | (INB & (1 << column))   ' Poll column state and store in temp
    NEXT

    keypad = keypad << 4 | (Temp REV 4)     ' Store keypad value
  NEXT
RETURN


' -----[ Subroutine - Update ]-----------------------------------------------------
' Graphical depiction of keypad
Update:
  DEBUG CRSRXY,0,7,
    "+---+---+---+---+",CR,
    "|   |   |   |   |",CR,
    "+---+---+---+---+",CR,
    "|   |   |   |   |",CR,
    "+---+---+---+---+",CR,
    "|   |   |   |   |",CR,
    "+---+---+---+---+",CR,
    "|   |   |   |   |",CR,
    "+---+---+---+---+"
RETURN


' -----[ Subroutine - Display ]----------------------------------------------------
' Display button pressed in keypad graphic
Display:
  IF KeyPad.BIT15 THEN  DEBUG CRSRXY, 02,08,"1"
  IF Keypad.BIT14 THEN  DEBUG CRSRXY, 06,08,"2"
  IF KeyPad.BIT13 THEN  DEBUG CRSRXY, 10,08,"3"
  IF Keypad.BIT12 THEN  DEBUG CRSRXY, 14,08,"A"
  IF KeyPad.BIT11 THEN  DEBUG CRSRXY, 02,10,"4"
  IF Keypad.BIT10 THEN  DEBUG CRSRXY, 06,10,"5"
  IF KeyPad.BIT9  THEN  DEBUG CRSRXY, 10,10,"6"
  IF Keypad.BIT8  THEN  DEBUG CRSRXY, 14,10,"B"
  IF KeyPad.BIT7  THEN  DEBUG CRSRXY, 02,12,"7"
  IF Keypad.BIT6  THEN  DEBUG CRSRXY, 06,12,"8"
  IF KeyPad.BIT5  THEN  DEBUG CRSRXY, 10,12,"9"
  IF Keypad.BIT4  THEN  DEBUG CRSRXY, 14,12,"C"
  IF KeyPad.BIT3  THEN  DEBUG CRSRXY, 02,14,"*"
  IF Keypad.BIT2  THEN  DEBUG CRSRXY, 06,14,"0"
  IF KeyPad.BIT1  THEN  DEBUG CRSRXY, 10,14,"#"
  IF Keypad.BIT0  THEN  DEBUG CRSRXY, 14,14,"D"
RETURN

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2015-02-24 11:13
    What have you tried so far? What do you understand about what you need?

    Remember that your LCD expects characters, one byte per character, to be sent via SEROUT. Your keypad code supplies one bit for each button on the keypad and this is returned in "keypad" when you call ReadKeypad. There's no debouncing (look up debounce in the Wikipedia) done by ReadKeypad and there's no translation to a character. You have to do that yourself in your code. The NCD operator will take the "keypad" value and return the number of the first 1 bit found which you can use with LOOKUP to translate to a character. Look in the Stamp Reference Manual for the descriptions of these operators / statements.

    I think there's a Nuts & Volts column on using a similar keypad. Have a look at the code they use for suggestions. The archive is on Parallax's website.
  • CambodiaCambodia Posts: 2
    edited 2015-02-24 22:48
    We want it so that a user puts in a password and the microcontroller sees if it's correct (say the password is 1234) and if it is, the LCD will say "Authorized." and then reset after say 30 seconds.
    We've looked at the Manual for information on both keypad and passwords, and it has left us more confused than given us answers.
    The only Nuts&Volts column I see that might be the one you're referring to is #22, and we've already looked at it. I'll double check with it though.

    This is a code that we've been messing with to see if we could get it to work.
    '   {$STAMP BS2}
    '   {$PBASIC 2.5}
    
    
    ' -----[ I/O Definitions ]-------------------------------------------------
    LCD    PIN 15  'lcd display
    
    
    ' -----[ Constants ]-------------------------------------------------------
    
    TxPin     CON   15
    n9600     CON   84
    
    
    ' -----[ Variables ]-------------------------------------------------------
    
    row         VAR  Nib                        ' Variable space for row counting
    column      VAR  Nib                        ' Variable space for column counting
    keypad      VAR  Word                       ' Variable space to store keypad output
    keypadOld   VAR  Word                       ' Variable space to store old keypad output
    temp        VAR  Nib                        ' Variable space for polling column states
    
    #IF _No_SPRAM #THEN
     buf  VAR  Byte(10)
    #ELSE
     chkChar VAR Byte
    #ENDIF
    tagNum   VAR Nib
    tkn      VAR Byte
    char     VAR Byte
    
    counter     VAR   Word                       ' Counter Variable
    Password    DATA  "1234"                     ' Store "secret" password here.
    index       VAR   Nib                        ' Index variable.
    userEntry   VAR   Byte(4)                    ' Store user entered password.
    
    
    ' -----[ EEPROM Data ]-----------------------------------------------------
    
    
    
    ' -----[ Initialization ]--------------------------------------------------
    
    
    ' -----[ Program Code ]----------------------------------------------------
    
    DO
    
    
    DEBUG "Enter password: "                                   ' User instructions
    HIGH TxPin                       ' Set serial pin port high
    PAUSE 100                        ' Pause to initialize
    SEROUT TxPin, n9600, [12, 17]    ' Clear, turn on backlight
    SEROUT TxPin, n9600, ["DOOR LOCKED", 13] ' Print text, line feed
    SEROUT TxPin, n9600, [212, 220]  ' Quarter A note
    PAUSE 3000                       ' Wait 3 seconds
    SEROUT TxPin, n9600, [18]        ' Turn backlight off
    DEBUGIN STR userEntry \4                                   ' Get user input password.
    FOR index = 0 TO 3                                         ' Check array against DATA
    READ Password + index, keypad                              ' Get next password char
    IF keypad <> userEntry(keypad) THEN EXIT                    ' Compare to user input,
    NEXT                                                       ' exit if not equal.
    IF index <> 4 THEN                                         ' If exit, then index not equal
    DEBUG CR,"Password not correct.", CR                       ' to 5 and pass is not correct.
      DO                                                       ' Alarm is ON
      SEROUT 2, 84, [22, 12] ' Initialize LCD
    PAUSE 500 ' 1/2 second delay
    ' Display evenly spaced characters on Line 0 every 200 ms.
    SEROUT TxPin, n9600, [12, 17]    ' Clear, turn on backlight
    SEROUT TxPin, n9600, ["UNAUTHORIZED", 13] ' Print text, line feed
    SEROUT TxPin, n9600, [212, 220]  ' Quarter A note
    PAUSE 3000                       ' Wait 3 seconds
    SEROUT TxPin, n9600, [18]        ' Turn backlight off]
    
    PAUSE 3000
      LOOP
    ENDIF
    LOOP UNTIL index = 4                                        ' Only get out of loop when  ' index = 5.
    
    
    
    DEBUG "Authorized Unlocking Door", CR
    PAUSE 250
    DEBUG "Door Unlocked", CR
    FOR counter= 1 TO 59
    PULSOUT 14, 1000
    PAUSE 2
    NEXT
    
    SEROUT TxPin, n9600, [12, 17]    ' Clear, turn on backlight
    SEROUT TxPin, n9600, ["AUTHORIZED", 13] ' Print text, line feed
    SEROUT TxPin, n9600, [212, 220]  ' Quarter A note
    PAUSE 3000                       ' Wait 3 seconds
    SEROUT TxPin, n9600, [18]        ' Turn backlight off
    SEROUT 2, 84, [12]
    
    PAUSE 5000
    
    DEBUG  "Locking Door", CR, CR
    
    PAUSE 1000
    
    FOR counter= 1 TO 59
    PULSOUT 14, 250
    PAUSE 2
    NEXT
    DEBUG "Door Locked", CR, CR
    SEROUT TxPin, n9600, [12, 17]    ' Clear, turn on backlight
    SEROUT TxPin, n9600, ["DOOR LOCKED", 13] ' Print text, line feed
    SEROUT TxPin, n9600, [212, 220]  ' Quarter A note
    PAUSE 3000                       ' Wait 3 seconds
    SEROUT TxPin, n9600, [18]        ' Turn backlight off
    
    END
    
    ' -----[ Subroutines ]-----------------------------------------------------
    
    ' -----[ Subroutine - ReadKeypad ]-------------------------------------------------
    ' Read keypad button states
    ReadKeypad:
      keypad = 0
      OUTL   = %00000000                        ' Initialize IO
      DIRL   = %00000000
    
      FOR row = 0 TO 3
        DIRB = %1111                            ' Set columns (P7-P4) as outputs
        OUTB = %0000                            ' Pull columns low (act as pull down)
        OUTA = 1 << Row                         ' Set rows high one by one
        DIRA = 1 << Row
    
        temp = 0                                ' Reset temp variable to 0
        FOR column = 0 TO 3
          INPUT (column + 4)                    ' Set columns as inputs one by one
          temp = temp | (INB & (1 << column))   ' Poll column state and store in temp
        NEXT
    
        keypad = keypad << 4 | (Temp REV 4)     ' Store keypad value
      NEXT
    RETURN
    
    ' -----[ Subroutine - Update ]-----------------------------------------------------
    ' Graphical depiction of keypad
    Update:
      DEBUG CRSRXY,0,7,
        "+---+---+---+---+",CR,
        "|   |   |   |   |",CR,
        "+---+---+---+---+",CR,
        "|   |   |   |   |",CR,
        "+---+---+---+---+",CR,
        "|   |   |   |   |",CR,
        "+---+---+---+---+",CR,
        "|   |   |   |   |",CR,
        "+---+---+---+---+"
    RETURN
    
    ' -----[ Subroutine - Display ]----------------------------------------------------
    ' Display button pressed in keypad graphic
    Display:
      IF KeyPad.BIT15 THEN  DEBUG CRSRXY, 02,08,"1"
      IF Keypad.BIT14 THEN  DEBUG CRSRXY, 06,08,"2"
      IF KeyPad.BIT13 THEN  DEBUG CRSRXY, 10,08,"3"
      IF Keypad.BIT12 THEN  DEBUG CRSRXY, 14,08,"A"
      IF KeyPad.BIT11 THEN  DEBUG CRSRXY, 02,10,"4"
      IF Keypad.BIT10 THEN  DEBUG CRSRXY, 06,10,"5"
      IF KeyPad.BIT9  THEN  DEBUG CRSRXY, 10,10,"6"
      IF Keypad.BIT8  THEN  DEBUG CRSRXY, 14,10,"B"
      IF KeyPad.BIT7  THEN  DEBUG CRSRXY, 02,12,"7"
      IF Keypad.BIT6  THEN  DEBUG CRSRXY, 06,12,"8"
      IF KeyPad.BIT5  THEN  DEBUG CRSRXY, 10,12,"9"
      IF Keypad.BIT4  THEN  DEBUG CRSRXY, 14,12,"C"
      IF KeyPad.BIT3  THEN  DEBUG CRSRXY, 02,14,"*"
      IF Keypad.BIT2  THEN  DEBUG CRSRXY, 06,14,"0"
      IF KeyPad.BIT1  THEN  DEBUG CRSRXY, 10,14,"#"
      IF Keypad.BIT0  THEN  DEBUG CRSRXY, 14,14,"D"
    RETURN
    

    Which is based on this code:
    ' {$STAMP BS2}
    ' {$PBASIC 2.5}
    
    
    row         VAR  Nib                        ' Variable space for row counting
    column      VAR  Nib                        ' Variable space for column counting
    keypad      VAR  Word                       ' Variable space to store keypad output
    keypadOld   VAR  Word                       ' Variable space to store old keypad output
    temp        VAR  Nib                        ' Variable space for polling column states
    
    DEBUG CLS                                   ' Clear Debug Terminal
    GOSUB Update                                ' Display keypad graphic
    
    DO
      GOSUB ReadKeypad                          ' Read keypad button states
      DEBUG HOME, BIN16 keypad, CR, CR,         ' Display 16-bit keypad value
                  BIN4 keypad >> 12,CR,         ' Display 1st row 4-bit keypad value
                  BIN4 keypad >> 8, CR,         ' Display 2nd row 4-bit keypad value
                  BIN4 keypad >> 4, CR,         ' Display 3rd row 4-bit keypad value
                  BIN4 keypad                   ' Display 4th row 4-bit keypad value
    
      IF keypad <> keypadOld THEN               ' If different button is pressed,
        GOSUB Update                            ' update the keypad graphic to clear
      ENDIF                                     ' old display
    
      IF keypad THEN                            ' Display button pressed in graphic
        GOSUB display
      ENDIF
    
      keypadOld = keypad                        ' Store keypad value in variable keypadOld
    LOOP
    
    
    
    ' -----[ Subroutine - ReadKeypad ]-------------------------------------------------
    ' Read keypad button states
    ReadKeypad:
      keypad = 0
      OUTL   = 000000                        ' Initialize IO
      DIRL   = 000000
    
    
      FOR row = 0 TO 3
        DIRB = 11                            ' Set columns (P7-P4) as outputs
        OUTB = 00                            ' Pull columns low (act as pull down)
        OUTA = 1 << Row                         ' Set rows high one by one
        DIRA = 1 << Row
    
    
        temp = 0                                ' Reset temp variable to 0
        FOR column = 0 TO 3
          INPUT (column + 4)                    ' Set columns as inputs one by one
          temp = temp | (INB & (1 << column))   ' Poll column state and store in temp
        NEXT
    
    
        keypad = keypad << 4 | (Temp REV 4)     ' Store keypad value
      NEXT
    RETURN
    
    
    ' -----[ Subroutine - Update ]-----------------------------------------------------
    ' Graphical depiction of keypad
    Update:
      DEBUG CRSRXY,9,15,
        "+---+---+---+---+",CR,
        "|   |   |   |   |",CR,
        "+---+---+---+---+",CR,
        "|   |   |   |   |",CR,
        "+---+---+---+---+",CR,
        "|   |   |   |   |",CR,
        "+---+---+---+---+",CR,
        "|   |   |   |   |",CR,
        "+---+---+---+---+"
    RETURN
    
    
    ' -----[ Subroutine - Display ]----------------------------------------------------
    ' Display button pressed in keypad graphic
    Display:
      IF KeyPad.BIT15 THEN  DEBUG CRSRXY, 02,08,"1"
      IF Keypad.BIT14 THEN  DEBUG CRSRXY, 06,08,"2"
      IF KeyPad.BIT13 THEN  DEBUG CRSRXY, 10,08,"3"
      IF Keypad.BIT12 THEN  DEBUG CRSRXY, 14,08,"A"
      IF KeyPad.BIT11 THEN  DEBUG CRSRXY, 02,10,"4"
      IF Keypad.BIT10 THEN  DEBUG CRSRXY, 06,10,"5"
      IF KeyPad.BIT9  THEN  DEBUG CRSRXY, 10,10,"6"
      IF Keypad.BIT8  THEN  DEBUG CRSRXY, 14,10,"B"
      IF KeyPad.BIT7  THEN  DEBUG CRSRXY, 02,12,"7"
      IF Keypad.BIT6  THEN  DEBUG CRSRXY, 06,12,"8"
      IF KeyPad.BIT5  THEN  DEBUG CRSRXY, 10,12,"9"
      IF Keypad.BIT4  THEN  DEBUG CRSRXY, 14,12,"C"
      IF KeyPad.BIT3  THEN  DEBUG CRSRXY, 02,14,"*"
      IF Keypad.BIT2  THEN  DEBUG CRSRXY, 06,14,"0"
      IF KeyPad.BIT1  THEN  DEBUG CRSRXY, 10,14,"#"
      IF Keypad.BIT0  THEN  DEBUG CRSRXY, 14,14,"D"
    RETURN
    
    
    '-----[ PassCode Entry ]----------------------------------------------------------
    ' Entering passcode
    
    
    counter     VAR   Word                       ' Counter Variable
    Password    DATA  "1234"                     ' Store "secret" password here.
    index       VAR   Nib                        ' Index variable.
    userEntry   VAR   Byte(4)                    ' Store user entered password.
    
    
    
    
    DO
    
    
    DEBUG "Enter password: "                                   ' User instructions
    DEBUGIN STR userEntry \4                                   ' Get user input password.
    FOR index = 0 TO 3                                         ' Check array against DATA
    READ Password + index, keypad                              ' Get next password char
    IF keypad <> userEntry(keypad) THEN EXIT                    ' Compare to user input,
    NEXT                                                       ' exit if not equal.
    IF index <> 4 THEN                                         ' If exit, then index not equal
    DEBUG CR,"Password not correct.", CR                       ' to 5 and pass is not correct.
      DO                                                       ' Alarm is ON
      FREQOUT 5, 500, 3000                                     ' Creation of a beeping sound
      HIGH 13                                                  ' Flashing LEDs
      LOW 12
      PAUSE 100
      FREQOUT 5, 500, 3000
      HIGH 12
      LOW  13
      LOOP
    ENDIF
    LOOP UNTIL index = 4                                        ' Only get out of loop when  ' index = 5.
    
    
    DEBUG CR, "Password is correct;", CR,                       ' Program can move on when
                          "program can continue..."             ' password is correct.
    
    
    HIGH 13
       FOR counter = 1 TO 150                                   ' "Door Opens" (Sliding door)
       PULSOUT 14, 1200
       PAUSE 20
       NEXT                                                     ' Light ON for 5 sec
    PAUSE 5000
    LOW 13                                                      ' Then off
       FOR counter = 1 TO 150                                   ' "Door closes" (Sliding door)
       PULSOUT 14, 300
       PAUSE 20
       NEXT
    END
    

    We both don't have much knowledge with STAMP. Most of what we know about microcontrollers is from Ardunio and using C++
  • Mike GreenMike Green Posts: 23,101
    edited 2015-02-25 07:15
    Unfortunately, you're trying to combine two pieces of code that were meant for different things and they don't combine as you've noticed. One scans a 4 x 4 keypad and returns 16 bits in a word, one bit for each key indicating which keys were pressed. The other handles organizing password input and display on an LCD, but expects input from the connected PC. There's a big piece missing that takes a 16 bit bitmap (for the keys), figures out when a key is pressed and released, and converts the bit for the pressed key into a character. For now I'd forget about the password handling and the LCD and work on this missing piece.

    ReadKeypad is good, but you don't need Update or Display or keypadOld. Have you looked at NCD and LOOKUP yet? You have to understand those.

    You need to create a subroutine (labelled GetAKey) that first sits in a loop (DO ... LOOP) calling ReadKeypad until keypad is zero. This ensures that none of the keys are pressed. Next in that subroutine is another loop (DO ... LOOP) that calls ReadKeypad until keypad is non-zero. This ensures that some key is pressed, maybe more than one. Now you have to identify which key is pressed and translate it like:

    keypad = (NCD keypad) - 1
    lookup keypad,["D","#","0","*","C","9","8","7","B","6","5","4","A","3","2","1"],keypad

    The result in keypad is the character code and your subroutine can RETURN with that in keypad.

    Go ahead and create the GetAKey subroutine. Read the Manual sections on DO/LOOP. Write a short main program (that comes first) that calls GetAKey and displays the result with DEBUG. See what you get.
  • GenetixGenetix Posts: 1,749
    edited 2015-02-26 12:52
    Cambodia,

    Mike Green has gotten you off to a great start!

    You should always have the Stamp Manual handy.
    http://www.parallax.com/sites/default/files/downloads/27218-Web-BASICStampManual-v2.2.pdf

    The older version of What's a Microcontroller had a password check program starting on page 289.
    https://www.pololu.com/file/0J204/What%27s_a_microcontroller_text.pdf

    Chapter 1 of the old Smart Sensors text shows how to use the Serial LCD.
    http://www.parallax.com/sites/default/files/downloads/28029-Smart-Sensors-Text-v1.0.pdf

    To modify ReusablePasswordChecker.bs2 you need to change all the DEBUG statements to SEROUT statements.
    Adding CR CON 13 to the Constants section of your program will take care of any CR that is part of a DEBUG statement since a CR is actually an ASCII code of 13.
    Also, if you notice some of your SEROUT statements end in 13 which is the same as sending a CR, so you can change them to CR since that's what they mean.
    The password entry and check code is more of a problem since DEBUGIN will read in a String of 5 characters.
    You can either call Get-A-Key 5X and store each value in a String BEFORE the FOR..NEXT or call Get_A_Key before the READ statement in the FOR...NEXT loop.
    Remember though that normally a person will see the display change as each key is pressed. You can either display the key that was pressed or * so no one else can see it. To do this you would first call Get_A_Key and then send a SEROUT to the LCD.
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2015-02-27 11:24
    Here's a post where I showed an easy way to read a numeric value using the keypad. http://forums.parallax.com/showthread.php/156472-programming-the-basic-stamp-with-keypad-to-be-able-to-read-and-write-00-99?p=1286903&viewfull=1#post1286903

    You can use the keyscan subroutine portion of this along with the attached code to see how this kind of stuff is done. The attached program is from a demo I did back in 2006 using an EDE1144 keypad decoder. But between the two programs there is a lot of useful information there. Hopefully you will find it useful.

    The Security test code even has a timeout function on the input as well as the ability to support extra functions from the keypad.
Sign In or Register to comment.