Shop OBEX P1 Docs P2 Docs Learn Events
ARC - Arbitrary Row and Column keyboard scanner — Parallax Forums

ARC - Arbitrary Row and Column keyboard scanner

Peter JakackiPeter Jakacki Posts: 10,193
edited 2011-10-05 16:05 in Propeller 1
Here is a keyboard scanner that is not limited by the number or positions of the rows and columns in a keyboard matrix. Essentially you can take a bunch of unused pins from your Prop, even though they may be scattered here and there, and use these to scan a keyboard/keypad. My original implementation had all the rows and columns neatly together but the keypad didn't match up. So this code will handle those different keypads and/or allow you to use any combination of port pins for your matrix.

This code is not fully tested although it seems to work fine. I polled this every 1ms and also every 10ms and keys were captured just as well in the latter. Also, this code is part of a combination SmartSerialLCD object I am preparing for possible release. Contrary to the name it doesn't have to be serial but accessed as if it were serial rather than having many call methods so therefore it can easily be tethered over a serial link.

The hardware it is being developed for is the MultiLCD which backpacks onto a 20x4 character or 128x64 graphic LCD. Besides LCD and keyboard interfaces it includes an SD card, raw piezo transducer, and options for RS485, audio out, USB/PS2 keypad etc.
'*************************************************************************
'
'   ARC KEYBOARD SCANNER V1.0
'   October 2011 Peter Jakacki
'
'   ARBITRARY ROW & COLUMN KEYBOARD SCANNER
'   Any combination of row and column pins can be used
'   Port pins that are non-sequential can therefore be used
'   Also a change of keypad which has different row and column conections
'   can easily be accommodated
'
'   Hardware requirments are that each port pin has a current limit resistor (1K) along
'   with a corresponding pullup at least 5 times the value of the CLR
'
'           VDD---10K---|
'  port pin)------1K----|--COLUMN or ROW
'
'*************************************************************************

var
  long rowmask,colmask,lastkey,debounce

'
' Application informs the keypad scanner of which pins it wants for rows and which for columns
' i.e.  InitKeys(%11001100,%100000110010) ' note that the pins are scattered
'
pub Initkeys(rows,columns)      ' bitmasks of rows and columns - can be arbitrary
  rowmask := rows
  colmask := columns

' Application should poll "key" on a regular basis from 100 to 1000 times a second
' 'key' will return -1 if there is no new key
'
pub key | i
  result := scankeys
  if result+1                   ' process as long as keycode is not -1
    i~                          ' scan through scancode to ASCII translation table
    repeat until word[@keytbl][i] == 0                  ' end of table?
      if result == word[@keytbl][i]                     ' do we have a match?
         bip                                           ' short little bip
         return word[@keytbl][i+1]                      ' yes, return with ASCII (or 16-bit code)
      i += 2                                            ' jump to next table entry

' application specific short key beep (bip)
pri Bip
  dira[piezo]~~
  sound(80,50)

' Application can also call scankeys which will return the 10-bit scancode if a key is pressed
'
pub scankeys  | n,i,j                ' scan keypad and return with code else -1
  result := -1
  outa &= !colmask              ' drive all columns low with pullups
  dira |= colmask               ' all columns active
  n := ina & rowmask
  if n <> rowmask               ' active column detected if result does not match rowmask
    dira &= !colmask            ' return columns inactive
    debounce := 3              ' preset debounce for long enough time to cover debounce
    if lastkey == -1            ' process key as long as it's a new key press (must be idle before)
      repeat i from 0 to 31     ' check all possible mask positions
        if colmask & |<i        ' column in this position?
          dira[i]~~             ' drive this column low? (open-drain)
          n := ina & rowmask
          dira[i]~              ' release column
          if n <> rowmask         ' found the column yet?
                                ' yes, column found, now find row that's different
                                ' if rowmask = 110011 and n = 100011
                                ' 110011 xor 100011 = 10000
            n ^= rowmask        ' get active bit
            n := >|n            ' convert mask to a value+1
            n--                 ' zero based
            n += i<<5           ' merge row and column codes
            lastkey := n

            result := n         ' return with an intermediate 10-bit scan code
  else
    if debounce
      debounce--
    else
      lastkey := -1

dat
keytbl
        word $012b,"1"
        word $010b,"2"
        word $00cb,"3"
        word $012a,"4"
        word $010a,"5"
        word $00ca,"6"
        word $0120,"7"
        word $0100,"8"
        word $00c0,"9"
        word $0122,"*"
        word $0102,"0"
        word $00c2,"#"
        word  0

Comments

  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2011-10-05 16:05
    I have now converted this code into an object along with demo code. It's been added to the OBEX HID section. With 28 pins you could encode a 196 key matrix!
    BTW, only the pull-up resistors are really needed, the other 1K resistor is only if you are using the port pins for other functions such as driving LCDs.
Sign In or Register to comment.