keypad multiple key press

Hi Guys,
I have built a tactile button array and Im using Keypad.h so far it works great.
However I need to be able to press to keys at once and notice that is the case. So what im thinking is I need to scan all the combinations of the array (button matrix) and store the result in an array that is the size of the number of buttons I have, is that how you guys would do it, has anyone got a link to an example of this?
Thanks

That is a good approach, you may even stop if you have found more than one key pressed to minimize search time.

You should look at hoe the library code scans the keypad and redo that with a counter.

There was a bug in the keypad library where it might cause a "short" if multiple keys were pressed. In your case this would be particularly bad, as you would be actively trying to do it.

You will want to check in your copy that where it initializes the pin states it does something like this:

void Keypad::initializePins(){
	for (byte r=0; r<size.rows; r++){
        for (byte c=0; c<size.columns; c++){
			pinMode(columnPins[c],OUTPUT);
			digitalWrite(columnPins[c],HIGH);
        }
		//configure row pin modes and states
		pinMode(rowPins[r],INPUT);
		digitalWrite(rowPins[r],HIGH);
    }
}

Note how the rows are set to inputs? Then when each row is scanned it is temporarily turned into an output.

Hi Nick, I'm rewriting the keypad library to support multiple keys by default. I know you're not the op but I wanted to point it out for my next question.

I know from testing with an oscilloscope that the columns and rows will definitely short out if more than one key is pressed at a time. And if you think two keys are bad you should see how hot the Atmel chip gets when you press three or more. It just doesn't work. However, you called it a bug which makes me think you might have a software solution or fix. My only solution was to use diodes. They work but if you have another idea I would definitely llike to eliminate the extra components and avoid having to rewrite the keypad tutorial to include diodes.

-Mark

See this page for a discussion:

Yes! Thankyou very much. I can't believe I missed that solution. When I was doing my troubleshooting it was definitely showing the shorts between columns. Or voltage drops if I tried using series resistors. There it was staring me in the face and all I could think to do was insert some diodes.

Hi guys,
sorry I havent replied, I only just got my internet back! Yeah Im using Diodes to stop what I believe is called ghosting on my button matrix, but I once saw a piece of code that scanned all the buttons and stored their current states to an array so that the user could use them, Im not entirely sure how the keypad.h file nick wrote (I think it was you nick) works, and whether the fix you suggest just stops it completely failing, or actually allows for multiple button presses, but I cant see a way you would do it without storing all the buttons current state to an array for the user to use????

EDIT:
I just realised, posting my use of this will probably help you understand....
I am trying to make a small (1 octave) keyboard, and want the user to be able to hold down chords, so what would you guys do? create an array the size of the number of keys of type boolean, then scan all the inputs (of the button array) for high/low (true/false) and store the state to the array then cycle through the array checking for true or false to make the sounds?
I kind of see how it might work, but I dont think Keypad.h is necessarliry the answer here????? Im struggling with it but I think its a confidence thing..

I think you need diodes to prevent ghosting. The software fix will stop shorts but not ghosting.

a.mlw.walker:
Yeah Im using Diodes to stop what I believe is called ghosting on my button matrix

For your keyboard you will have to continue to use diodes. It's the only way to prevent ghosting & jamming.

I once saw a piece of code that scanned all the buttons and stored their current states to an array so that the user could use them

Well now, it seems you have stumbled upon my secret method. :wink: I've already provided three people with a multi-key solution but I asked if they could keep it under wraps until I had time to clean up the code (a.k.a. make big changes). I think it was two pc and one midi keyboard.

I cant see a way you would do it without storing all the buttons current state to an array for the user to use????

Absolutely. I created a list that can store up to 10 active KeyCodes. If I recall my research midi requires 10 simultaneous keypresses.

[Snip]... so what would you guys do? create an array the size of the number of keys of type boolean, then scan all the inputs (of the button array) for high/low (true/false) and store the state to the array then cycle through the array checking for true or false to make the sounds?

Close, but I create the array using unsigned int's.

#define MAPSIZE 10

uint bitMap[MAPSIZE];	// 10 row x 16 column array of bits.

which allows up to 160 user defined keys. You can define smaller keypads/keyboards as needed. I then scan only the user defined keys and store open/closed key status as single bits in the bitMap. This allows some efficiencies in scanning the bitMap. In other words, because each row is an int I can see if any keys were pressed on that row by checking thus:

