Go Down

### Topic: Matrix Keypad - Optimisation (Read 15624 times)previous topic - next topic

#### Imahilus

#15
##### Nov 25, 2010, 01:34 pm
Carls list looks like a good one for detecting single button presses.
If you want to be able to detect multiple button presses, the Vout of a button needs to be more than the total of all previous Vout values combined (presenting a exponential curve).
This also means the last button has the biggest tolerance issue, since it needs to take into account the tolerances of all the buttons before it.

To give a small list (that doesn't take into account tolerances):
button1 - Vout: .1V
button2 - Vout: .2V
button3 - Vout: .4V
button4 - Vout: .8V
button5 - Vout: 1.6V
(notice how this resembles binary counting?)
.6V is measured, meaning button 2 and 3 are pressed. 2.1V? buttons 1, 3 and 5.

#16
##### Nov 25, 2010, 02:58 pm
Wow - check the prices on those - I think it would be less expensive to just add another atmega to your design!  And then you could program in other functionality as well. Do some searches in the forum, I believe the crystal can be shared between chips, as well as the reset pin, so shouldn't need much in the way of other components.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

#### robtillaart

#17
##### Nov 25, 2010, 07:03 pm

Found this article http://www.avr-asm-tutorial.net/avr_en/keypad/keyboard.html See Chapter 3: Connection to an ADC with a resistor matrix. Although code is in assembler the resistor values are interesting as they seemed quite well tuned.

Rob Tillaart

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

#### Deep_C

#18
##### Nov 29, 2010, 06:13 pm
I've modified a circuit from an instructable http://www.instructables.com/id/Arduino-3-wire-Matrix-Keypad/step2/Wiring-up-the-resistors/

it uses very specific valued resistors and puts out a pretty nice linear value, rather than exponential. the key was to make a divider out of the keypad with a separate array for the columns going from ground to the analog input; and another array for the rows coming from 5 volts. this puts the analog input between the two arrays

In other words:

One array is

5V - 180ohm - row A - 680ohm - row B - 3.3kohm - row C - 15kohm - row D

This puts from 180 ohms to 19160 ohms from 5V to the analog in depending on which row the button is pressed

the other array is

Analog input - col1 - 1.2K ohm - col 2 - 1K ohm - col3 - 820 ohm - col4 - 1k ohm - ground

this puts  from 1000 ohms to 3020 ohms to the analog in to ground depending on which column the button is pressed.

this makes a voltage divider with 16 different values.

As for the problem with temperature drift, I would think it would be proportional. whereas the resistance on one side is going to change a similar percentage to the resistance on the other side, leaving the output essentially unchanged. at least unchanged enough that it won't be confuse which button is being pressed.

I put this into a spreadsheet to better get a baseline range, that may need a little tweaking once hooked up, but if you use  if arguments, with the values halfway between the nominal values for each button it will give you a broad range for each button it to  fall within and render the same results

I had to add four conditions and change the values since I added a 1.2K ohm resistor for the fourth column. This is the code from the instuctable modified for 16 keys versus the 12 keys it had.

int keypressed = 0;
int keyboardValue = 0;   // value read from the keyboard

void setup(){

Serial.begin(9600);  //hardware serial to PC

}

void loop(){

while (keyboardValue < 25){
//do nothing until a key is pressed
delay(50);
}//end of do nothing till a key is pressed

readkeyboard(); //get the value of key being pressed "keypressed" i.e. 0-9

}

if (keyboardValue <25){keypressed = 0;}
if (keyboardValue >25) && (keyboardValue < 68)){keypressed = 0;)
if (keyboardValue >68) && (keyboardValue < 108)){keypressed = 0;)
if (keyboardValue >108) && (keyboardValue < 153)){keypressed = 0;)
if (keyboardValue >153) && (keyboardValue < 186)){keypressed = 0;)
if ((keyboardValue >186) && (keyboardValue < 254)){keypressed = 1;}
if ((keyboardValue >254) && (keyboardValue < 361)){keypressed = 2;}
if ((keyboardValue >361) && (keyboardValue < 457)){keypressed = 3;}
if ((keyboardValue >457) && (keyboardValue < 525)){keypressed = 4;}
if ((keyboardValue >525) && (keyboardValue < 621)){keypressed = 5;}
if ((keyboardValue >621) && (keyboardValue < 738)){keypressed = 6;}
if ((keyboardValue >738) && (keyboardValue < 812)){keypressed = 7;}
if ((keyboardValue >812) && (keyboardValue < 854)){keypressed = 8;}
if ((keyboardValue >854) && (keyboardValue < 898)){keypressed = 9;}
if ((keyboardValue >898) && (keyboardValue < 945)){keypressed = 0;}
if ((keyboardValue >945) && (keyboardValue < 970)){keypressed = 0;}
if (keyboardValue >970){keypressed = 0;}
//NOTE: the values used above are all halfway between the value obtained with each keypress in previous test sketch

while (keyboardValue > 25) {
delay (100);
}//wait until key no longer being pressed before continuing

Serial.println(keypressed);      // print the value back to the Serial view window on your PC
delay(1000);                     // wait 1000 milliseconds before the next loop
}
//end of read the keyboard routine

