How to enter numerical data?

I'm trying to find a way to store a number entered on a 4x4 keypad. I've successfully hooked up my keypad. mapped the keys and printed individual keypresses to the serial monitor but don't know how to combine them into a decimal number. Where do I go from here? The eventual goal is to write this number to an lcd and use the number to calculate steps for a stepper motor.

Thanks

My first try would be to assemble the digits as characters in a string, and then convert the string to an integer. I guess there is no native string-to-int function in Arduino, but here's a discussion with some code to do that:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1285085509

Hint: multiply a number by ten to shift it.

i = 4
i = 4 * 10
i = i + 2

i contains 42.

Decimal or hexdec keypad?

Assuming decimal numbers, each digit you press is = 10x the next one, so something like

int value = 0;
int factor = 1000;

for (i = 3; i != 0; i--) {

   value += getKeyVal() * factor;
   factor /= 10;

}

Also assumes you always have 4 digits so may need mods, but that's the general idea.


Rob

Graynomad,

the time tested method of converting numbers as they're read for latin languages is like James described it. You're code isn't advisable - even if it works in many cases, it has no advantages.

int value = 0;

for (int i = 3; i != 0; i--) {
   value = value * 10 + getKeyVal();
}

Yep fair cop, that's more efficient.


Rob

Ok. That makes sense. I will play with this and see what I come up with. I noticed you declared the variable as an integer but I'm thinking I need to use a long to get the resolution I need. Does that change anything? (the values I will be inputting will be between 0.000 and 199.999)

Does that change anything?

Yes, it means you have to have a terminating key like enter to tell your program you have finished.

It also means you have to have a boolean variable that keeps track of if a decimal point has been entered and treats then digits differently depending on its value.

OK. I’ve finally found some time to play with this and here is what I have so far (using Korman’s code snippet):

#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keys[ROWS][COLS] = {
  {'7','8','9','A'},
  {'4','5','6','B'},
  {'1','2','3','C'},
  {'0','.','e','D'},
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {9, 8, 7, 6,}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
int value = 0;

void setup(){
  Serial.begin(9600);
}

void loop(){
  char key = keypad.getKey();              
  if (key != NO_KEY && key != 'e')         
  Serial.print (key);                            //prints input digit
  {
    
     for (int i = 3; i != 0; i--) {              //shifts digits to left
     value = value * 10 + key;
   
} if (key == 'e'){                               //prints value 
      Serial.println ();
      Serial.print (value);
      Serial.println ();}
   }
}

It displays the digits as I type them but when I hit “e” I get a result of ‘11211’ no matter what was entered previously.

Indentation's a bit screwy, but what is that for loop doing multiplying by powers of ten?

Yes, I need to learn better form. I'll work on that :). The bit with the powers of ten is an attempt to implement Korman's code (post #5 above). Obviously I don't understand it fully.

Yes, but in Korman's code, he got a new key value each time through the loop, not just kept using the same one.

I'm totally confounded! I keep looking at it but can't understand why "key" would not be a different value each time through the loop. If I describe how I see the logic perhaps someone could point out my erroneous thinking. Bear with me. When a key is hit the variable "key" is set to that key. The "if" statement tests to see that "key" is not an unpressed key nor an "e" We then serial.print "key" (up to this point everything works fine) let's say the first key entered is 2 1st loop: i=0, key=2 so value=value*2+key=0+2 2nd loop: i=1, key=3, so value=value*10+key=20+3=23 3rd loop: i=2, key=4, so value=value*10 +key=23+4=234 I hit "e" and and expect to print 234 but instead I print 11211.

Obviously I don't understand the logic. :-X

If there is no explicit assignment to it, like calling a 'getKey' method, then the value of 'key' can't change within the loop. korman's code did such an assignment, yours doesn't.

That should fix the mess your loop function has become.

void loop(){
  char key = keypad.getKey();
  switch (key) {
    case NO_KEY:
      // No key read. Do nothing
      break;

    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
      // Digits from 0 to 9
      // Don't forget we deal with ASCII characters and not numbers
      value = value * 10 + key[glow] - '0'[/glow];
      break;

    case 'e':
      // Enter key

      Serial.println ();
      Serial.print ("You have chosen to be spanked ");
      Serial.print (value);
      Serial.println (" times by our lovely hostess Gertrude.");
      // Additional processing for value goes in here
      // ...

      // Reset value. The last number is done
      value = 0;
      break;

    default:
      // All other keys
      Serial.println ();
      Serial.print ("Criminy! Don't press key '");
      Serial.print (key);
      Serial.println ("'! Another ");
      Serial.print (value);
      Serial.println (" puppies died in China.");

      // Reset value. The last number is done
      value = 0;
  }
}

Note the highlight, that was the reason for the strange value you got. You simply forgot to convert from ascii to the value of the digit.

Korman

Thank you Korman. I'm not sure that completely answers my question but it gives me a new approach to the problem (I've never used the "case/break" function before). Now I will have to ponder this and move on to the next step which will be to add the decimal portion of the value.