if (bitMap[n] {...} where n is any value between 0 and MAPSIZE.

The previous code I passed around was pretty basic and the three guys had to write some things that I really want to include in the library. I've got most of that done but the last thing I want to add before beginning testing is an easy way to convert the list of KeyCodes into the characters defined by the user. Then I get to start debugging all my bugging (programming.)

Hi Guys, sorry Im so bad at posting, my new job started recently and they are keeping me there quite late at the moment.
So this is what Ive written, I know the array (mstanley) isnt unsigned integers, I just wanted to do it from first principles and see how far I got. I think Im almost there?

const byte ROWS = 2; //four rows
const byte COLS = 4; //three columns
int buttonstate [ROWS][COLS] = {
  {
    0,0, 0, 0  }
  ,
  {
    0,0, 0, 0  }
};
byte colPins[COLS] = {
  22, 23, 24, 25}; //connect to the row pinouts of the keypad
byte rowPins[ROWS] = {
  5, 6}; //connect to the column pinouts of the keypad
void setup()
{
  pinMode(rowPins[0], OUTPUT);
  pinMode(rowPins[1], OUTPUT);//can be increased
  for (int i = 0; i < COLS; i++){
    pinMode(colPins[i], INPUT);
  }
  Serial.begin(19200);
}

void loop(){
  for (int i = 0;i<ROWS;i++){
    digitalWrite(rowPins[i], HIGH);
    for (int j = 0; j<COLS;j++){
      buttonstate[j][i] = digitalRead(colPins[j]);
      Serial.print(buttonstate[j][i]);
      Serial.print(",");
    }
    Serial.println("");
    digitalWrite(rowPins[i], LOW);
  }
  Serial.println("");
}

so that compiles and everything, but I get odd output:

1,1,1,1,
0,0,0,0,

0,0,0,0,
0,0,1,1,

1,1,1,1,
0,0,0,0,

0,0,1,1,
1,0,1,1,

0,0,0,0,
0,0,0,0,

0,0,1,1,
1,0,1,1,

0,0,0,0,
0,0,1,1,

1,1,1,1,
0,0,0,0,

0,0,0,0,
0,0,1,1,

1,1,1,1,
0,0,0,0,

0,0,1,1,
1,0,1,1,

0,0,0,0,
0,0,0,0,

0,0,1,1,
1,0,1,1,

0,0,0,0,
0,0,1,1,

1,1,1,1,
0,0,0,0,

Thats when Im not pressing any buttons at all. Just letting the loop run. When I do press buttons nothing seems to happen. Can anyone spot if Im doing something stupid?
Thanks
As a side question, once I have got this working, can I just map the state of each positon in the array to a midi signal and output that?

a.mlw.walker:
Can anyone spot if Im doing something stupid?

Well, to be blunt you have missed half the process of scanning a matrix keypad. You have the beginnings but remember that you need to scan all rows for EACH column. Your code doesn't send any pulses out the column pins so there is never anything for your row pins to read. Also, you need to enable the internal pullup resistors to prevent spurious readings like you are getting.

The following code is intended for you to study. I didn't even try to compile it.

// Prepare the row pins for reading.
    for (byte r=0; r<ROWS; r++) {
        pinMode(rowPins[r],INPUT);
        digitalWrite(rowPins[r],HIGH);	// Enable the internal 20K pullup resistors.
    }

    for (int c=0; c<COLS; c++) {
        pinMode(colPins[c],OUTPUT);               // Prepare column pin for sending a pulse.
        digitalWrite(colPins[c], LOW);            // Pulse the pin colPins[c] low.
        for (int r=0; r<kpdSize.rows; r++) {
            if (!digitalRead(rowPins[r])          // A key is PRESSED on row r, column c
                buttonstate[r][c] = 1;            // Store PRESSED keys.
            else
                buttonstate[r][c] = 0;            // Store OPEN keys.
        }
        digitalWrite(colPins[c], HIGH);          // End the pulse
        pinMode(colPins[c],INPUT);	         // Prevent shorts between columns when multiple keys are pressed.
    }

As a side question, once I have got this working, can I just map the state of each positon in the array to a midi signal and output that?

Sort of. You can create another array of midi signals and then scan through the buttonstate array looking for 1's and then you can output that certain midi signal.

Does that help?

Hmmm
Ive never seen code before where you set a pin as an input, and then set it high...

On this line:
for (int r=0; r<kpdSize.rows; r++) {

I assume kpdSize.rows is mereley the number of rows my keypad has and can be a constant?

a.mlw.walker:
Ive never seen code before where you set a pin as an input, and then set it high...

I have. That enables the internal pull-up resistors, giving a weak pull-up to those pins.

I wasn't suggesting it was wrong, more commenting on the fact that I would never have got that right as I didn't know about it.
You couldn't comment on my question though could you?

a.mlw.walker:
On this line:
for (int r=0; r<kpdSize.rows; r++) {

I assume kpdSize.rows is mereley the number of rows my keypad has and can be a constant?

Yes, sorry about that. :* I copied it from some of my code and forgot to change that. It should be ROWS like in your sketch.

Yeah, sorry about that. There was a lot of space between the lines on this one. After I finished the update I wrote a completely different post to announce it. :wink:

Since you recently downloaded the library you have all the changes supporting multiple key presses. The first thing you should do is load and run the Keypad MultiKey example sketch. It will get you started and has several comments that may help you use it in your sketch. Since you are doing midi, though, you will still be required to add diodes to your keys.

I dont know if i can help u.
But i had a problem when you keep pressed the keys cause if u keep pressed all keys of COL 1 and u press a key of COL2 the ground is received even from the keys in the COL2.
That's it's not a bug but it's a limitation of matrix circuit.

CIAO!

I have been trying to use this library to decode the a toy piano keyboard matrix, and it ALMOST does the job! But for that sort of thing, you need not only multi-keys, but also "key up" and "key down" events. The event handling in this library will give you an event for all those things, but it won't tell you what state it has gone into, just that something happened with the key!

It is an easy fix, but I didn't want to screw up anybody else's code, so I added a separate, parallel "statedEventListener" to solve the problem.

I'm not sure where to submit my changes, tho. I found the GitHub here: LIT-Arduino-Libraries/Keypad at master · kernd/LIT-Arduino-Libraries · GitHub
but it is horribly out of date.
Also, the source of the Teensy version at PJRC is ever so slightly different from the official one, despite having the same revision number in the file.
Anyway, here are my changes:

In keypad.h:

void addEventListener(void (*listener)(char));
void addStatedEventListener(void (*listener)(char, KeyState));// THIS
int findInList(char keyChar);

and

void (*keypadEventListener)(char);
void (*keypadStatedEventListener)(char, KeyState); // THIS
};

In Keypad.cpp, add this after the "addEventListener" function:

void Keypad::addStatedEventListener(void (*listener)(char, KeyState)){
keypadStatedEventListener = listener;
}

And add this to the end of "transitionTo":

if (keypadStatedEventListener!=NULL)
keypadStatedEventListener(key[n].kchar, nextState);

To set it up, do something like this:

customKeypad.addStatedEventListener(KeyListen);

And make a function like this:

void KeyListen(char key, KeyState state)
{
   switch (state )
   {
     case PRESSED:
       //do key down stuff
       break;
     case RELEASED:
       //do key up stuff
       break;
   }
}

I had written a longer explanation, but the forum logged me out while I was typing and I lost the post, so this will have to do.

Anyway, can somebody please tell me where to submit my changes?

Hi,

Have you tried this Phi_Interface library ? I have and I must say its very flexible and quite nice to use. I have not tried with multiple keypresses. But anyway just thought will mention.

More here : phi_interfaces | LiuDr Electronic Solutions LLC Official Blog

SoftEgg:
I have been trying to use this library to decode the a toy piano keyboard matrix, and it ALMOST does the job! But for that sort of thing, you need not only multi-keys, but also "key up" and "key down" events. The event handling in this library will give you an event for all those things, but it won't tell you what state it has gone into, just that something happened with the key!

Hello SoftEgg,

I'm the author of the keypad driver but I'm a bit curious about your statement. I've had several people create midi devices using this library. I think I understand what you are asking for but the library already provides the current state of every key that is active. Using a keypad object you can get, for example,

keypad.key[i].kstate

for each key 'i' in the list of active keys.

There are two examples included with the library that may help to explain what I am talking about; MultiKey and EventKeypad. They show how to accomplish the same thing that you wrote.

Unless I have completely misunderstood what you are saying, which is a very distinct possibility. :wink:

By the way, the latest keypad library can be found on the Playgound.