Using a 4 by4 Keypad to Get an Integer

Like everyone else, I need some help!

I am trying to get input of 1 to 4 digits from a 4 by 4 keypad and convert them to an integer. I want to use the number to tell a stepper motor how many steps to take in manual mode. As examples, 25 or 1723 followed by a < or an > as a “Start in Direction” key.
I have been trying everything for a couple of days. I have has good success in other parts of programming the rest of the project but I don’t know too much about this stuff. I guess that the char key = keypad.getKey(); gives me characters. One minute it looks like a number then the next, it comes out as a two digit ascii version.

I’ve attacked this about five different ways but fall short every time. The many related example files don’t quite work in this situation. I want to use atoi but first I think that I need to use an array and some string constructors to put it together first. I just don’t know how to work this. What can I do?

You could start by showing us your code. Guessing what you are trying just will not work.

Simple code:

int Value = 0;
.
.
.
// Inside Loop or make into function
if(getKey() >= '0' && getKey()  <= '9') // it's a digit
{
   Value = Value * 10 + (getKey() - '0');
}

else if(getKey() == '>' )
{
 // step clockwise
 Value = 0; // Once the  stepper has stepped, reset Value back  to zero.
}

else if(getKey() == '<' )
{
 // step C-clockwise
 Value = 0;  // Once the  stepper has stepped, reset Value back  to zero.
}

else 
 //print invalid entry

HazardsMind:
Simple code:

Perhaps you should ask your question on http://snippets-r-us.com/

Good thing it’s a lazy sort of day, and I had nothing better to do. Here’s an example, using Serial .

int Value;
bool direction;

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

void loop() {

  while (Serial.available() > 0) {
    char in = Serial.read();
    if ( in >='0' && in <='9' ) {
      Value = Value * 10 + (in - '0');
    }
    else if ( in == '>' ) {
      direction = true;
      show();
    }
    else if ( in == '<' ) {
      direction = false;
      show();
    }
  }
}

void show() {
    Serial.print(Value);
    Serial.println( (direction ? "CW": "CCW"));
    Value = 0;
}

What I gave was meant to point the OP in the right direction, it was not meant to work without first filling the rest in. If you actually looked at my code, when would if(getKey() >= ‘0’ && getKey() <= ‘9’) // it’s a digit ever work on its own?

Yes it is a snippet, but sometimes that is all that is needed.

HazardsMind:
What I gave was meant to point the OP in the right direction, it was not meant to work without first filling the rest in. If you actually looked at my code, when would if(getKey() >= ‘0’ && getKey() <= ‘9’) // it’s a digit ever work on its own?

Yes it is a snippet, but sometimes that is all that is needed.

It wouldn’t work, of course. Why do you ask?

As for the snippet; yes, the full code isn’t needed, but full code that illustrates the problem is desirable. By that I mean that I should be able to copy it, paste it into the IDE, and try it, modify it, etc., in order to MORE EASILY help the person with the problem. Under most circumstances, I would not have bothered even looking at the code, let alone write an example, and among the folks that VOLUNTEER their time and efforts to help, I don’t think my sentiment is rare.

Edit: My apologies, HazardsMind. I didn’t realize it was your code. I could have paid more attention to who posted it.

The reason that I didn’t offer up any code is because it was all garbage. I don’t know if this is the right word to use but I needed help with the architecture before I started writing specific code.

Sorry, I was out of town for a couple of days. I didn’t have internet to see your responses. I want to thank you all for the input.
I did get one night to work on this without seeing your responses. I am posting it below. It works but it is long and clunky. Of course it is not cleaned back up and it doesn’t have any error checking or have the ability to back space and replace errant entries or anything like that. It just takes 4 keypad entries and spits out a integer.

I will try the stuff that you have posted.

