Keypad Library

I’m using the multi-key example from the keypad library. Currently the code will print the status of the key press (pressed, released, hold) and store up to 10 active key presses at any given time.

I would like to print a number (1-10) each time a new key is pressed (eg 7 keys held down = print number 7)

I’m trying to do that with ‘findInList’ which i believe should return an index(1-10) from ‘kpd.key’ array of keys currently held down.

Any help is much appreciated

#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
byte rowPins[ROWS] = {1, 2, 3, 4}; //connect to the row pinouts of the kpd
byte colPins[COLS] = {5, 6, 7}; //connect to the column pinouts of the kpd

Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

unsigned long loopCount;
unsigned long startTime;
String msg;


void setup() {
    Serial.begin(9600);
    loopCount = 0;
    startTime = millis();
    msg = "";
}


void loop() {
    loopCount++;
    if ( (millis()-startTime)>5000 ) {
        Serial.print("Average loops per second = ");
        Serial.println(loopCount/5);
        startTime = millis();
        loopCount = 0;
    }

    // Fills kpd.key[ ] array with up-to 10 active keys.
    // Returns true if there are ANY active keys.
    if (kpd.getKeys())
    {
        for (int i=0; i<LIST_MAX; i++)   // Scan the whole key list.
        {
            if ( kpd.key[i].stateChanged )   // Only find keys that have changed state.
            {
                switch (kpd.key[i].kstate) {  // Report active key state : IDLE, PRESSED, HOLD, or RELEASED
                    case PRESSED:
                    msg = " PRESSED.";
                break;
                    case HOLD:
                    msg = " HOLD.";
                break;
                    case RELEASED:
                    msg = " RELEASED.";
                break;
                    case IDLE:
                    msg = " IDLE.";
                }
                Serial.print("Key ");
                Serial.print(kpd.key[i].kchar);
                Serial.println(msg);

                int position_in_list;
                position_in_list = findInList(10);  
                Serial.print(position_in_list);
            }
        }
    }
}  // End loop

Pin 1 is not a good choice for a keypad row pin as it is used by the Serial interface. This may not be causing a problem but you would be wise to avoid using it for anything apart from Serial communications

The findInList function is as follows

// 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 Keypad::findInList (char keyChar) {
	for (byte i=0; i<LIST_MAX; i++) {
		if (key[i].kchar == keyChar) {
			return i;
		}
	}
	return -1;
}

It searches for a char rather than a integer

Looking for a key with character code 10 (Newline?) in the list will NOT do what you want. Try counting the keys in the PRESSED or HOLD state. Note: Count them even if their state has not just changed!

void loop()
{
  loopCount++;
  if ( (millis() - startTime) > 5000 )
  {
    Serial.print("Average loops per second = ");
    Serial.println(loopCount / 5);
    startTime = millis();
    loopCount = 0;
  }


  // Fills kpd.key[ ] array with up-to 10 active keys.
  // Returns true if there are ANY active keys.
  if (kpd.getKeys())
  {
    int keysPressed = 0;
    for (int i = 0; i < LIST_MAX; i++) // Scan the whole key list.
    {
      if (kpd.key[i].kstate == PRESSED || kpd.key[i].kstate == HOLD)
        keysPressed++;


      if ( kpd.key[i].stateChanged )   // Only find keys that have changed state.
      {
        switch (kpd.key[i].kstate)    // Report active key state : IDLE, PRESSED, HOLD, or RELEASED
        {
          case PRESSED:
            msg = " PRESSED.";
            break;
          case HOLD:
            msg = " HOLD.";
            break;
          case RELEASED:
            msg = " RELEASED.";
            break;
          case IDLE:
            msg = " IDLE.";
        }
        Serial.print("Key ");
        Serial.print(kpd.key[i].kchar);
        Serial.println(msg);
      }
    }
    Serial.print(keysPressed);
  }
}  // End loop

Thanks very much - this makes sense. Its kind of working but It is giving me pretty unstable values in serial monitor + not working every time.

Went back to my old code and it’s still reading an int (1-29) for each key so the matrix connections are ok.

Have I implemented this correctly?

#include <Keypad.h>
#include <stdlib.h>
#include <Wire.h>//Include the Wire library to talk I2C
#include <Adafruit_MCP4725.h>

//This is the I2C Address of the MCP4725, by default (A0 pulled to GND).
#define MCP4725_ADDR 0x60

Adafruit_MCP4725 dac;

#define LED 13    // Arduino Board LED is on Pin 13
//#define GATE A0 // Use Pin 12 to output GATE signal

int DACnum = 0;
int LEDval = LOW;
int GATEval = LOW;

const byte numRows = 6;
const byte numCols = 9;


//Code that shows the the keypad connections to the arduino terminals
byte colPins[numCols] = {13, 12, 11, 10, 9, 8, 4, 3, 2}; 
byte rowPins[numRows] = {A1, A2, A3, A4, A5, A6}; 


//keymap defines the key pressed according to the row and columns just as appears on the keypad
byte keymap[numRows][numCols] =
{
  {1, 7, 13, 19, 25},
  {2, 8, 14, 20, 26},
  {3, 9, 15, 21, 27},
  {4, 10, 16, 22, 28},
  {5, 11, 17, 23, 29},
  {6, 12, 18, 24},

};



// DAC = 4096/5 V/12 (for 1V per Octave) = 67.9 per step
unsigned int DACpitches[29] =
{

  0, 68,  137,  205,  273,  341,  410,  478,
  546,  614,  683,  751,  819,  887,  956, 1024,
  1092, 1161, 1229, 1297, 1365, 1434, 1502, 1570,
  1638, 1707, 1775, 1843, 1911,
};


//initializes an instance of the Keypad class
Keypad kpd = Keypad(makeKeymap(keymap), rowPins, colPins, numRows, numCols);

unsigned long loopCount;
unsigned long startTime;
String msg;

void setup()
{
  // initialize the serial communication:
  Serial.begin(19200);

//  pinMode(GATE, OUTPUT); // Set GATE pin to output

  Wire.begin();
  dac.begin(0x60);

  loopCount = 0;
  startTime = millis();
  msg = "";


}

void loop()
{

  unsigned int KeyPadNum = kpd.getKey();

  unsigned int DACnum = DACpitches[KeyPadNum];
 
  // Fills kpd.key[ ] array with up-to 10 active keys.
  // Returns true if there are ANY active keys.
  if (kpd.getKeys())
  {
    int keysPressed = 0;
    for (int i = 0; i < LIST_MAX; i++) // Scan the whole key list.
    {
      if (kpd.key[i].kstate == PRESSED || kpd.key[i].kstate == HOLD)
        keysPressed++;
    }
    Serial.println(keysPressed);
    
  }

}

I see the problem:

raymond_bagdust420:
Have I implemented this correctly?

No. You can't mix "kpd.getKey()" and "kpd.getKeys()":

void loop()
{
  unsigned int KeyPadNum = kpd.getKey();

 
  // Fills kpd.key[ ] array with up-to 10 active keys.
  // Returns true if there are ANY active keys.
  if (kpd.getKeys())
  {

The "kpd.getKey()" sets a flag that causes weird effects in the kpd.getKeys() list. Do not use both in the same sketch.