November 21, 2024, 01:00:24 PM

News:

Got VSA?  Want to use your Prop-SX?  Now you can!  See the VSA section of the Library forum for Prop-SX code that works with VSA.


3x4 matrix keypad with Prop 2

Started by freakyland, April 21, 2011, 03:39:56 PM

Previous topic - Next topic

freakyland

I have been trying to integrate my 3x4  matrix keypad to work with the Prop-2.  It is a basic telephone layout keypad arranged like this:
1  2  3
4  5  6
7  8  9
*  0  #

There are 7 pins from the keypad (1-4 are rows, 5-7 are columns)

I think I have come close, but have decided its time to ask for help converting the 2x8 matrix midi program from these forums (http://www.efx-tek.com/php/smf/index.php?topic=673.0)  I have been able to get the Prop2 to register a button press on all of the buttons, but have not been successful doing anything with the value. 

The most recent iteration of the code is a bit garbled, which is why I am not posting it here).  It is basically a hybrid of the 2x8 program and the nuts and volts matrix scanner program. (http://www.parallax.com/dl/docs/cols/nv/vol1/col/nv22.pdf).

The nuts and volts column is written for the BS2, and I'm sure there are some variations to use the hardware already in place on the Prop-2.

Thanks in advance!!

bsnut

What are you trying to do with this keypad? Taking number value is easy to do. All you need to do with Scott Edwards program is to use the DEBUG to show your values that are pressed on the keypad. Replace this line in his program
"key pressed = ", hex key,cr

to look like this
DEBUG "key pressed = ", dec key,cr

What you were seeing before was hex value of "key" and you should see the decimal value for which keypad button is pressed when you rerun the program.   
William Stefan
The Basic Stamp Nut

freakyland

I'm basically wanting to set up the keypad for a bomb-prop I am working on, (and eventually also for a password door lock mechanism).  Set a 4 digit password to arm the bomb (probably also with a # to set the code, but I can work that in later), and need to re-enter it to deactivate it.  Buttons should be debounced to only register once when pressed.

I shouldn't have a problem writing the code to work with the values once I can get get them to the Prop2.  I could get a debug command to show a button had been pressed, but I wasn't getting an intelligible result as to which key it was; so its probably getting crossed up when I combined the programs.  If I get a chance, I'll clean up the code and post what I have been working with.  I'm expecting the trouble is in the NCD/Math part that I am running into issues, but it could be in the hardware as well.

The Scott Edwards setup has 2 banks of resistors, and scans a 0 across the rows.  Do I need all those resistors with the Prop2?  I know the 220ohm Keypad side ones are technically optional, but what about the pullups?  I would expect these are necessary, but will that actually work with the Prop2?

In Jon's schematic (from this forum)  the only resistors are the 470ohm on the columns; is this because the Prop2 already that with the ULN?   I like the simplicity of Jon's 2x8 matrix ( many fewer resistors).  Jon's also scans a 1 instead of a 0 across; is this a preference thing or a function of working with the built in hardware?

JonnyMac

Here's how you can wire the keyboard:



And here's a subroutine that will scan them.  This subroutine needs a Word variable called keys.   You have to be very careful with this code: 1) never make P3..P0 outputs and, 2) to deactivate a column you must use INPUT (not LOW).

Get_Keys:
  keys = $000                                   ' clear old scan

  HIGH Col2                                     ' activate column
  keys = (keys << 4) | INA                      ' add column to scan
  INPUT Col2                                    ' INPUT only

  HIGH Col1
  keys = (keys << 4) | INA
  INPUT Col1

  HIGH Col0
  keys = (keys << 4) | INA
  INPUT Col0

  RETURN


Now... the keyboard may I show may differ from yours.  No worries, we can code to re-map the keyboard.  First, you want to check for multiple keys (invalid) -- you can do something like this:

Count_Keys:
  nKeys = 0
  FOR idx = 0 TO 11
    nKeys = nKeys + keys.LOWBIT(idx)
  NEXT
  RETURN


If this returns 1 you can check to determine which key like this:

  theKey = (NCD keys) - 1

Now the key can be remapped to your keyboard like this:

  theKey = LOOKUP theKey, [14, 7, 4, 1, 0, 8, 5, 2, 15, 9, 6, 3]

Caveat: I've done all this stuff before so I know the process works; you may have to tune my code a bit for your setup.
Jon McPhalen
EFX-TEK Hollywood Office

freakyland

Yep, that setup worked wonderfully, and much more minimal from a hardware perspective than the other options I had tested!  Thanks, Jon, this project may work out after all!!!

What I am working with now is creating the code to store a 4 digit number (access code if you will) that I will be able to access again later.  I will be using the * (10) and #(11) keys as special keys to clear or allow access to the disarm mode of the bomb (I'll work out those details later, once I figure out exactly how the code will work into the greater scheme).  Once I have the code to be able to create/store the 4 digit access code, I'm sure I can expand it to fit my other needs.

What is the way to create a 4 digit decimal number with the keypad?  Should I store each digit in EEPROM as its gathered?  The direction I have been heading(to little avail) was digit1*1000 +digit2 *100+digit3 *10 + digit4...  Does the "DIG" command work for storing a digit as well as reading it (ie "code DIG 4 = value", etc), or is it only for reading a value?

Here is the code I have put together to read my keypad.  It correctly displays the most recently pressed button (thekey) on the terminal without giving multiple results from a single press (by comparing it to oldkey).  I wouldn't mind debouncing the trigger inputs to eliminate the chance of a false electrical trigger somewhere (but maybe the way it is wired up decreases that chance pretty well on its own). 

I'm assuming there is a simpler and more elegant way to do all of this (and wouldn't mind being let in on the secrets of the master!!).  This whole thing will eventually need to be able to be a subroutine in a much more complex program (mostly written, but I'm planning on at least testing my own integration skills).  I still would appreciate, however, any suggestions that anyone sees that will save me major headaches in the near future!

Okay, I think thats probably enough questions and comments for a few more steps forward!  Thanks again for the great support!

' ========================================================================
'   {$STAMP BS2}
'   {$PBASIC 2.5}
'
'
' =========================================================================

  Col2            PIN     6
  Col1            PIN     5                       ' key maxtix column outputs
  Col0            PIN     4

  KeysIn          VAR     INA                     ' key matrix row inputs


' -----[ Constants ]-------------------------------------------------------

  IsOn            CON     1                       ' for active-high in/out
  IsOff           CON     0

' -----[ Variables ]-------------------------------------------------

  idx             VAR     Byte                                        ' index used for loop

  keys            VAR     Word                                        ' value used in Get_Keys
  nkeys           VAR     Byte                                        ' number of keys pressed
  theKey          VAR     Byte                                        ' value of specific key pressed
  oldKey          VAR     Byte                                        ' old key used to prevent multitrigger

' -----[ Initialization ]--------------------------------------------------

Reset:
  oldKey = 100                                                        ' Set repress marker to 100 (arbitrary value)

' -----[ Program Code ]----------------------------------------------------

Main:
  GOSUB Count_Keys                                                    ' check to see if only 1 key is pressed
  GOSUB Get_Keys                                                      ' scan matrix for pressed key
  IF nKeys = 0 THEN Main                                              ' if no keys pressed, goto repeat
  theKey = (NCD keys) - 1                                             ' if pressed, convert key value to value between 0 and 11
  IF theKey = oldKey THEN Main                                    ' prevents multi-triggering from 1 press
  oldKey = theKey                                                          ' set current value to compare back to later
  IF theKey = 255 THEN Released                                       ' 255 is returned on release of button
  LOOKUP theKey, [1, 4, 7, 10, 2, 5, 8, 0, 3, 6, 9, 11], theKey       ' convert value to match markings on keypad, store as "theKey"
  DEBUG CLS, DEC theKey, CR                                           ' display key in debug terminal
  GOTO Main                                                           ' repeat

Released:
  oldKey = 100                                                        ' reset repress marker to 100 to allow for new press
    GOTO Main                                                         ' repeat

  ' -----[ Subroutines ]-----------------------------------------------------

Count_Keys:                                     ' count number of buttons pressed
  FOR idx = 0 TO 11
    nKeys = nKeys + keys.LOWBIT(idx)            ' number of buttons = 0 to 12
  NEXT
  RETURN

' -------------------------------------------------------------------------

Get_Keys:
  keys = $000                                   ' clear old scan

  HIGH Col2                                     ' activate column
  keys = (keys << 4) | INA                      ' add column to scan
  INPUT Col2                                    ' turn off column, INPUT only

  HIGH Col1
  keys = (keys << 4) | INA
  INPUT Col1

  HIGH Col0
  keys = (keys << 4) | INA
  INPUT Col0

  RETURN

' -----[ User Data ]---------------------------------------------------------


JonnyMac

April 27, 2011, 01:05:13 PM #5 Last Edit: April 27, 2011, 08:19:24 PM by JonnyMac
Sorry for the delay, was traveling yesterday (am presently sitting in EFX-TEK home office in TN).

I did a lot of clean-up; have a look, it should make sense.  Remember that PBASIC2 has advanced features (like IF-THEN-ELSE) so you can simplify a bit of the code.

' =========================================================================
'
'   File......
'   Purpose...
'   Author....
'   E-mail....
'   Started...
'   Updated...
'
'   {$STAMP BS2}
'   {$PBASIC 2.5}
'
' =========================================================================


' -----[ Program Description ]---------------------------------------------


' -----[ Revision History ]------------------------------------------------


' -----[ I/O Definitions ]-------------------------------------------------

Col2            PIN     6                       ' key matrix colums
Col1            PIN     5
Col0            PIN     4

KeysIn          VAR     INA                     ' key matrix rows


' -----[ Constants ]-------------------------------------------------------

IsOn            CON     1                       ' for active-high in/out
IsOff           CON     0


' -----[ Variables ]-------------------------------------------------------

idx             VAR     Byte                    ' loop index

keyBits         VAR     Word                    ' holds key scan
nKeys           VAR     Byte                    ' keys pressed
theKey          VAR     Byte                    ' new key press
oldKey          VAR     Byte                    ' old key press

' -----[ Initialization ]--------------------------------------------------

Reset:
 DEBUG CLS, "Keypad Test", CR

 oldKey = 99                                   ' mark as released

' -----[ Program Code ]----------------------------------------------------

Main:
 GOSUB Get_Keys                                ' scan matrix
 GOSUB Count_Keys                              ' count pressed keys

 IF (nKeys = 1) THEN                           ' if just 1 pressed
   GOTO Decode                                 '  check new key
 ELSE
   IF (nKeys = 0) THEN                         ' if nothing pressed
     oldKey = 99                               '  mark as released
   ENDIF
   GOTO Main
 ENDIF

Decode:
 theKey = (NCD keyBits) - 1                    ' decode key bit

 IF (theKey = oldKey) THEN
   GOTO Main                                   ' do not allow repeat
 ELSE
   oldKey = theKey                             ' save for next
 ENDIF

 ' remap for physical keyboard

 LOOKUP theKey, [1, 4, 7, 10, 2, 5, 8, 0, 3, 6, 9, 11], theKey

 DEBUG "Key = ", DEC theKey, CR                ' show new key

 GOTO Main


 ' -----[ Subroutines ]---------------------------------------------------

Count_Keys:
 FOR idx = 0 TO 11
   nKeys = nKeys + keyBits.LOWBIT(idx)         ' count active-high bits
 NEXT
 RETURN

' -------------------------------------------------------------------------

Get_Keys:
 keyBits = $000                                ' clear old scan

 HIGH Col2                                     ' activate column
 keyBits = (keyBits << 4) | KeysIn             ' add column to scan
 INPUT Col2                                    ' turn off column, INPUT only

 HIGH Col1
 keyBits = (keyBits << 4) | KeysIn
 INPUT Col1

 HIGH Col0
 keyBits = (keyBits << 4) | KeysIn
 INPUT Col0

 RETURN

' -----[ User Data ]-------------------------------------------------------
Jon McPhalen
EFX-TEK Hollywood Office

freakyland

The cleaned up code does make sense!!  Thanks!

I haven't played with if...then...else yet, so i guess I have a new function to play around with!  I haven't had a chance to run it, but is there a missing "Decode:" heading?  There is a "GOTO Decode" line, but I don't see the routine it is calling. My guess is it is meant to be right after the first If.Then.Else.

How would you recommend going about collecting/storing/retrieving the 4 digit passcode with this routine?   I'm assuming the whole thing will end up being a sub-routine (at least until the HC-8 comes on line and I can convert to Propeller!!)  I would like to be able to enter a new passcode each time (as opposed to setting a permanent), and will later want to compare the 4 digits later to "unlock" the device.  Am I correct in assuming there will need to be a marker variable (1 to 4) that is updated once a value is registered that can be linked to storing the 4 separate digits which can be accesses/displayed/compared as need be?

P.S.  Just over a day and a half turn-around on a response is probably not something worthy of needing an apology from a busy man such as yourself!! ;)


