Go Down

Topic: keypad multiple key press (Read 14062 times) previous topic - next topic

a.mlw.walker

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

robtillaart

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.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

nickgammon

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:

Code: [Select]
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.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

mstanley

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

nickgammon

See this page for a discussion:

http://arduino.cc/forum/index.php?topic=95027.0
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

mstanley

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.

a.mlw.walker

#6
May 29, 2012, 10:14 pm Last Edit: May 29, 2012, 10:20 pm by a.mlw.walker Reason: 1
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..

nickgammon

I think you need diodes to prevent ghosting. The software fix will stop shorts but not ghosting.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

mstanley


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.

Quote

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. ;)  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.

Quote

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.

Quote

[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. 
Code: [Select]
#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:
Code: [Select]
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.)

a.mlw.walker

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?

Code: [Select]


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:
Quote

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?

mstanley


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.
Code: [Select]

// 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.
    }



Quote

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?

a.mlw.walker

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?

nickgammon


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.
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

a.mlw.walker

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?

mstanley


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.

Go Up