Go Down

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

robtillaart

#30
Dec 01, 2010, 07:35 pm Last Edit: Dec 01, 2010, 07:35 pm by robtillaart Reason: 1
Well done Carl, your skills are improving, however (there allways is) readkeyboard() reads the keyboard again and by doing so it could read again a value below 25 or so. So instead I propose a function that will interpret the keyboardValue read

Note: Code not compiled or tested

Code: [Select]

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
                                           
 int k = kbValue(keyboardValue);   // maps the value of the key being pressed "keypressed" i.e. 0-9
 
 Serial.println(k);                // print the value back to the Serial view window on your PC
 delay(1000);
}

// interpret the keyboard routine
int kbValue(int kbv)
{
 keypressed = 1;
 if (keyboardValue >=68) keypressed++;
 if (keyboardValue >=108) keypressed++;
 if (keyboardValue >=153) keypressed++;
 if ((keyboardValue >=186) keypressed++;
 if ((keyboardValue >=254) keypressed++;
 if ((keyboardValue >=361) keypressed++;
 if ((keyboardValue >=457) keypressed++;
 if ((keyboardValue >=525) keypressed++;
 if ((keyboardValue >=621) keypressed++;
 if ((keyboardValue >=738) keypressed++;
 if ((keyboardValue >=812) keypressed++;
 if ((keyboardValue >=854) keypressed++;
 if ((keyboardValue >=898) keypressed++;
 if ((keyboardValue >=945) keypressed++;
 if (keyboardValue >=970) keypressed++;
 
 do
 {  
   delay (100);
   keyboardValue = analogRead(keyboardPin); // read the value (0-1023)
 } while (keyboardValue > 68);          //wait until key no longer being pressed before continuing
 
 return keypressed;
}


Another point of attention is that in readkeyboard you test keyboard value even if keypressed has gotten a value. Replace all the if's with multiple nested if else .. Here a snippet of code how that could be done.

Code: [Select]

 keyboardValue = analogRead(keyboardPin); // read the value (0-1023)
 if (keyboardValue < 68){keypressed = 1;}
 else if (keyboardValue < 108)) {keypressed = 2;}
 else if (keyboardValue < 153)) {keypressed = 3;}
 else if (keyboardValue < 186)) {keypressed = 4;}
 else if .... etc

The tests are simpler and the number of tests are less. This is caused by the fact that we use earlier tested information. If a value is not smaller than 68 it must be greater or equal so we do not need to test that.
Rob Tillaart

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

CrossRoads

too bad we can't combine them; 'case xx:' needs to be a discrete value for xx:

Code: [Select]

int value = 0;
void setup(){}
void loop(){
value = analogRead(keypess); // or whatever the read statement is
 switch (value)
 {
   case (value<25):
// do something
   break;

   case (value>25 && value <68):
// do something else
   break;
 }
}
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.

Carl R

Boy, you guys are snappy,

@robtillaart

I see how your code is superior; if i understand it correctly, instead of checking the values for each if statement, it instead reads through all the possible values incrementing the keypressed and once it exceeds the value it doesn't increment any further an stays the value right before the value it no longer exceeds. brilliant

@CrossRoads

you say that Case won't work right? it would be nice if it did. why wouldn't it and what situation would be appropriate for the case function??

I haven't come across that yet.


thanks again,

Carl

CrossRoads

You will need to define the number using the if statements you have, then you can proceed with this funtionality
switch(keypressed)
{
case 1:
//
break;
case 2:
//
break;
:
:
case 16:
//
break;
}

The compiler won't accept the 'case (value<25): type statement, I tried  ::)
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

#34
Dec 01, 2010, 09:31 pm Last Edit: Dec 01, 2010, 09:33 pm by robtillaart Reason: 1
Quote
you say that Case won't work right? it would be nice if it did. why wouldn't it and what situation would be appropriate for the case function??


"Case" is part of the switch statement and it needs discrete values like int char long or byte. A typical usage of a switch is

Code: [Select]
incomingChar = Serial.read();
switch (incomingChar)
{
 case 'A' : DoTheAcommand();
   break;     // this jumps out of the switch
 case 'B' : DoTheBcommand();
   break;
 ...
default:  DoError("unexpected char");
}

In essence a switch statement is a faster and more intuitive way to write many if ..  if ... if ... statements or many if .. else if ... statements. See more http://arduino.cc/en/Reference/SwitchCase
Rob Tillaart

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

Carl R

#35
Dec 01, 2010, 11:20 pm Last Edit: Dec 02, 2010, 03:41 pm by Deep_C Reason: 1
robtillaart said:

Quote

Another point of attention is that in readkeyboard you test keyboard value even if keypressed has gotten a value. Replace all the if's with multiple nested if else .. Here a snippet of code how that could be done.

Code: [Select]

 keyboardValue = analogRead(keyboardPin); // read the value (0-1023)
 if (keyboardValue < 68){keypressed = 1};
 else if (keyboardValue < 108)) {keypressed = 2};
 else if (keyboardValue < 153)) {keypressed = 3};
 else if (keyboardValue < 186)) {keypressed = 4};
 else if .... etc



The tests are simpler and the number of tests are less. This is caused by the fact that we use earlier tested information. If a value is not smaller than 68 it must be greater or equal so we do not need to test that.



would that work like that or would I need to start a the high end and work my way down

ie

Code: [Select]
keyboardValue = analogRead(keyboardPin); // read the value (0-1023)
 if (keyboardValue > 970){keypressed = 16;}
 else if (keyboardValue > 945)) {keypressed = 15;}
 else if (keyboardValue > 898)) {keypressed = 14;}
 else if (keyboardValue > 854)) {keypressed = 13;}
 ...
 else if (keyboard value > 24) {keypressed = 1;}


that way in the case where no key is pressed is represented by nothing happening and it will just loop around and scan the value again and evaluate it against  the multiple nested if else statements until it is above 24

another thing that concerns me with the code is

Code: [Select]
 
 Serial.println(k);                // print the value back to the Serial view window on your PC
 delay(1000);


the delay seems long. won't it take a second between each keypress? or is that so it doesn't put out multiple digits for the same key press? am I misunderstanding the function of the delay there?

one final question, in the code you sent, don't I need to initialize all the new variables you mention

Code: [Select]
int k = 0;
int kbvalue = 0;
int kbv = 0;


Thanks again,

Carl

CrossRoads

#36
Dec 02, 2010, 12:36 am Last Edit: Dec 02, 2010, 12:39 am by CrossRoads Reason: 1
The other thing you could is this:
(sticking in all  your correct names & values,  before setup & in setup, etc)

Code: [Select]

void  loop(){
value = readAnalog(inputpin);

if (value<=25)
{
delay (30); // for debounce of next press
//do nothing}  // and all the else if's are skipped, no key has been pressed
else if (value>25 or value <=68) {keypressed = 1;} // or the sequencing up/down in the last exchange
else if (value >68 or value <=125) {keypressed = 2;}
// ... down to 16th

switch(keypressed){
case 1:
//
break;
case 2:
// break;
etc down to 16th

}

make sure to set value = 0 if no key is pressed so that the switch:case is not going to try and work on an old value. Or add value=0 prior to each break statement so it gets cleared after good button press.
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.

Carl R

#37
Dec 02, 2010, 03:55 pm Last Edit: Dec 02, 2010, 04:05 pm by Deep_C Reason: 1
That makes sense, if it is less than or equal to 25 it will wait 30mS and reevaluate it again for 25, once it exceeds 25 it will continue with the other else if commands and when it finds which one it satisfies, sets the keypressed value to that number and then it has a discrete value for the switch/case statements which will easily implement the corresponding commands. then it goes back to the beginning.

if a key is pressed though and held longer than the 30mS will it then execute the case again?

thanks for throwing more ideas at me, I rewrite the code each time and learn a new way of looking at it. a great learning experience.  ;)

-carl

CrossRoads

No problem Carl. I started arduino-ing myself in August (after not having done any code writing since the late 80's), am starting to get the hang of it myself again.
Robert
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.

Carl R

#39
Dec 02, 2010, 05:25 pm Last Edit: Dec 02, 2010, 05:53 pm by Deep_C Reason: 1
if i understand this right,  I could redefine keypressed as char long and then use the actual names for the keys, ie  0 -9 a b c d menu enter, instead of 1-16

then when writing the code for the different cases I don't mix up which key I'm actually pressing

Another question can I nest case statements?

ie
Code: [Select]


switch(keypressed){
case menu:
//display options

switch (keypressed){
case a:
//do a
break;

case b:
//do b
break;

case c:
//do c
break;

case d:
//do d
break;
}
break;

case xx:
//continue other cases


and then continue primary case commands for other keys



thanks again,

Carl

robtillaart

#40
Dec 02, 2010, 06:39 pm Last Edit: Dec 02, 2010, 06:40 pm by robtillaart Reason: 1
Yes you can nest switch statements but proper indenting your code will help to keep the overview in the editor. Use tools >> auto format or press CTRL-T


Rob Tillaart

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

CrossRoads

Not sure if you can use just letters like that, or if they need to defined as 'a', 'b', etc.
Try it, see which way works.
not sure 'char long' is a type - think you only get char, or unsigned char. 1 byte long in either case.

Nested Switch:case works.
Need to watch the {} and getting the break; out of the case in all the right places.
switch(value)
{
case 1:
 switch(value2)
 {
 case 'a':
 // code 'a'
 break;
 }
break;
case 2:
// code 2
break;
}
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

#42
Dec 02, 2010, 07:52 pm Last Edit: Dec 02, 2010, 08:00 pm by robtillaart Reason: 1
Must be defined as 'a' 'b' as then they are of the type char, just  a would be a variable name.

The values allowed in a switch statement behind the case include  byte, char, int, long and unsigned versions of it. Furthermore the enum type can be used.

// sample code to show the usage of enum type
Code: [Select]

enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };

void setup()
{

 Days thisDay = Sunday;
 
 switch ( thisDay )
 {
   case Sunday:
   break;
   case Monday:
   break;
   case Tuesday:
   break;
 }
}

void loop()
{
}


[edit]enums are ideal for state machines[/edit]
Rob Tillaart

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

CrossRoads

enum - that's kinda neat. Could make following code easier.
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.

Carl R

it's not liking my using char's for keypressed values; i'm assuming because it's a case label and needs to be an integer

keypad:62: error: case label does not reduce to an integer constant

it refers to line 62 which is the line prior to where I declare case "a" line 62 is blank ; there is of course one of these errors for each non numerical keypressed value I declare

Code: [Select]

case "a":
// do a
break;


keypad:35: error: invalid conversion from 'const char*' to char

Code: [Select]
else if ((keyboardValue >108) && (keyboardValue <=153)){keypressed = 3;}
 else if ((keyboardValue >153) && (keyboardValue <=186)){keypressed = "a";}


line 35 is the line where I declare (keypressed = 3;)


I guess I could define the cases as numbers and just have a comment for the non numerical keys as to what they represent and change keypressed back to an integer;

will try that;


Go Up