JonnyMac

Quotebut is there a missing "Decode:"

Whoops... I'm such a nut about my posts I went back and cleaned up my post and accidentally removed that label.  I put it back (right above the NCD line).

Here's a suggestion for reading a password:

' =========================================================================
'
'   File......
'   Purpose...
'   Author....
'   E-mail....
'   Started...
'   Updated...
'
'   {$STAMP BS2}
'   {$PBASIC 2.5}
'
' =========================================================================


' -----[ Program Description ]---------------------------------------------


' -----[ Revision History ]------------------------------------------------


' -----[ I/O Definitions ]-------------------------------------------------

Col2            PIN     6                       ' key matrix colums
Col1            PIN     5
Col0            PIN     4

KeysIn          VAR     INA                     ' key matrix rows


' -----[ Constants ]-------------------------------------------------------

IsOn            CON     1                       ' for active-high in/out
IsOff           CON     0

PW0             CON     0                       ' password digits
PW1             CON     7
PW2             CON     2
PW3             CON     5


' -----[ Variables ]-------------------------------------------------------

keyBits         VAR     Word                    ' holds key scan

idx             VAR     Byte                    ' loop index
nKeys           VAR     Byte                    ' keys pressed
theKey          VAR     Byte                    ' new key press
check           VAR     Byte