#include <Keypad.h>
int oneNumber;
int twoNumber;
int threeNumber;
int fourNumber;
int junk;
int keyInt[4];// = {\0,\0,\0,\0};
char* val = “0”;
char* val2 = “0”;
int numberKey = 1;
const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
{‘1’,‘2’,‘3’,‘A’},
{‘4’,‘5’,‘6’,‘B’},
{‘7’,‘8’,‘9’,‘C’},
{’*’,‘0’,’#’,‘D’}
};
byte rowPins[ROWS] = {45, 43, 41, 39}; //connect to the row pinouts of the keypad 37, 35, 33, 31
byte colPins[COLS] = {37, 35, 33, 31}; //connect to the column pinouts of the keypad

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

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

void loop()
{
char key = keypad.getKey();

if (key)
{
val[0] = key;
switch (key)
{
case ‘*’:
Serial.println(“Do this.”);
break;
case ‘#’:
Serial.println(“Do that.”);
break;
default:
// Serial.println(key);

int a = atoi(val);
// Serial.println(a);
keyInt[numberKey] = a;
// Serial.println(numberKey);
switch (numberKey)
{
case 4:
oneNumber = keyInt[1] * 1000;
twoNumber = keyInt[2] * 100;
threeNumber = keyInt[3] * 10;
fourNumber = keyInt[4];
junk = oneNumber + twoNumber + threeNumber + fourNumber;
Serial.println(junk);
break;
case 3:
oneNumber = keyInt[1] * 100;
twoNumber = keyInt[2] * 10;
threeNumber = keyInt[3];
junk = oneNumber + twoNumber + threeNumber;
Serial.println(junk);
break;
case 2:
oneNumber = keyInt[1] * 10;
twoNumber = keyInt[2];
junk = oneNumber + twoNumber;
Serial.println(junk);
break;
case 1:
oneNumber = keyInt[1];
junk = oneNumber;
Serial.println(junk);
// Serial.println(oneNumber);
// Serial.println(keyInt[1]);
// Serial.println(numberKey);
break;

}
numberKey = numberKey + 1;
}
}
}

Wow!

Architecture is great be finished code is so my better. It worked right out of the box.

Thank you

I have a new question. I added an ELSE IF that let me find ‘#’ key pushes and that worked. I got it to go to a different function. Once there, I look for ‘1’ or ‘2’ but it doesn’t see it. I tried asking the program to look for key2 but that didn’t work.

How can I branch and look for another input.

This is the code that I have so far. When I enter 4 integers and then hit ‘C’ or ‘D’, I get i.e. 1234>. If I enter 5 or more characters I get an error but when hit ‘C’ or ‘D’, I get what I want. When I hit ‘#’, I ask:
Automatic Manual
1 or 2
but when a ‘1’ or ‘2’ is pushed, Serial.print finds no record of it.

#include <Keypad.h>
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>

Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
int in;
int DIR;
int Value;
int autoInputFork;
int inputDigitCount = 0;
bool direction;
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns

