Pages: 1 [2] 3 4   Go Down
Author Topic: Matrix Keypad - Optimisation  (Read 5027 times)
0 Members and 1 Guest are viewing this topic.
Holland
Offline Offline
Sr. Member
****
Karma: 0
Posts: 439
Arduino likes cookies too
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 436
Posts: 23648
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


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.


Logged

Rob Tillaart

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

AZ
Offline Offline
Jr. Member
**
Karma: 0
Posts: 52
Effectiveness is the measure of truth
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 keyboardPin = 0;    // Analog input pin that the keypad is attached to
int keyboardValue = 0;   // value read from the keyboard

void setup(){
  
  
  Serial.begin(9600);  //hardware serial to PC
  
}


void loop(){
 
 
 keyboardValue = analogRead(keyboardPin); // read the keyboard value (0 - 1023)
 while (keyboardValue < 25){
   //do nothing until a key is pressed
 keyboardValue = analogRead(keyboardPin);
 delay(50);
                            }//end of do nothing till a key is pressed
                            
                            
 readkeyboard(); //get the value of key being pressed "keypressed" i.e. 0-9
 
}



//read the keyboard routine
void readkeyboard(){
   keyboardValue = analogRead(keyboardPin); // read the value (0-1023)
   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);
     keyboardValue = analogRead(keyboardPin); // read the value (0-1023)
   }//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

Logged

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 436
Posts: 23648
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Could call the extras A, B, C, D, #, * like the velleman keypad uses.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
« Last Edit: November 29, 2010, 01:22:06 pm by robtillaart » Logged

Rob Tillaart

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

AZ
Offline Offline
Jr. Member
**
Karma: 0
Posts: 52
Effectiveness is the measure of truth
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@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
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
 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:
 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  smiley-wink

Logged

Rob Tillaart

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

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 436
Posts: 23648
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

"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:
// your code
break;
case 2:
// your code
break;
:
:
case 15:
// your code
break;
}

also looks like not all of your if conditions have their ending }
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

AZ
Offline Offline
Jr. Member
**
Karma: 0
Posts: 52
Effectiveness is the measure of truth
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
« Last Edit: November 30, 2010, 09:42:44 pm by Deep_C » Logged

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 436
Posts: 23648
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 168
Posts: 12428
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley
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"
« Last Edit: December 01, 2010, 03:11:00 am by robtillaart » Logged

Rob Tillaart

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

AZ
Offline Offline
Jr. Member
**
Karma: 0
Posts: 52
Effectiveness is the measure of truth
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.  smiley-razz 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
Logged

AZ
Offline Offline
Jr. Member
**
Karma: 0
Posts: 52
Effectiveness is the measure of truth
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

keyboardValue = analogRead(keyboardPin); // read the keyboard value (0 - 1023)
while (keyboardValue < 25){
  //do nothing until a key is pressed
keyboardValue = analogRead(keyboardPin);
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 keyboardPin = 0;    // Analog input pin that the keypad is attached to
int keyboardValue = 0;   // value read from the keyboard

void setup(){
 
 
 Serial.begin(9600);  //hardware serial to PC
 
}


void loop(){


keyboardValue = analogRead(keyboardPin); // read the keyboard value (0 - 1023)
while (keyboardValue < 25){
  //do nothing until a key is pressed
keyboardValue = analogRead(keyboardPin);
delay(50);
}//end of do nothing till a key is pressed
                           
                           
readkeyboard(); //get the value of key being pressed "keypressed" i.e. 0-9

}



//read the keyboard routine
void readkeyboard(){
  keyboardValue = analogRead(keyboardPin); // read the value (0-1023)
  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);
    keyboardValue = analogRead(keyboardPin); // read the value (0-1023)
  }//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
Logged

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 436
Posts: 23648
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Pages: 1 [2] 3 4   Go Up
Jump to: