Keypad matrix last row and column of keys return the wrong data

Hi, I built a 9 by 9 matrix and I used these codes to run the circuit. These were contributed by community members.

Sketch:

#include "BigKeypad.h"

uint16_t gobanLegend[19][19] = {
  {'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AI', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS'},
  {'BA', 'BB', 'BC', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BK', 'BL', 'BM', 'BN', 'BO', 'BP', 'BQ', 'BR', 'BS'},
  {'CA', 'CB', 'CC', 'CD', 'CE', 'CF', 'CG', 'CH', 'CI', 'CJ', 'CK', 'CL', 'CM', 'CN', 'CO', 'CP', 'CQ', 'CR', 'CS'},
  {'DA', 'DB', 'DC', 'DD', 'DE', 'DF', 'DG', 'DH', 'DI', 'DJ', 'DK', 'DL', 'DM', 'DN', 'DO', 'DP', 'DQ', 'DR', 'DS'},
  {'EA', 'EB', 'EC', 'ED', 'EE', 'EF', 'EG', 'EH', 'EI', 'EJ', 'EK', 'EL', 'EM', 'EN', 'EO', 'EP', 'EQ', 'ER', 'ES'},
  {'FA', 'FB', 'FC', 'FD', 'FE', 'FF', 'FG', 'FH', 'FI', 'FJ', 'FK', 'FL', 'FM', 'FN', 'FO', 'FP', 'FQ', 'FR', 'FS'},
  {'GA', 'GB', 'GC', 'GD', 'GE', 'GF', 'GG', 'GH', 'GI', 'GJ', 'GK', 'GL', 'GM', 'GN', 'GO', 'GP', 'GQ', 'GR', 'GS'},
  {'HA', 'HB', 'HC', 'HD', 'HE', 'HF', 'HG', 'HH', 'HI', 'HJ', 'HK', 'HL', 'HM', 'HN', 'HO', 'HP', 'HQ', 'HR', 'HS'},
  {'IA', 'IB', 'IC', 'ID', 'IE', 'IF', 'IG', 'IH', 'II', 'IJ', 'IK', 'IL', 'IM', 'IN', 'IO', 'IP', 'IQ', 'IR', 'IS'},
  {'JA', 'JB', 'JC', 'JD', 'JE', 'JF', 'JG', 'JH', 'II', 'JJ', 'JK', 'JL', 'JM', 'JN', 'JO', 'JP', 'JQ', 'JR', 'JS'},
  {'KA', 'KB', 'KC', 'KD', 'KE', 'KF', 'KG', 'KH', 'KI', 'KJ', 'KK', 'KL', 'KM', 'KN', 'KO', 'KP', 'KQ', 'KR', 'KS'},
  {'LA', 'LB', 'LC', 'LD', 'LE', 'LF', 'LG', 'LH', 'LI', 'LJ', 'LK', 'LL', 'LM', 'LN', 'LO', 'LP', 'LQ', 'LR', 'LS'},
  {'MA', 'MB', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MI', 'MJ', 'MK', 'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS'},
  {'NA', 'NB', 'NC', 'ND', 'NE', 'NF', 'NG', 'NH', 'NI', 'NJ', 'NK', 'NL', 'NM', 'NN', 'NO', 'NP', 'NQ', 'NR', 'NS'},
  {'OA', 'OB', 'OC', 'OD', 'OE', 'OF', 'OG', 'OH', 'OI', 'OJ', 'OK', 'OL', 'OM', 'ON', 'OO', 'OP', 'OQ', 'OR', 'OS'},
  {'PA', 'PB', 'PC', 'PD', 'PE', 'PF', 'PG', 'PH', 'PI', 'PJ', 'PK', 'PL', 'PM', 'PN', 'PO', 'PP', 'PQ', 'PR', 'PS'},
  {'QA', 'QB', 'QC', 'QD', 'QE', 'QF', 'QG', 'QH', 'QI', 'QJ', 'QK', 'QL', 'QM', 'QN', 'QO', 'QP', 'QQ', 'QR', 'QS'},
  {'RA', 'RB', 'RC', 'RD', 'RE', 'RF', 'RG', 'RH', 'RI', 'RJ', 'RK', 'RL', 'RM', 'RN', 'RO', 'RP', 'RQ', 'RR', 'RS'},
  {'SA', 'SB', 'SC', 'SD', 'SE', 'SF', 'SG', 'SH', 'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SP', 'SQ', 'SR', 'SS'}
};

uint16_t gobanLegend2[19][19] = {
  {'AA', 'AB', 'AC', 'AD', 'AE', 'AF', 'AG', 'AH', 'AJ', 'AK', 'AL', 'AM', 'AN', 'AO', 'AP', 'AQ', 'AR', 'AS', 'AT'},
  {'BA', 'BB', 'BC', 'BD', 'BE', 'BF', 'BG', 'BH', 'BJ', 'BK', 'BL', 'BM', 'BN', 'BO', 'BP', 'BQ', 'BR', 'BS', 'BT'},
  {'CA', 'CB', 'CC', 'CD', 'CE', 'CF', 'CG', 'CH', 'CJ', 'CK', 'CL', 'CM', 'CN', 'CO', 'CP', 'CQ', 'CR', 'CS', 'CT'},
  {'DA', 'DB', 'DC', 'DD', 'DE', 'DF', 'DG', 'DH', 'DJ', 'DK', 'DL', 'DM', 'DN', 'DO', 'DP', 'DQ', 'DR', 'DS', 'DT'},
  {'EA', 'EB', 'EC', 'ED', 'EE', 'EF', 'EG', 'EH', 'EJ', 'EK', 'EL', 'EM', 'EN', 'EO', 'EP', 'EQ', 'ER', 'ES', 'ET'},
  {'FA', 'FB', 'FC', 'FD', 'FE', 'FF', 'FG', 'FH', 'FJ', 'FK', 'FL', 'FM', 'FN', 'FO', 'FP', 'FQ', 'FR', 'FS', 'FT'},
  {'GA', 'GB', 'GC', 'GD', 'GE', 'GF', 'GG', 'GH', 'GJ', 'GK', 'GL', 'GM', 'GN', 'GO', 'GP', 'GQ', 'GR', 'GS', 'GT'},
  {'HA', 'HB', 'HC', 'HD', 'HE', 'HF', 'HG', 'HH', 'HJ', 'HK', 'HL', 'HM', 'HN', 'HO', 'HP', 'HQ', 'HR', 'HS', 'HT'},
  {'JA', 'JB', 'JC', 'JD', 'JE', 'JF', 'JG', 'JH', 'JJ', 'JK', 'JL', 'JM', 'JN', 'JO', 'JP', 'JQ', 'JR', 'JS', 'JT'},
  {'KA', 'KB', 'KC', 'KD', 'KE', 'KF', 'KG', 'KH', 'KJ', 'KK', 'KL', 'KM', 'KN', 'KO', 'KP', 'KQ', 'KR', 'KS', 'KT'},
  {'LA', 'LB', 'LC', 'LD', 'LE', 'LF', 'LG', 'LH', 'LJ', 'LK', 'LL', 'LM', 'LN', 'LO', 'LP', 'LQ', 'LR', 'LS', 'LT'},
  {'MA', 'MB', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MJ', 'MK', 'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT'},
  {'NA', 'NB', 'NC', 'ND', 'NE', 'NF', 'NG', 'NH', 'NJ', 'NK', 'NL', 'NM', 'NN', 'NO', 'NP', 'NQ', 'NR', 'NS', 'NT'},
  {'OA', 'OB', 'OC', 'OD', 'OE', 'OF', 'OG', 'OH', 'OJ', 'OK', 'OL', 'OM', 'ON', 'OO', 'OP', 'OQ', 'OR', 'OS', 'OT'},
  {'PA', 'PB', 'PC', 'PD', 'PE', 'PF', 'PG', 'PH', 'PJ', 'PK', 'PL', 'PM', 'PN', 'PO', 'PP', 'PQ', 'PR', 'PS', 'PT'},
  {'QA', 'QB', 'QC', 'QD', 'QE', 'QF', 'QG', 'QH', 'QJ', 'QK', 'QL', 'QM', 'QN', 'QO', 'QP', 'QQ', 'QR', 'QS', 'QT'},
  {'RA', 'RB', 'RC', 'RD', 'RE', 'RF', 'RG', 'RH', 'RJ', 'RK', 'RL', 'RM', 'RN', 'RO', 'RP', 'RQ', 'RR', 'RS', 'RT'},
  {'SA', 'SB', 'SC', 'SD', 'SE', 'SF', 'SG', 'SH', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SP', 'SQ', 'SR', 'SS', 'ST'},
  {'TA', 'TB', 'TC', 'TD', 'TE', 'TF', 'TG', 'TH', 'TJ', 'TK', 'TL', 'TM', 'TN', 'TO', 'TP', 'TQ', 'TR', 'TS', 'TT'}
};

const byte ROWS = 5; //four rows
// THE ROW NEED TO BE ON THE SIDE OF DIODE. MAKE SURE THE COLUMN PINS ARE THE SIDE OF THE MATRIX WIRES WITH DIODES
const byte COLS = 9; //four columns



uint16_t testArray[ROWS][COLS];
uint16_t hexaKeys[ROWS][COLS];


// THE ROW NEED TO BE ON THE SIDE OF DIODE. MAKE SURE THE COLUMN PINS ARE THE SIDE OF THE MATRIX WIRES WITH DIODES

byte rowPins[ROWS] = {2,3,4,5,6};
byte colPins[COLS] = {14,15,16,17,18,19,20,21,22};
//initialize an instance of class NewKeypad
BigKeypad customKeypad = BigKeypad( makeIntKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

void setup() {
  Serial.begin(9600);

  for (int i = 0; i < ROWS; i++) {
    for (int j = 0; j < COLS; j++) {
      hexaKeys[i][j] = gobanLegend2[i][j];
      //      Serial.print(hexaKeys[i][j]);
    }
  }
}

void loop() {

  if (customKeypad.getKeys()) {
    for (uint16_t i = 0; i < LIST_MAX; i++) {
      if (customKeypad.key[i].stateChanged) {
        if (customKeypad.key[i].kstate == PRESSED) {

          //          Serial.write(char(customKeypad.key[i].kchar >> 8));
          //          Serial.write(char(customKeypad.key[i].kchar));
          Serial.print(char(customKeypad.key[i].kchar >> 8));
          Serial.print(char(customKeypad.key[i].kchar));

        }
      }
    }
  }
}

Libraries:

BigKeypad.h

/*
  ||
  || @file Keypad.h
  || @version 3.1
  || @author Mark Stanley, Alexander Brevig
  || @contact mstanley@technologist.com, alexanderbrevig@gmail.com
  ||
  || @description
  || | This library provides a simple interface for using matrix
  || | keypads. It supports multiple keypresses while maintaining
  || | backwards compatibility with the old single key library.
  || | It also supports user selectable pins and definable keymaps.
  || #
  ||
  || @license
  || | This library is free software; you can redistribute it and/or
  || | modify it under the terms of the GNU Lesser General Public
  || | License as published by the Free Software Foundation; version
  || | 2.1 of the License.
  || |
  || | This library is distributed in the hope that it will be useful,
  || | but WITHOUT ANY WARRANTY; without even the implied warranty of
  || | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  || | Lesser General Public License for more details.
  || |
  || | You should have received a copy of the GNU Lesser General Public
  || | License along with this library; if not, write to the Free Software
  || | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  || #
  ||
*/

#ifndef KEYPAD_H
#define KEYPAD_H

#include "BigKey.h"

// bperrybap - Thanks for a well reasoned argument and the following macro(s).
// See http://arduino.cc/forum/index.php/topic,142041.msg1069480.html#msg1069480
#ifndef INPUT_PULLUP
#warning "Using  pinMode() INPUT_PULLUP AVR emulation"
#define INPUT_PULLUP 0x2
#define pinMode(_pin, _mode) _mypinMode(_pin, _mode)
#define _mypinMode(_pin, _mode)  \
  do {							 \
    if(_mode == INPUT_PULLUP)	 \
      pinMode(_pin, INPUT);	 \
    digitalWrite(_pin, 1);	 \
    if(_mode != INPUT_PULLUP)	 \
      pinMode(_pin, _mode);	 \
  }while(0)
#endif


#define OPEN LOW
#define CLOSED HIGH

typedef char KeypadEvent;
typedef unsigned int uint;
typedef unsigned long ulong;

// Made changes according to this post http://arduino.cc/forum/index.php?topic=58337.0
// by Nick Gammon. Thanks for the input Nick. It actually saved 78 bytes for me. :)
typedef struct
{
  byte rows;
  byte columns;
} KeypadSize;

#define LIST_MAX 100		// Max number of keys on the active list.
#define MAPSIZE 19		// MAPSIZE is the number of rows (times 24 columns)
#define makeIntKeymap(x) ((uint16_t*)x)

class BigKeypad : public BigKey
{
  public:

    BigKeypad(const uint16_t *userKeymap, const byte *row, const byte *col, const byte numRows, const byte numCols);

    virtual void pin_mode(byte pinNum, byte mode)
    {
      pinMode(pinNum, mode);
    }
    virtual void pin_write(byte pinNum, boolean level)
    {
      digitalWrite(pinNum, level);
    }
    virtual int  pin_read(byte pinNum)
    {
      return digitalRead(pinNum);
    }

    uint32_t bitMap[MAPSIZE];	// 19 row x 32 column array of bits.
    BigKey key[LIST_MAX];
    unsigned long holdTimer;

    uint16_t getKey();
    bool getKeys();
    KeyState getState();
    void begin(const uint16_t *userKeymap);
    bool isPressed(uint16_t keyChar);
    void setDebounceTime(uint);
    void setHoldTime(uint);
    void addEventListener(void (*listener)(char));
    int findInList(uint16_t keyChar);
    int findInList(int keyCode);
    uint16_t waitForKey();
    bool keyStateChanged();
    byte numKeys();

  private:
    unsigned long startTime;
    const uint16_t *keymap;
    const byte *rowPins;
    const byte *columnPins;
    KeypadSize sizeKpd;
    uint debounceTime;
    uint holdTime;
    bool single_key;

    void scanKeys();
    bool updateList();
    void nextKeyState(byte n, boolean button);
    void transitionTo(byte n, KeyState nextState);
    void (*keypadEventListener)(char);
};

#endif

/*
  || @changelog
  || | 3.1 2013-01-15 - Mark Stanley     : Fixed missing RELEASED & IDLE status when using a single key.
  || | 3.0 2012-07-12 - Mark Stanley     : Made library multi-keypress by default. (Backwards compatible)
  || | 3.0 2012-07-12 - Mark Stanley     : Modified pin functions to support Keypad_I2C
  || | 3.0 2012-07-12 - Stanley & Young  : Removed static variables. Fix for multiple keypad objects.
  || | 3.0 2012-07-12 - Mark Stanley     : Fixed bug that caused shorted pins when pressing multiple keys.
  || | 2.0 2011-12-29 - Mark Stanley     : Added waitForKey().
  || | 2.0 2011-12-23 - Mark Stanley     : Added the public function keyStateChanged().
  || | 2.0 2011-12-23 - Mark Stanley     : Added the private function scanKeys().
  || | 2.0 2011-12-23 - Mark Stanley     : Moved the Finite State Machine into the function getKeyState().
  || | 2.0 2011-12-23 - Mark Stanley     : Removed the member variable lastUdate. Not needed after rewrite.
  || | 1.8 2011-11-21 - Mark Stanley     : Added test to determine which header file to compile,
  || |                                          WProgram.h or Arduino.h.
  || | 1.8 2009-07-08 - Alexander Brevig : No longer uses arrays
  || | 1.7 2009-06-18 - Alexander Brevig : This library is a Finite State Machine every time a state changes
  || |                                          the keypadEventListener will trigger, if set
  || | 1.7 2009-06-18 - Alexander Brevig : Added setDebounceTime setHoldTime specifies the amount of
  || |                                          microseconds before a HOLD state triggers
  || | 1.7 2009-06-18 - Alexander Brevig : Added transitionTo
  || | 1.6 2009-06-15 - Alexander Brevig : Added getState() and state variable
  || | 1.5 2009-05-19 - Alexander Brevig : Added setHoldTime()
  || | 1.4 2009-05-15 - Alexander Brevig : Added addEventListener
  || | 1.3 2009-05-12 - Alexander Brevig : Added lastUdate, in order to do simple debouncing
  || | 1.2 2009-05-09 - Alexander Brevig : Changed getKey()
  || | 1.1 2009-04-28 - Alexander Brevig : Modified API, and made variables private
  || | 1.0 2007-XX-XX - Mark Stanley : Initial Release
  || #
*/

BigKeypad.cpp:

/*
  ||
  || @file Keypad.cpp
  || @version 3.1
  || @author Mark Stanley, Alexander Brevig
  || @contact mstanley@technologist.com, alexanderbrevig@gmail.com
  ||
  || @description
  || | This library provides a simple interface for using matrix
  || | keypads. It supports multiple keypresses while maintaining
  || | backwards compatibility with the old single key library.
  || | It also supports user selectable pins and definable keymaps.
  || #
  ||
  || @license
  || | This library is free software; you can redistribute it and/or
  || | modify it under the terms of the GNU Lesser General Public
  || | License as published by the Free Software Foundation; version
  || | 2.1 of the License.
  || |
  || | This library is distributed in the hope that it will be useful,
  || | but WITHOUT ANY WARRANTY; without even the implied warranty of
  || | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  || | Lesser General Public License for more details.
  || |
  || | You should have received a copy of the GNU Lesser General Public
  || | License along with this library; if not, write to the Free Software
  || | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  || #
  ||
*/
#include "BigKeypad.h"

// <<constructor>> Allows custom keymap, pin configuration, and keypad sizes.
BigKeypad::BigKeypad(const uint16_t *userKeymap, const byte *row, const byte *col, const byte numRows, const byte numCols)
{
  rowPins = row;
  columnPins = col;
  sizeKpd.rows = numRows;
  sizeKpd.columns = numCols;

  begin(userKeymap);

  setDebounceTime(10);
  setHoldTime(500);
  keypadEventListener = 0;

  startTime = 0;
  single_key = false;
}

// Let the user define a keymap - assume the same row/column count as defined in constructor
void BigKeypad::begin(const uint16_t *userKeymap)
{
  keymap = userKeymap;
}

// Returns a single key only. Retained for backwards compatibility.
uint16_t BigKeypad::getKey()
{
  single_key = true;

  if (getKeys() && key[0].stateChanged && (key[0].kstate == PRESSED))
    return key[0].kchar;

  single_key = false;

  return NO_KEY;
}

// Populate the key list.
bool BigKeypad::getKeys()
{
  bool keyActivity = false;

  // Limit how often the keypad is scanned. This makes the loop() run 10 times as fast.
  if ( (millis() - startTime) > debounceTime )
  {
    scanKeys();
    keyActivity = updateList();
    startTime = millis();
  }

  return keyActivity;
}

// Private : Hardware scan
void BigKeypad::scanKeys()
{
  // Re-intialize the row pins. Allows sharing these pins with other hardware.
  for (byte r = 0; r < sizeKpd.rows; r++)
  {
    pin_mode(rowPins[r], INPUT_PULLUP);
  }

  // bitMap stores ALL the keys that are being pressed.
  for (byte c = 0; c < sizeKpd.columns; c++)
  {
    pin_mode(columnPins[c], OUTPUT);
    pin_write(columnPins[c], LOW);	// Begin column pulse output.
    for (byte r = 0; r < sizeKpd.rows; r++)
    {
      bitWrite(bitMap[r], c, !pin_read(rowPins[r]));  // keypress is active low so invert to high.
    }
    // Set pin to high impedance input. Effectively ends column pulse.
    pin_write(columnPins[c], HIGH);
    pin_mode(columnPins[c], INPUT);
  }
}

// Manage the list without rearranging the keys. Returns true if any keys on the list changed state.
bool BigKeypad::updateList()
{

  bool anyActivity = false;

  // Delete any IDLE keys
  for (byte i = 0; i < LIST_MAX; i++)
  {
    if (key[i].kstate == IDLE)
    {
      key[i].kchar = NO_KEY;
      key[i].kcode = -1;
      key[i].stateChanged = false;
    }
  }

  // Add new keys to empty slots in the key list.
  for (byte r = 0; r < sizeKpd.rows; r++)
  {
    for (byte c = 0; c < sizeKpd.columns; c++)
    {
      boolean button = bitRead(bitMap[r], c);
      uint16_t keyChar = keymap[r * sizeKpd.columns + c];
      int keyCode = r * sizeKpd.columns + c;
      int idx = findInList (keyCode);
      // Key is already on the list so set its next state.
      if (idx > -1)
      {
        nextKeyState(idx, button);
      }
      // Key is NOT on the list so add it.
      if ((idx == -1) && button)
      {
        for (byte i = 0; i < LIST_MAX; i++)
        {
          if (key[i].kchar == NO_KEY)  		// Find an empty slot or don't add key to list.
          {
            key[i].kchar = keyChar;
            key[i].kcode = keyCode;
            key[i].kstate = IDLE;		// Keys NOT on the list have an initial state of IDLE.
            nextKeyState (i, button);
            break;	// Don't fill all the empty slots with the same key.
          }
        }
      }
    }
  }

  // Report if the user changed the state of any key.
  for (byte i = 0; i < LIST_MAX; i++)
  {
    if (key[i].stateChanged) anyActivity = true;
  }

  return anyActivity;
}

// Private
// This function is a state machine but is also used for debouncing the keys.
void BigKeypad::nextKeyState(byte idx, boolean button)
{
  key[idx].stateChanged = false;

  switch (key[idx].kstate)
  {
    case IDLE:
      if (button == CLOSED)
      {
        transitionTo (idx, PRESSED);
        holdTimer = millis();
      }		// Get ready for next HOLD state.
      break;
    case PRESSED:
      if ((millis() - holdTimer) > holdTime)	// Waiting for a key HOLD...
        transitionTo (idx, HOLD);
      else if (button == OPEN)				// or for a key to be RELEASED.
        transitionTo (idx, RELEASED);
      break;
    case HOLD:
      if (button == OPEN)
        transitionTo (idx, RELEASED);
      break;
    case RELEASED:
      transitionTo (idx, IDLE);
      break;
  }
}

// New in 2.1
bool BigKeypad::isPressed(uint16_t keyChar)
{
  for (byte i = 0; i < LIST_MAX; i++)
  {
    if ( key[i].kchar == keyChar )
    {
      if ( (key[i].kstate == PRESSED) && key[i].stateChanged )
        return true;
    }
  }
  return false;	// Not pressed.
}

// Search by character for a key in the list of active keys.
// Returns -1 if not found or the index into the list of active keys.
int BigKeypad::findInList (uint16_t keyChar)
{
  for (byte i = 0; i < LIST_MAX; i++)
  {
    if (key[i].kchar == keyChar)
    {
      return i;
    }
  }
  return -1;
}

// Search by code for a key in the list of active keys.
// Returns -1 if not found or the index into the list of active keys.
int BigKeypad::findInList (int keyCode)
{
  for (byte i = 0; i < LIST_MAX; i++)
  {
    if (key[i].kcode == keyCode)
    {
      return i;
    }
  }
  return -1;
}

// New in 2.0
uint16_t BigKeypad::waitForKey()
{
  uint16_t waitKey = NO_KEY;
  while ( (waitKey = getKey()) == NO_KEY );	// Block everything while waiting for a keypress.
  return waitKey;
}

// Backwards compatibility function.
KeyState BigKeypad::getState()
{
  return key[0].kstate;
}

// The end user can test for any changes in state before deciding
// if any variables, etc. needs to be updated in their code.
bool BigKeypad::keyStateChanged()
{
  return key[0].stateChanged;
}

// The number of keys on the key list, key[LIST_MAX], equals the number
// of bytes in the key list divided by the number of bytes in a Key object.
byte BigKeypad::numKeys()
{
  return sizeof(key) / sizeof(BigKey);
}

// Minimum debounceTime is 1 mS. Any lower *will* slow down the loop().
void BigKeypad::setDebounceTime(uint debounce)
{
  debounce < 1 ? debounceTime = 1 : debounceTime = debounce;
}

void BigKeypad::setHoldTime(uint hold)
{
  holdTime = hold;
}

void BigKeypad::addEventListener(void (*listener)(char))
{
  keypadEventListener = listener;
}

void BigKeypad::transitionTo(byte idx, KeyState nextState)
{
  key[idx].kstate = nextState;
  key[idx].stateChanged = true;

  // Sketch used the getKey() function.
  // Calls keypadEventListener only when the first key in slot 0 changes state.
  if (single_key)
  {
    if ( (keypadEventListener != NULL) && (idx == 0) )
    {
      keypadEventListener(key[0].kchar);
    }
  }
  // Sketch used the getKeys() function.
  // Calls keypadEventListener on any key that changes state.
  else
  {
    if (keypadEventListener != NULL)
    {
      keypadEventListener(key[idx].kchar);
    }
  }
}

/*
  || @changelog
  || | 3.1 2013-01-15 - Mark Stanley     : Fixed missing RELEASED & IDLE status when using a single key.
  || | 3.0 2012-07-12 - Mark Stanley     : Made library multi-keypress by default. (Backwards compatible)
  || | 3.0 2012-07-12 - Mark Stanley     : Modified pin functions to support Keypad_I2C
  || | 3.0 2012-07-12 - Stanley & Young  : Removed static variables. Fix for multiple keypad objects.
  || | 3.0 2012-07-12 - Mark Stanley     : Fixed bug that caused shorted pins when pressing multiple keys.
  || | 2.0 2011-12-29 - Mark Stanley     : Added waitForKey().
  || | 2.0 2011-12-23 - Mark Stanley     : Added the public function keyStateChanged().
  || | 2.0 2011-12-23 - Mark Stanley     : Added the private function scanKeys().
  || | 2.0 2011-12-23 - Mark Stanley     : Moved the Finite State Machine into the function getKeyState().
  || | 2.0 2011-12-23 - Mark Stanley     : Removed the member variable lastUdate. Not needed after rewrite.
  || | 1.8 2011-11-21 - Mark Stanley     : Added decision logic to compile WProgram.h or Arduino.h
  || | 1.8 2009-07-08 - Alexander Brevig : No longer uses arrays
  || | 1.7 2009-06-18 - Alexander Brevig : Every time a state changes the keypadEventListener will trigger, if set.
  || | 1.7 2009-06-18 - Alexander Brevig : Added setDebounceTime. setHoldTime specifies the amount of
  || |                                          microseconds before a HOLD state triggers
  || | 1.7 2009-06-18 - Alexander Brevig : Added transitionTo
  || | 1.6 2009-06-15 - Alexander Brevig : Added getState() and state variable
  || | 1.5 2009-05-19 - Alexander Brevig : Added setHoldTime()
  || | 1.4 2009-05-15 - Alexander Brevig : Added addEventListener
  || | 1.3 2009-05-12 - Alexander Brevig : Added lastUdate, in order to do simple debouncing
  || | 1.2 2009-05-09 - Alexander Brevig : Changed getKey()
  || | 1.1 2009-04-28 - Alexander Brevig : Modified API, and made variables private
  || | 1.0 2007-XX-XX - Mark Stanley : Initial Release
  || #
*/

BigKey.h:

/*
  ||
  || @file Key.h
  || @version 1.0
  || @author Mark Stanley
  || @contact mstanley@technologist.com
  ||
  || @description
  || | Key class provides an abstract definition of a key or button
  || | and was initially designed to be used in conjunction with a
  || | state-machine.
  || #
  ||
  || @license
  || | This library is free software; you can redistribute it and/or
  || | modify it under the terms of the GNU Lesser General Public
  || | License as published by the Free Software Foundation; version
  || | 2.1 of the License.
  || |
  || | This library is distributed in the hope that it will be useful,
  || | but WITHOUT ANY WARRANTY; without even the implied warranty of
  || | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  || | Lesser General Public License for more details.
  || |
  || | You should have received a copy of the GNU Lesser General Public
  || | License along with this library; if not, write to the Free Software
  || | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  || #
  ||
*/

#ifndef Keypadlib_KEY_H_
#define Keypadlib_KEY_H_

#include <Arduino.h>

#define OPEN LOW
#define CLOSED HIGH

typedef unsigned int uint;
typedef enum { IDLE, PRESSED, HOLD, RELEASED } KeyState;

const char NO_KEY = '\0';

class BigKey
{
  public:
    // members
    uint16_t kchar;
    int kcode;
    KeyState kstate;
    boolean stateChanged;

    // methods
    BigKey();
    BigKey(uint16_t userKeyInt);
    void key_update(uint16_t userKeyInt, KeyState userState, boolean userStatus);

  private:

};

#endif

/*
  || @changelog
  || | 1.0 2012-06-04 - Mark Stanley : Initial Release
  || #
*/

BigKey.cpp:

/*
  || @file Key.cpp
  || @version 1.0
  || @author Mark Stanley
  || @contact mstanley@technologist.com
  ||
  || @description
  || | Key class provides an abstract definition of a key or button
  || | and was initially designed to be used in conjunction with a
  || | state-machine.
  || #
  ||
  || @license
  || | This library is free software; you can redistribute it and/or
  || | modify it under the terms of the GNU Lesser General Public
  || | License as published by the Free Software Foundation; version
  || | 2.1 of the License.
  || |
  || | This library is distributed in the hope that it will be useful,
  || | but WITHOUT ANY WARRANTY; without even the implied warranty of
  || | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  || | Lesser General Public License for more details.
  || |
  || | You should have received a copy of the GNU Lesser General Public
  || | License along with this library; if not, write to the Free Software
  || | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  || #
  ||
*/
#include "BigKey.h"


// default constructor
BigKey::BigKey()
{
  kchar = NO_KEY;
  kstate = IDLE;
  stateChanged = false;
}

// constructor
BigKey::BigKey(uint16_t userKeyChar)
{
  kchar = userKeyChar;
  kcode = -1;
  kstate = IDLE;
  stateChanged = false;
}


void BigKey::key_update (uint16_t userKeyChar, KeyState userState, boolean userStatus)
{
  kchar = userKeyChar;
  kstate = userState;
  stateChanged = userStatus;
}



/*
  || @changelog
  || | 1.0 2012-06-04 - Mark Stanley : Initial Release
  || #
*/

When I connect my nine by nine matrix to arduino, the 9th row and column always give extra data, as if the edge case is not handled. Can someone help me with this?

you should not have single quotes with double chars in it... what is it you really want as a uint16_t ??


 {'AA', . . . . .

What is ’AA'

What model Arduino are you using?

You are showing the code for a 5x9 keypad.

The 'hexaKeys' array doesn't appear to be initialized.

That actually is valid code, the compiler generates a 16-bit number from the hex values of the ASCII code.

agreed - it is valid code for the time being because of the old compiler we use but should not be relied upon as Multicharacter constants are moving out of the spec in C++23

This is to allow sending 361 different values through the serial port so two-character value is needed.

I didn't know the array has to be initialized. Let me try that out.

sure, but the future ready solution would be something like

const uint16_t gobanLegend[19][19] = {
  {0x4141,0x4142,0x4143,0x4144,0x4145,0x4146,0x4147,0x4148,0x4149,0x414A,0x414B,0x414C,0x414D,0x414E,0x414F,0x4150,0x4151,0x4152,0x4153},
  {0x4241,0x4242,0x4243,0x4244,0x4245,0x4246,0x4247,0x4248,0x4249,0x424A,0x424B,0x424C,0x424D,0x424E,0x424F,0x4250,0x4251,0x4252,0x4253},
  {0x4341,0x4342,0x4343,0x4344,0x4345,0x4346,0x4347,0x4348,0x4349,0x434A,0x434B,0x434C,0x434D,0x434E,0x434F,0x4350,0x4351,0x4352,0x4353},
  {0x4441,0x4442,0x4443,0x4444,0x4445,0x4446,0x4447,0x4448,0x4449,0x444A,0x444B,0x444C,0x444D,0x444E,0x444F,0x4450,0x4451,0x4452,0x4453},
  {0x4541,0x4542,0x4543,0x4544,0x4545,0x4546,0x4547,0x4548,0x4549,0x454A,0x454B,0x454C,0x454D,0x454E,0x454F,0x4550,0x4551,0x4552,0x4553},
  {0x4641,0x4642,0x4643,0x4644,0x4645,0x4646,0x4647,0x4648,0x4649,0x464A,0x464B,0x464C,0x464D,0x464E,0x464F,0x4650,0x4651,0x4652,0x4653},
  {0x4741,0x4742,0x4743,0x4744,0x4745,0x4746,0x4747,0x4748,0x4749,0x474A,0x474B,0x474C,0x474D,0x474E,0x474F,0x4750,0x4751,0x4752,0x4753},
  {0x4841,0x4842,0x4843,0x4844,0x4845,0x4846,0x4847,0x4848,0x4849,0x484A,0x484B,0x484C,0x484D,0x484E,0x484F,0x4850,0x4851,0x4852,0x4853},
  {0x4941,0x4942,0x4943,0x4944,0x4945,0x4946,0x4947,0x4948,0x4949,0x494A,0x494B,0x494C,0x494D,0x494E,0x494F,0x4950,0x4951,0x4952,0x4953},
  {0x4A41,0x4A42,0x4A43,0x4A44,0x4A45,0x4A46,0x4A47,0x4A48,0x4949,0x4A4A,0x4A4B,0x4A4C,0x4A4D,0x4A4E,0x4A4F,0x4A50,0x4A51,0x4A52,0x4A53},
  {0x4B41,0x4B42,0x4B43,0x4B44,0x4B45,0x4B46,0x4B47,0x4B48,0x4B49,0x4B4A,0x4B4B,0x4B4C,0x4B4D,0x4B4E,0x4B4F,0x4B50,0x4B51,0x4B52,0x4B53},
  {0x4C41,0x4C42,0x4C43,0x4C44,0x4C45,0x4C46,0x4C47,0x4C48,0x4C49,0x4C4A,0x4C4B,0x4C4C,0x4C4D,0x4C4E,0x4C4F,0x4C50,0x4C51,0x4C52,0x4C53},
  {0x4D41,0x4D42,0x4D43,0x4D44,0x4D45,0x4D46,0x4D47,0x4D48,0x4D49,0x4D4A,0x4D4B,0x4D4C,0x4D4D,0x4D4E,0x4D4F,0x4D50,0x4D51,0x4D52,0x4D53},
  {0x4E41,0x4E42,0x4E43,0x4E44,0x4E45,0x4E46,0x4E47,0x4E48,0x4E49,0x4E4A,0x4E4B,0x4E4C,0x4E4D,0x4E4E,0x4E4F,0x4E50,0x4E51,0x4E52,0x4E53},
  {0x4F41,0x4F42,0x4F43,0x4F44,0x4F45,0x4F46,0x4F47,0x4F48,0x4F49,0x4F4A,0x4F4B,0x4F4C,0x4F4D,0x4F4E,0x4F4F,0x4F50,0x4F51,0x4F52,0x4F53},
  {0x5041,0x5042,0x5043,0x5044,0x5045,0x5046,0x5047,0x5048,0x5049,0x504A,0x504B,0x504C,0x504D,0x504E,0x504F,0x5050,0x5051,0x5052,0x5053},
  {0x5141,0x5142,0x5143,0x5144,0x5145,0x5146,0x5147,0x5148,0x5149,0x514A,0x514B,0x514C,0x514D,0x514E,0x514F,0x5150,0x5151,0x5152,0x5153},
  {0x5241,0x5242,0x5243,0x5244,0x5245,0x5246,0x5247,0x5248,0x5249,0x524A,0x524B,0x524C,0x524D,0x524E,0x524F,0x5250,0x5251,0x5252,0x5253},
  {0x5341,0x5342,0x5343,0x5344,0x5345,0x5346,0x5347,0x5348,0x5349,0x534A,0x534B,0x534C,0x534D,0x534E,0x534F,0x5350,0x5351,0x5352,0x5353},
};
1 Like

Is row "IA" (letter #9+A) intentionally not present in the second array?

On a side note, a lot of the keypad matrix circuit diagram have the diode pointing towards the row wire and away from the switch, like this:

However, when I constructed my matrix, I swapped the diode direction by accident. So now it's pointing towards switch. Is that going to cause issues?

It is but it can really be anything :sweat_smile:

Cool let me try this.

I'm using the mega model now. I was using uno before.

My bad I didn't paste the code for 9 by 9 matrix, but the same thing happen for the 9 by 5 matrix. However, when I only use 2 by 2 matrix I didn't have the same issue.

Do you mind explaining why the array has to be initialized?

Why is this more future proof?

That array is the list of key values, like "gobanLegend[]". If you don't initialize it, all of the keys will have the value zero (which is not a valid key value).

I use a nested for loop in setup() to assign the 2d array's content. Is that not enough?

void setup() {
  Serial.begin(9600);

  for (int i = 0; i < ROWS; i++) {
    for (int j = 0; j < COLS; j++) {
      hexaKeys[i][j] = gobanLegend2[i][j];
      //      Serial.print(hexaKeys[i][j]);
    }
  }
}

since your keypad is only 9x5, why don't you use the standard keypad library?

Yes, that will work. I didn't see that and setup() doesn't happen until after the BigKeypad object is created but since BigKeypad only keeps a pointer to the array it is ok to fill the array after the object is created.

Awesome that's great to hear. Thanks for confirming it. It is more convenient if I can define the hexaKeys dynamically.