Issue in collecting keypad input into a char Array

Hi forum,,

I want to
1-collect 12 digits using a keypad
2-and then saving those 12 digits into a variable (long long variable)
3-and then display this on lcd for confirmation
all of this using a function

and then save it for a use in another function.

So, i just set this long long variable (call it IC) as a global variable and used external function to print the variable on the lcd so that the value doesn't get destroyed.
My question is: Was that right ? Am i actually saving the IC to be used in another function like that?

Now the problem i am facing is: I tried to use a button to move from the first function to the other but apparently i'm stuck in the first one and the button is not doing the goal.

Here is my code:

#include <SoftwareSerial.h>
#include <String.h>
#include <LiquidCrystal.h>
#include <Keypad.h>
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte rowPins[ROWS] = {9, 8, 7, 6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5, 4, 3}; //connect to the column pinouts of the keypad
Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
LiquidCrystal lcd(A0, A1, A2, A3, A4, A5); //connecting the lcd





int buttonOne = 2;              //connected to pin 2
long long IC = 0;               // the number accumulator
uint8_t state ;
int buttonOnestate;
uint8_t smallstate;
const uint8_t toTakeID = 0; //state 1 (to collect the 12 digits into IC variable)
const uint8_t correct = 1;//state 2 (i will use the 12 digits here)





void setup() {
  smallstate = toTakeID;
  lcd.begin(20, 4);
  lcd.setCursor(0, 0);
  Serial.begin(9600);
  pinMode(buttonOne, INPUT);//in real life must be INPUT_PULLUP and connect it to the arduino ground but i'm using potreus to simulate now
}





void loop() {
// state machine
  if ( smallstate == toTakeID )
  {
    long keyvalue;                              // the key pressed at current moment
    int isnum;
    do
    {
      keyvalue = kpd.getKey();                              // input the key
      isnum = (keyvalue >= '0' && keyvalue <= '9');        // is it a digit?
      if (isnum)                                          // if it is a digit then do this
      {
        lcd.print(keyvalue - '0');
        IC = (IC * 10) + keyvalue - '0';               // accumulate the input number
      }
    } while (isnum || !keyvalue);                    // until not a digit or while no key pressed
    // Print the string from the buffer.
    Serial.print("The value is:");
    printLL(IC); //using this function because long long is too much for print and println
    lcd.clear();
    lcd.print("The value is:       ");
    LCDPrintLL(IC);//using this function because long long is too much for print and println
    return IC; //i will need the IC value for later use
    buttonOnestate = digitalRead(buttonOne);
    if (buttonOnestate == HIGH) { //here i want to go to the next state by using the button
      smallstate = correct;
    }
  }
  if ( smallstate == correct ) //the next function
  { 
    lcd.clear();
    lcd.print("HI correct"); //just example, my application will involve using the IC here
  }


}


//in another topic i was advised to use this function to print since 
//it will distroy the value if it is used directly 
void printLL(long long val) {
  char digits[22];
  int index = 21;
  digits[index--] = '\0'; // Null terminator
  // Take the rightmost digit, even if it's 0;
  digits[index--] = (val % 10) + '0';
  val /= 10;
  // Take all the remaining digits
  while (val != 0) {
    digits[index--] = (val % 10) + '0';
    val /= 10;
  }
  // Print the string from the buffer.
  Serial.print(&digits[index + 1]);
}


//in another topic i was advised to use this function to print since 
//it will distroy the value if it is used directly 
void LCDPrintLL(long long val) {
  char digits[22];
  int index = 21;
  digits[index--] = '\0'; // Null terminator

  // Take the rightmost digit, even if it's 0;
  digits[index--] = (val % 10) + '0';
  val /= 10;

  // Take all the remaining digits
  while (val != 0) {
    digits[index--] = (val % 10) + '0';
    val /= 10;
  }
  // Print the string from the buffer.
  lcd.print(&digits[index + 1]);
}
1 Like

Before I look too deeply at this, I'll point out that using a long long ( int64_t ) is an unusual way of collecting keyboard input. I'd simply collect it in a character buffer or byte array. Anyway, assuming you collect it successfully, what are you going to do with it ?

typically, you should display the keypresses as they are being made as feedback that the keypress is recognized. typically this means collecting the keypresses in a byte array, possibly translating each byte to an ASCII char and re-displaying the entire array after each keypress. presumably the '#' key may indicate the entry is complete.

the array is then translated into a int or long value by translating back from ascii to binary and accumulating a value

val += 10*val + keypress [i] - '0';
1 Like