as the instructable says this is a bit clunky, but functional code.

the next thing I need to do is figure out what I want the values to correspond to. the values it uses pretty much gives you a bunch of extra 0 keys for the non-numeric keys. that's where it gets a little confusing for me. I'd need to assign names to each key and then reference that name in the code. since some keys will have functions other than numeric values

I was reading about the map function which separates an analog input into a predetermined number of steps, but I'm not sure how it would mesh with the values the keypad matrix will put out.

I have the spreadsheet I mentioned in open office,  I also have a fritzing file with the schematic, It may not have the resistor values on it as fritzing only has certain resistance values. shoot me a message if you need these for better clarification

-carl

#19
##### Nov 29, 2010, 06:30 pm
Could call the extras A, B, C, D, #, * like the velleman keypad uses.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

#### robtillaart

#20
##### Nov 29, 2010, 07:13 pmLast Edit: Nov 29, 2010, 07:22 pm by robtillaart Reason: 1
Quote
if (keyboardValue <25){keypressed = 0;}
if (keyboardValue >25) && (keyboardValue < 68)){keypressed = 0;)
if (keyboardValue >68) && (keyboardValue < 108)){keypressed = 0;)

@Carl R
Although not your code I notice the "borders - 25 , 68 etc - " are not used. Is there a specific reason ? Logically there is a chance a keypress isn't interpreted correctly.
Rob Tillaart

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

#### Deep_C

#21
##### Nov 30, 2010, 01:51 pm
@robtillaart

I'm not sure what exactly you are asking, is borders a command?

if you are asking why there is no gap between the ranges, it is nearly impossible to get that extreme a value. in other words it is just telling the controller to interpret the value as the one it is closest to.

the reason I use 0 for a few of the buttons is I modified code from a 3x4 keypad, and was unsure how to specify other Values. I was thinking menu, enter, and as you suggested A, B, C, D  so if I have options I can use the letters to select it. i'm just foggy on how to define them

#### robtillaart

#22
##### Nov 30, 2010, 02:18 pm
Quote
if you are asking why there is no gap between the ranges

On contrary there is a gap in the values of keyboardValue tested: What happens if KeyboardValue is 25 or 68 or 108 or 153 or 186 or 254 or 361 etc ?

There will be no value set for keypressed!

Follow the algorithm by hand for one of these values and you see what I mean. There is no place in the algorithm where there is an equal sign in the comparison of keyboardValue. E.d. in the next two lines the value 525 will not match keypressed 4 and not with keypressed 5.

Code: [Select]
`  if ((keyboardValue >457) && (keyboardValue [glow]< 525[/glow])){keypressed = 4;}  if ((keyboardValue [glow]>525[/glow]) && (keyboardValue < 621)){keypressed = 5;}`
With borders I meant the border values of the ranges, upper /lower limit of a range that belongs to one value of keypressed.

So the code should read like
Code: [Select]
`  if ((keyboardValue >[glow]=[/glow]525) && (keyboardValue < 621)){keypressed = 5;}` and that for all comparisons of course.

Quote
it is nearly impossible to get that extreme a value

So it is possible so the algorithm should deal with it. OK I assume it is not part of the control of a nuclear power plant or a automatic pilot for planes (or is it?) so it's not that critical

Rob Tillaart

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

#23
##### Nov 30, 2010, 04:19 pm
"i'm just foggy on how to define them "
Just give them a value then:
{keypressed = 0;)}  instead of 0 use 10, 11, 12, 13, 14, 15

then if you make decisions based on the key pressed later on,  you can do this:

switch(keypressed)
{
case 1:
break;
case 2:
break;
:
:
case 15:
break;
}

also looks like not all of your if conditions have their ending }
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

#### Deep_C

#24
##### Dec 01, 2010, 03:37 amLast Edit: Dec 01, 2010, 03:42 am by Deep_C Reason: 1
thanks for the clarification on keypressed, that makes sense, and I see where i missed the }'s you mentioned, thanks for catching that.

As for the borders, it is highly unlikely the value will ever be that far away from the center of the range. I'll likely use this code as a beginning, and use the serial monitor to see where the values actually come in for each key. Then I'll split the difference between each one to give me the ranges. I could use >= to for one side of the arguments to include those values, but I don't really think it's needed.

regards,

Carl

#25
##### Dec 01, 2010, 05:58 am
just go thru & press = 16 times, give us all some peace of mind:-)

I used a programmable state machine chip for work years ago, and the 1 state of 32 that I didn't define is the one that it powered up into. So during development  had to pull them off and program new ones that defined every state, even if it was just to go to the starting state.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

#### robtillaart

#26
##### Dec 01, 2010, 09:09 amLast Edit: Dec 01, 2010, 09:11 am by robtillaart Reason: 1
Quote
I could use >= to for one side of the arguments to include those values, but I don't really think it's needed.

How do you think you will get working/robust/failsafe programs if you "deny" simple bugs like this one. There are zillion projects  (including my own)  that tried hard to make programs robust and still unwanted sideeffects (aka bugs) appeared.  Read History's Worst Software Bugs http://www.wired.com/software/coolapps/news/2005/11/69355