pwWork          VAR     Byte(4)                 ' password array


' -----[ Initialization ]--------------------------------------------------

Reset:
  DEBUG CLS


' -----[ Program Code ]----------------------------------------------------

Main:
  DEBUG "Enter password: "

  GOSUB Get_Password
  check = 0
  FOR idx = 0 TO 3                              ' check digits
    LOOKUP idx, [PW0, PW1, PW2, PW3], theKey
    IF (theKey = pwWork(idx)) THEN
      check = check + 1
    ENDIF
  NEXT

  IF (check = 4) THEN                           ' did all match?
    DEBUG CR, "-- pass", CR, CR
  ELSE
    DEBUG CR, "-- fail!", CR, CR
  ENDIF

  GOTO Main


' -----[ Subroutines ]-----------------------------------------------------

Get_Password:
  FOR idx = 0 TO 3
    DO
      GOSUB Get_Keys
      GOSUB Count_Keys
    LOOP UNTIL (nKeys > 0)                      ' wait for a press

    IF (nKeys = 1) THEN                         ' valid?
      theKey = (NCD keyBits) - 1
      LOOKUP theKey, [1, 4, 7, 10, 2, 5, 8, 0, 3, 6, 9, 11], theKey
      pwWork(idx) = theKey
      IF (theKey < 10) THEN
        DEBUG DEC theKey
      ELSEIF (theKey = 11) THEN
        DEBUG "#"                               ' show as single character
      ELSE
        DEBUG "*"
      ENDIF
    ELSE
      pwWork(idx) = "?"                         ' no, bogus input
      DEBUG DEC "?"
    ENDIF
  NEXT
  RETURN

' -------------------------------------------------------------------------

Count_Keys:
  FOR idx = 0 TO 11
    nKeys = nKeys + keyBits.LOWBIT(idx)         ' count active-high bits
  NEXT
  RETURN

' -------------------------------------------------------------------------

Get_Keys:
  keyBits = $000                                ' clear old scan

  HIGH Col2                                     ' activate column
  keyBits = (keyBits << 4) | KeysIn             ' add column to scan
  INPUT Col2                                    ' turn off column, INPUT only

  HIGH Col1
  keyBits = (keyBits << 4) | KeysIn
  INPUT Col1

  HIGH Col0
  keyBits = (keyBits << 4) | KeysIn
  INPUT Col0

  RETURN

' -----[ User Data ]-------------------------------------------------------
Jon McPhalen
EFX-TEK Hollywood Office