I used long long because i want to collect 12 digits and even more.
I will use HTTP POST request and send this number together with a sensor value to a database.
Do you think it would be better to use other than long long to collect it? And let's say i used char, the function of collection would still be the same?

You have to anyway send character data if you are sending it via HTTP POST so leave it as character data.

alright noted, i will try to make it as character

what about the other problem i'm facing? i cannot move to the other state using the button.

Well, smallstate is going to change from toTakeID to correct when the button is pressed (assuming the button is wired on the low side). However, it will never change back to toTakeID

Is that how you want it, or have I missed something ?

Yes tha't how i want it.
and later when the whole application is done i will use another button or maybe the same one to go back to toTakeID.

What do you mean by this? i wired the button to pin 2 in arduino UNO.

You have a return statement right before you try to read the button. Nothing after a return statement will ever get executed since a return statement exits the current function which is loop()

    LCDPrintLL(IC);//using this function because long long is too much for print and println
    return IC; //i will need the IC value for later use
    buttonOnestate = digitalRead(buttonOne);

It appears you do not need that return statement there since you are not fetching your digits in a separate function.

and if you wired the other pin of the button to ground, then that is LOW side.
Had you wired the other pin to +5v, instead of ground, that would be HIGH side.

Well i'm simulating the project on proteus now so i wired one pin to the the arduino's pin2 and the other to a power source since the arduino i have in proteus doesn't have the ground pin (accourding to a youtube tutorial i saw on how to simulate button with arduino in proteus and they treated the button as if it was connected to LOW side).
I will follow the way you explained when i finally apply my project on the physical components.

I figured out why i was stuck and never leaving the state of collecting numbers

it is because of this caode

specifically the (!keyvalue)....
this means that as long as (while) we are not pressing anything in the keypad the code is stuck at the (do) taking numbers.
The thing is, i really need to keep this condition or else the code is not gonna stay still asking for numbers input and it will jump to the next thing which is displaying "The value is:"

Do anyone have an idea how to deal with this?
I know where my problem is but i cannot come to a solution.

For the long long problem, i'm still doing my research on how to collect to a character buffer.

You need to read this: several things at the same time
And then refactor your code such that you

  1. check for a key press
  2. if yes, process it.
  3. Is it the the last digit or '*' to indicate done? then set a flag
  4. only display the final value if your 'done' flag is set
1 Like

since i will be treating the input as a text i used a string to store the values and it worked.

#include <SoftwareSerial.h>
#include <String.h>
#include <LiquidCrystal.h>
#include <Keypad.h>
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte rowPins[ROWS] = {9, 8, 7, 6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5, 4, 3}; //connect to the column pinouts of the keypad
Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
LiquidCrystal lcd(A0, A1, A2, A3, A4, A5); //connecting the lcd



int buttonOne = 2;              //connected to pin 2
int buttonOnestate;
uint8_t smallstate;
const uint8_t toTakeID = 0; //state 1 (to collect the 12 ot more digits into inputString)
const uint8_t correct = 1;//state 2 (i will use the 12 digits here)

String inputString;
char inputInt;


void setup() {
  smallstate = toTakeID;
  lcd.begin(20, 4);
  lcd.setCursor(0, 0);
  Serial.begin(9600);
  pinMode(buttonOne, INPUT);//in real life must be INPUT_PULLUP and connect it to the arduino ground but i'm using potreus to simulate now
}





void loop() {
  if ( smallstate == toTakeID )
  {
   // lcd.print("Please Enter ID");
    char key = kpd.getKey();
    if (key) {
      Serial.println(key);
      lcd.print(key);
      if (key >= '0' && key <= '9') {     // only act on numeric keys
        inputString += key;               // append new character to input string
      } else if (key == '#') {
        if (inputString.length() > 0) {
          Serial.println("the ID is:  ");
          Serial.println(inputString);
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("The ID is:   ");
          lcd.setCursor(0, 1);
          lcd.print(inputString);
        }
      } else if (key == '*') {
        inputString = "";                 // clear input
        lcd.clear();
      }
    }

    buttonOnestate = digitalRead(buttonOne);
    if (buttonOnestate == HIGH) { //here i want to go to the next state by using the button
     lcd.clear();
      smallstate = correct;
    }

  }


  if ( smallstate == correct ) //the next function
  {
   
    lcd.setCursor(0, 0);
    lcd.print("HI correct"); //just example, my application will involve using the inputInt here
    lcd.print(inputString);
  }


}
1 Like

Thank you for posting your finished code so others can learn too