For those with a deeper interest in bugfree software development - not available for Arduino
http://www.verum.com/pdf/resources/locked/White_Paper_An_Introduction_to_ASD.pdf

"there are so many errors to choose from,  so why make them twice"
Rob Tillaart

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

#### Deep_C

#27
##### Dec 01, 2010, 04:25 pm
I will let you know what happens when I press each one numerous times, I'm currently waiting for the resistors to come.  and I'll fix that bug, but it still seems pretty unnecessary.   if it is one of those values, who's to say which key it represents? If I use the serial monitor and get the value that comes up for each one, and split the difference between each key, it should never come close to the extremes.

I mean, what could go wrong if we only use 2 digits to represent the year??

-carl

#### Deep_C

#28
##### Dec 01, 2010, 07:01 pm
Now that you are scrutinizing my code as I should be, I guess I will;

I notice a few other problems below;

I changed the keypressed values and in doing so noticed I had an extra argument (17 possible keys)

Quote
if (keyboardValue <25){keypressed = 0;}

this range is actually in the while statement at the very beginning so that if it is less than 25 it does nothing until something is pressed.

am I right to want to exclude this range from  void readkeyboard? or do I want to define a state in there from 0-25 as a keypressed state?

it wouldn't make sense to me as no key is actually pressed and that while statement seems to take care of that......I think

in the code below I fixed the errors you mentioned and removed that keypressed state of <25

and made the first keypressed range 25 - 68

Quote
if (keyboardValue >=25) && (keyboardValue <68){keypressed = 1;}

As shown above I also forgot a pair of parentheses on both sides of the keyboardValue statements which while not correct below, I did fix in my code; I noticed it after beginning this message.

this is the statement I speak of that I think excludes the values below 25, but i don't completely understand it.

Quote

while (keyboardValue < 25){
//do nothing until a key is pressed
delay(50);
}//end of do nothing till a key is pressed

I began this with the code from a 3x4 matrix, and never verified it beforehand but, as I understand the code, it's supposed to be telling it to do nothing. I don't get how it is accomplishing that. it seems to me, that it is telling it the value is whatever it reads on the analog pin.

Quote

int keypressed = 0;
int keyboardValue = 0;   // value read from the keyboard

void setup(){

Serial.begin(9600);  //hardware serial to PC

}

void loop(){

while (keyboardValue < 25){
//do nothing until a key is pressed
delay(50);
}//end of do nothing till a key is pressed

readkeyboard(); //get the value of key being pressed "keypressed" i.e. 0-9

}

if (keyboardValue >=25) && (keyboardValue <68){keypressed = 1;}
if (keyboardValue >=68) && (keyboardValue < 108)){keypressed = 2;}
if (keyboardValue >=108) && (keyboardValue < 153)){keypressed = 3;}
if (keyboardValue >=153) && (keyboardValue < 186)){keypressed = 4;}
if ((keyboardValue >=186) && (keyboardValue < 254)){keypressed = 5;}
if ((keyboardValue >=254) && (keyboardValue < 361)){keypressed = 6;}
if ((keyboardValue >=361) && (keyboardValue < 457)){keypressed = 7;}
if ((keyboardValue >=457) && (keyboardValue < 525)){keypressed = 8;}
if ((keyboardValue >=525) && (keyboardValue < 621)){keypressed = 9;}
if ((keyboardValue >=621) && (keyboardValue < 738)){keypressed = 10;}
if ((keyboardValue >=738) && (keyboardValue < 812)){keypressed = 11;}
if ((keyboardValue >=812) && (keyboardValue < 854)){keypressed = 12;}
if ((keyboardValue >=854) && (keyboardValue < 898)){keypressed = 13;}
if ((keyboardValue >=898) && (keyboardValue < 945)){keypressed = 14;}
if ((keyboardValue >=945) && (keyboardValue < 970)){keypressed = 15;}
if (keyboardValue >=970){keypressed = 16;}
//NOTE: the values used above are all halfway between the value obtained with each keypress in previous test sketch

while (keyboardValue > 68) {
delay (100);
}//wait until key no longer being pressed before continuing

Serial.println(keypressed);      // print the value back to the Serial view window on your PC
delay(1000);                     // wait 1000 milliseconds before the next loop
}
//end of read the keyboard routine

Thanks again for all your patience and direction. I couldn't imagine trying to figure this all out on my own.

-carl

#29
##### Dec 01, 2010, 07:24 pm
I can see the point of the while <25 loop - the code just sits in there reading the value every 50mS until it sees a key pressed (value >=25).
Is your program going to do anything else? Or just sit there  monitor the keypad its whole existince?
You could do something else instead - see the blink without delay program.
You basically put your code inside a larger loop.
The outer one checks the time passed, say every 100mS, if 100mS hasn't passed you ignore your keypad and do other stuff. When you hit the 100mS mark, you read the keypad, if nothing is pressed go do other stuff again.

The analog pin sits at ~0V when no key is pressed because all the resistors are only connected to ground until a key is pressed?
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Go Up