Best regards, Greg

Well, I worked hard all week and finally got my sketch to do what I want.
Many thanks to Korman. I’m sure it could be done in a more elegant manner and would appreciate if any of you could take the time to look at it and critique it for me.

/*This sketch reads a numbers from a 4x4 matrix keypad using either decimal
or fractional entry and returns a value in thousandths of an inch. */

#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keys[ROWS][COLS] = {
  {'7','8','9','A'},
  {'4','5','6','B'},
  {'1','2','3','C'},
  {'0','.','e','/'},
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {9, 8, 7, 6,}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
long value = 0;                    //value in thousandths of an inch
int dec_switch = 0;                //0=integer entry, 1=decimal entry, 2=fractional entry
int dec_place = 0;                 //tracks decimal place 
int frac_switch = 0;               //switches to fraction mode 
int numerator;                     //numerator value
int denominator;                   //denominator value 
float frac_value;                  //calculated decimal value of fraction

void setup(){
  Serial.begin(9600);
}

void loop(){
  char key = keypad.getKey();      //read keypad
  
  
  switch (key){ 
        case NO_KEY:
      // No key read. Do nothing
      break;

        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
      
        //Serial.print (key);
        
        if (frac_switch  == 1){                        //prints and evaluates numerator
          numerator = numerator * 10 + key - '0';      //prints and evaluates denominator
          Serial.print (key);
          }
        if (frac_switch  == 2){                        //prints and evaluates denominator
          denominator = denominator * 10 + key - '0';
          Serial.print (key);
          }  
                       
        if ( dec_switch == 0 ){                        //prints and evaluates integer 
        value = value * 10 + key - '0';
          Serial.print (key);
        }        
        else if ( dec_switch == 1 && dec_place < 3){    //prints and evaluates decimal
        value = value * 10 + key - '0';
          dec_place = dec_place + 1;
          Serial.print (key);
        
        }
        else if (dec_switch == 1 && dec_place == 3) {  //prevents entering extra decimal places
          Serial.println ();
          Serial.print ("Entry complete. Press Enter");
        }
                        
        break;

        case 'e':
      // Enter key
        if (frac_switch == 1){                          //multiplier for fractional value
          value = value * 1000;
                  
        }

       
        if (frac_switch == 0 && dec_place == 0){       
          Serial.print (".000");                         //prints decimal placeholder 
          value = value * 1000;                          //multiplier for integer only decimal value
        }
        else if (frac_switch == 0 && dec_place == 1){  
            Serial.print ("00");                        //prints decimal placeholder  
            value = value * 100;                        //multiplier for decimal place
            
        }
        else if (frac_switch == 0 && dec_place == 2){
            Serial.print ("0");                          //prints decimal placeholder
            value = value * 10;                          //multiplier for decimal place    
        }
        if (frac_switch == 2) {
          frac_value = (float)numerator/denominator;     //calculates value of fraction 
          value = (value + frac_value) * 1000;           //multiplier for decimal place   
        }
        
        
         
          
        
              Serial.println ();
              Serial.print ("The current value is: ");
              Serial.print (value);
              Serial.print (" thousandths.");
              Serial.println ();
              //Serial.println (numerator);
              //Serial.println (denominator);
              //Serial.print  (frac_value);
              //Serial.println ();
      

      // Reset values. The last number is done
      value = 0;      
        dec_switch = 0;
        dec_place = 0;
        frac_switch = 0;
        numerator = 0;
        denominator = 0;
        frac_value = 0;
        
        break;
        
        case '.':                          
        dec_switch = 1;                  //switches to decimal mode
        Serial.print (".");              //prints decimal point
        break;
        
        case '/':
          if (frac_switch == 0){
          Serial.print ("-");            
          frac_switch = 1;
          dec_switch = 2;
          } 
          else if (frac_switch == 1){
            Serial.print ("/");          
            frac_switch = 2;
          }
       
           break;

           
        
        
       
        
        
        
    default:
      // All other keys
      Serial.println ();
      Serial.print ("Criminy! Don't press key '");
      Serial.print (key);
      Serial.println ("'! Another ");
      Serial.print (value);
      Serial.println (" puppies died in China.");

      // Reset value. The last number is done
      value = 0;
  }
}

While I’m waiting for my LCD display to arrive I will work on some routines to prevent entry of invalid data but I would like to make sure I’ve got the basic sketch in its best form first.
Thanks again.

Greg