Sunday, February 1, 2015

Many pins, easy keyboard

Having many I/O pins directly addressable means that you can immediately scan a keyboard.

Example: an intercom numeric keyboard, 4 rows by 4 columns (16 keys total):


it has 8 pins (4 for rows, 4 for columns): when you press a key, their respective pins are shorted.



Imagine you have those 8 pins on a single port of the Arduino, for example PORTC and its data direction register DDRC. You don't have to use digitalRead, you just read and write PORTC value, sending '1' to all columns to check if any row has changed, and vice-versa. For example:

int keypressed()
{
  // start with first scan: high bits (columns)
  DDRC  = B11110000;
  PORTC = B11110000;
  int c = PINC & B00001111;
  if(c == 0) return 0;  // return if "no key pressed"

  // a key was pressed, and now we know the columns
  // now: second scan: low bits (rows)
  DDRC  = B00001111;
  PORTC = B00001111;
  int r = PINC & 0xf0;
  if(r == 0) return -1;  // return "unknown" if key was released before this point

  switch(c | r)
  {
    case B10001000: return '1';
    case B10000100: return '2';
    case B10000010: return '3';
    case B10000001: return '4';
    case B01001000: return '5';
    case B01000100: return '6';
    case B01000010: return '7';
    case B01000001: return '8';
    case B00101000: return '9';
    case B00100100: return '0';
    case B00100010: return 'z';   // "lamp" key
    case B00100001: return 'u';   // "phone" key
    case B00011000: return '#';
    case B00010100: return '*';
    case B00010010: return 'k';   // "key" key
    case B00010001: return '\n';  // "return" key
  }

  return -1;  // return "unknown" if more than one key pressed
}


Code needs a bit of extra to check for key-released event and bouncing; it may be easily optimized using a look-up table, and some extra code could identify combinations of keys (e.g. for things like "shift-" or "ctrl-").

No comments:

Post a Comment