char keys[ROWS][COLS] = 
{
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

byte rowPins[ROWS] = {45, 43, 41, 39}; //connect to the row pinouts of the keypad 37, 35, 33, 31
byte colPins[COLS] = {37, 35, 33, 31}; //connect to the column pinouts of the keypad

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

void setup()
{
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.setCursor(9,0);
  lcd.print("                ");
  lcd.setCursor(9,1);
  lcd.print("                ");  
  lcd.setCursor(0,0);
  lcd.print("Pick < or >  Bk*");
  lcd.setCursor(14,0);
  lcd.setCursor(0,1);
  lcd.print("Manual Mode");  
  lcd.setCursor(12,1);  
}
  
void loop()
{
//>>>>  oldLocation = stepsToNextStation;
  int in;
  int DIR;
  int newDir;  
  int oldLocation;
  int oldDirection;
  char ch;
  newDir = DIR;
  getNumber();
 }

void getNumber()
{
  char key1 = keypad.getKey();
  
  if (key1)
   {
   in = key1;

    if ( in >='0' && in <='9' ) 
     {
       if(inputDigitCount >= 4 )
        {
        tooManyDigits();
        }
        else
        {
        inputDigitCount = inputDigitCount + 1;
        Serial.println(inputDigitCount);
        lcd.print(key1);        
        Value = Value * 10 + (in - '0');
        }
     }
     else if ( in == 'A' ) 
     {
//>>     raiseTheBoom();
     }         
      else if ( in == 'B' ) 
     {
//>>     lowerTheBoom();
     }        
     else if ( in == 'C' ) 
     {
       DIR = 1;
       goLeft();
     }     
     else if ( in == 'D' ) 
     {
//       direction = true;
       DIR = -1;
       goRight();      
     }
     else if ( in == '*' ) 
     {
       manualReEntryPoint();
     }
     else if ( in == '#' ) 
     {
       manualEntryPoint(); // <<<<<<<<<<<<<<<<<<<<<<<<
     }
   }
}

void manualEntryPoint()   // <<<<<<<<<<<<<<<<<<<<<<<<<
{
    Value = 0;
    inputDigitCount = 0;    
    lcd.setCursor(0,0);
    lcd.print("                ");    
    lcd.setCursor(0,0);
    lcd.print("Automatic Manual");   
    lcd.print("                ");
    lcd.setCursor(0,1);     
    lcd.print("   1   or   2   ");    
    inputDigitCount = 0;
    Value = 0;
    char key2 = keypad.getKey();

    if (key2)
   {
     lcd.setCursor(0,0);
     lcd.print(key2);
     autoInputFork = key2;     
     Value = Value * 10 + (autoInputFork - '0');
    if(autoInputFork == '1' )
     {
     //do something
     }
    else if(autoInputFork == '2')
    {
     Serial.print("Get Number");
     lcd.setCursor(9,0);
     lcd.print("                ");
     lcd.setCursor(9,1);
     lcd.print("                ");  
     lcd.setCursor(0,0);
     lcd.print("Pick < or >  Bk*");
     lcd.setCursor(14,0);
     lcd.setCursor(0,1);
     lcd.print("Manual Mode");  
     lcd.setCursor(12,1);
    }
   }
}

void manualReEntryPoint() 
{
    Serial.print("manualReEntryPoint");
    lcd.setCursor(12,1);
    lcd.print("      ");
    inputDigitCount = 0;
    Value = 0;
    lcd.setCursor(12,1);
}

void tooManyDigits()
{
  Serial.println("Only 4 digits are allowed   ");
  lcd.setCursor(0,0);
  lcd.print("                ");
  lcd.setCursor(0,1);  
  lcd.print("            ");
  lcd.setCursor(0,1);
  lcd.print("Manual Mode");  
  lcd.setCursor(0,0);
  lcd.print("Only 4 digits   ");
  delay(1000);
  lcd.setCursor(0,0);
  lcd.print("                ");
  lcd.setCursor(0,0);  
  lcd.print("Pick < or >  Bk*");  
}

void moveToNextStation(int stepsToNextStation, int DIR)
{
//This will be removed when incorporated into bigger program.
}

void goLeft() 
{
    Serial.print(Value);
    Serial.println( (direction ? "<": ">"));
    lcd.setCursor(12,1);
    lcd.print("      ");
    inputDigitCount = 0;
    Value = 0;
    lcd.setCursor(12,1);
//>>    moveToNextStation(stepsToNextStation, DIR);
}

void goRight()    
{
    Serial.print(Value);
    Serial.println( (direction ? "<": ">"));
    lcd.setCursor(12,1);
    lcd.print("      ");
    inputDigitCount = 0;
    Value = 0;
    lcd.setCursor(12,1);
//>>    moveToNextStation(stepsToNextStation, DIR);
}

The reason is that you only get a key when one is pressed. It does not buffer keystrokes.

You could write a loop in order to wait for a key in your function.

Change

    char key2 = keypad.getKey();

to something like

    while () {
       char key2 = keypad.getKey();
          if (key2 == '1' || key2 == '2') {
             break;
       }
    }

Unfortunately, I took it literally and did what you said with out what would be obvious customizations for my code so I got this when I tried to compile it.

HelloKeypad2Net.ino: In function 'void manualEntryPoint()':
HelloKeypad2Net:124: error: expected primary-expression before ')' token
HelloKeypad2Net:133: error: 'key2' was not declared in this scope

Did you change that one line to the entire “change to” code that I posted? If so, where did the error highlight show up (which line)?

Could you repost your code with the changes?

It points to the while() line 124

#include <Keypad.h>
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>

Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
int in;
int DIR;
int Value;
int autoInputFork;
int inputDigitCount = 0;
bool direction;
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns

char keys[ROWS][COLS] = 
{
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

byte rowPins[ROWS] = {45, 43, 41, 39}; //connect to the row pinouts of the keypad 37, 35, 33, 31
byte colPins[COLS] = {37, 35, 33, 31}; //connect to the column pinouts of the keypad

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

void setup()
{
  Serial.begin(9600);
  lcd.begin(16, 2);
  lcd.setCursor(9,0);
  lcd.print("                ");
  lcd.setCursor(9,1);
  lcd.print("                ");  
  lcd.setCursor(0,0);
  lcd.print("Pick < or >  Bk*");
  lcd.setCursor(14,0);
  lcd.setCursor(0,1);
  lcd.print("Manual Mode");  
  lcd.setCursor(12,1);  
}
  
void loop()
{
//>>>>  oldLocation = stepsToNextStation;
  int in;
  int DIR;
  int newDir;  
  int oldLocation;
  int oldDirection;
  char ch;
  newDir = DIR;
  getNumber();
 }

void getNumber()
{
  char key1 = keypad.getKey();
  
  if (key1)
   {
   in = key1;

    if ( in >='0' && in <='9' ) 
     {
       if(inputDigitCount >= 4 )
        {
        tooManyDigits();
        }
        else
        {
        inputDigitCount = inputDigitCount + 1;
        Serial.println(inputDigitCount);
        lcd.print(key1);        
        Value = Value * 10 + (in - '0');
        }
     }
     else if ( in == 'A' ) 
     {
//>>     raiseTheBoom();
     }         
      else if ( in == 'B' ) 
     {
//>>     lowerTheBoom();
     }        
     else if ( in == 'C' ) 
     {
       DIR = 1;
       goLeft();
     }     
     else if ( in == 'D' ) 
     {
//       direction = true;
       DIR = -1;
       goRight();      
     }
     else if ( in == '*' ) 
     {
       manualReEntryPoint();
     }
     else if ( in == '#' ) 
     {
       manualEntryPoint(); // <<<<<<<<<<<<<<<<<<<<<<<<
     }
   }
}

void manualEntryPoint()   // <<<<<<<<<<<<<<<<<<<<<<<<<
{
    Value = 0;
    inputDigitCount = 0;    
    lcd.setCursor(0,0);
    lcd.print("                ");    
    lcd.setCursor(0,0);
    lcd.print("Automatic Manual");   
    lcd.print("                ");
    lcd.setCursor(0,1);     
    lcd.print("   1   or   2   ");    
    inputDigitCount = 0;
    Value = 0;
    
    while () 
       {
       char key2 = keypad.getKey();
          if (key2 == '1' || key2 == '2') 
          {
             break;
          }
       }

    if (key2)
   {
     lcd.setCursor(0,0);
     lcd.print(key2);
     autoInputFork = key2;     
     Value = Value * 10 + (autoInputFork - '0');
    if(autoInputFork == '1' )
     {
     //do something
     }
    else if(autoInputFork == '2')
    {
     Serial.print("Get Number");
     lcd.setCursor(9,0);
     lcd.print("                ");
     lcd.setCursor(9,1);
     lcd.print("                ");  
     lcd.setCursor(0,0);
     lcd.print("Pick < or >  Bk*");
     lcd.setCursor(14,0);
     lcd.setCursor(0,1);
     lcd.print("Manual Mode");  
     lcd.setCursor(12,1);
    }
   }
}

void manualReEntryPoint() 
{
    Serial.print("manualReEntryPoint");
    lcd.setCursor(12,1);
    lcd.print("      ");
    inputDigitCount = 0;
    Value = 0;
    lcd.setCursor(12,1);
}

void tooManyDigits()
{
  Serial.println("Only 4 digits are allowed   ");
  lcd.setCursor(0,0);
  lcd.print("                ");
  lcd.setCursor(0,1);  
  lcd.print("            ");
  lcd.setCursor(0,1);
  lcd.print("Manual Mode");  
  lcd.setCursor(0,0);
  lcd.print("Only 4 digits   ");
  delay(1000);
  lcd.setCursor(0,0);
  lcd.print("                ");
  lcd.setCursor(0,0);  
  lcd.print("Pick < or >  Bk*");  
}

void moveToNextStation(int stepsToNextStation, int DIR)
{
//This will be removed when incorporated into bigger program.
}

void goLeft() 
{
    Serial.print(Value);
    Serial.println( (direction ? "<": ">"));
    lcd.setCursor(12,1);
    lcd.print("      ");
    inputDigitCount = 0;
    Value = 0;
    lcd.setCursor(12,1);
//>>    moveToNextStation(stepsToNextStation, DIR);
}

void goRight()    
{
    Serial.print(Value);
    Serial.println( (direction ? "<": ">"));
    lcd.setCursor(12,1);
    lcd.print("      ");
    inputDigitCount = 0;
    Value = 0;
    lcd.setCursor(12,1);
//>>    moveToNextStation(stepsToNextStation, DIR);
}
    while ()

while needs a condition. Re-read lar3ry's code.

PaulS:

    while ()

while needs a condition. Re-read lar3ry's code.

Rats! My code DOES read while ().

Asa, use while (1) { on that line.

Rats! My code DOES read while ().

Hmmm. That's the problem with reading code early in the morning, while my contacts are still fuzzy. I was sure that there was a 1 in the parentheses.

PaulS:

Rats! My code DOES read while ().

Hmmm. That's the problem with reading code early in the morning, while my contacts are still fuzzy. I was sure that there was a 1 in the parentheses.

No worse than me, writing it while suffering from a passing kidney stone, and too distracted to actually test the code.

Just for clarification, Asa, that while will loop until either a '1' or a '2' is received from the keypad, at which time it will execute the break;, causing it to drop out of the while loop, and into the if statements.

It wouldn't compile. It said the key2 was not declared so I added it as a variable a the top and then it worked great!
....
.........
but now......
How do I do one level lower?
I tried to go with key3 and 4 but that didn't work.

Also, how does

Value = Value * 10 + (in - '0');
void show() {
Serial.print(Value);
Serial.println( (direction ? "CW": "CCW"));
Value = 0;

give me i.e. 1234> ? If I want to send 1234 as one argument and > as another, I could parse it out but I'm sure that it is easier than that. Yes?

Here’s a more generalized routine for gathering numbers, followed by a special character. I ised Serial here, but the technique is the same for keypad input.

int amount;

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

void loop() {
  if (Serial.available()) {
    int ch = Serial.read();
    if (ch >= '0' && ch <= '9') {
      amount = (amount * 10) + Serial.read() - '0';
    }
    else {
      switch (ch) {
      case '#':
        do_stuff1();
        break;
      case '*':
        //do_stuff2
        break;
      case '<':
        // do_stuff3
        break;
      case '>':
        // do_stuff4
        break;
        default:
          ///do_stuff5
        break;
      }
    }
  }
}

void do_stuff1() {
 // put stuff 1 here 
}

I meant going one level lower like this:

int amount;

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

void loop() {
//Set up LED to ask question 1
if (Serial.available()) {
int ch = Serial.read();
if (ch >= ‘0’ && ch <= ‘9’) {
amount = (amount * 10) + Serial.read() - ‘0’;
}
else {
switch (ch) {
case ‘#’:
AskAnotherQuestion1();
break;
case ‘*’:
//do_stuff2
break;
case ‘<’:
// do_stuff3
break;
case ‘>’:
// do_stuff4
break;
default:
///do_stuff5
break;
}
}
}
}

AskAnotherQuestion1() {
// PutOnLED Question 2:
// Option 1 or 2 ?
// If (1) {
// now do something
// }
// else if (2) {
// maybeGoHereToDoSomethingElse()
// }
}

}