inputting with keypad, displaying and showing result of function

Hi, so I'm new to coding and was wondering if I could get some help. This is what I would like my code to do:

  1. display numbers input from keypad.
  2. when '#' is pressed, send the number/numbers entered into a function.
  3. return a result from the function.
  4. display the result.

I had it clear and start over if the number of digits entered went over 7, but after changing the code, it doesn't do that anymore. I tried working backwards, but I couldn't fix it. Also I'm not sure how send the entered numbers to the function.

I feel like there is a lot that I'm doing wrong with the code.

I would appreciate it if I could get some help with this!
Thank you!

Here is what I have so far.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>

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

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

LiquidCrystal_I2C lcd(0x27, 16, 2);
int key = keypad.getKey();

void setup()
{
  lcd.begin();
  // Turn on the blacklight and print a message.
  lcd.backlight();
  lcd.print("Enter Number!");
  lcd.setCursor(0, 1);
  lcd.print("Number= ");
}

void loop()
{
  static char userinput [7];
  static int count = 0;
  float add;
  char key = keypad.getKey();
  if (key != NO_KEY)
  {
    lcd.print(key);
    count++;
    if (count >= 7)
    {
      lcd.clear();
      lcd.print("Enter Number!");
      lcd.setCursor(0, 1);
      lcd.print("Number= ");
      count = 0;
    }
    if (key == '*')
    {
      lcd.clear();
      lcd.print("Enter Number!");
      lcd.setCursor(0, 1);
      lcd.print("Number= ");
      count = 0;
     }
     if (key == 'A')
    {
       lcd.clear();
       lcd.print("Enter Number!");
       lcd.setCursor(0, 1);
       lcd.print("Number= ");
      count = 0;
     }
     if (key == 'B')
    {
       lcd.clear();
       lcd.print("Enter Number!");
       lcd.setCursor(0, 1);
       lcd.print("Number= ");
      count = 0;
     }
     if (key == 'C')
    {
       lcd.clear();
       lcd.print("Enter Number!");
       lcd.setCursor(0, 1);
       lcd.print("Number= ");
      count = 0;
     }
     if (key == 'D')
    {
       lcd.clear();
       lcd.print("Enter Number!");
       lcd.setCursor(0, 1);
       lcd.print("Number= ");
      count = 0;
     }
     if (count < 7)
    {
      userinput [count++] = key;
    }
    if (key == '#')
     {
      memset (userinput, 0, sizeof(userinput));
    lcd. print(add);
    }
  }
}
float calc(int, int key)
{
  float result;
  result = 31 + key;
  return result;
}

input.ino (2.14 KB)

  1. display numbers input from keypad.

The decoration on the face of the key might look like a number, but the code says that when a key is pressed, return a character. You must turn the character into a number.

Your current code is abominable. You have SO much duplicate code. There is NO reason to clear the LCD every time a key is pressed.

    if (key == '#')
     {
      memset (userinput, 0, sizeof(userinput));
    lcd. print(add);
    }

If the # key is pressed, sh*t on the stored data, then use the stored data. I do believe that reversing the order of operations would be beneficial.

Of course, add is never assigned a value, so printing it is useless.

float calc(int, int key)

Anonymous arguments are useless.

I had it clear and start over if the number of digits entered went over 7, but after changing the code, it doesn't do that anymore.

Instead, it now does the hokey pokey? Help us out here. Describe what the code ACTUALLY does.

I tried working backwards, but I couldn't fix it.

You should have tried blindfolded and standing on one leg. That statement is just a bunch of correctly spelled words strung together. They convey NO information.

Your array of keys doesn't include a decimal point, so the type of add, float, and the type of the function you never call, float, doesn't make any sense.

All you can enter is integers.

Every time you add a character to the userinput array, also add a NULL in the next position (without incrementing the index). Then, when the '*' is pressed, call atoi() with the userinput array, to get a integer value.

You must turn the character into a number.

Okay, I'll do that. Thank you.

Your current code is abominable

Yea, sorry....I did say that I was new to coding. Also tried looking example programs and ones online that I thought I could use, so I combined and changed it a bit. I'm still learning. So please bare with me.

There is NO reason to clear the LCD every time a key is pressed.

I just didn't want A,B,C,D,* to do anything so that's why I made them clear everything and start over.

    if (key == '#')
     {
      memset (sizeof(userinput), 0, userinput);
    lcd. print(add);
    }

Is this a bit better?

Of course, add is never assigned a value, so printing it is useless.

I was thinking that the float calc needs to be called before I get a value for add right?

Anonymous arguments are useless.

Sorry, I don't really understand what you mean by this. Is it because it isn't called?

Describe what the code ACTUALLY does.

So, the current code only displays the numbers up to 3 digits or clears the numbers.

They convey NO information.

Sorry, I meant that I was able to make it clear itself when the 8th digit was pressed, but then I changed something and it cleared at 3 digits. I tried undoing the things I did, but it still cleared at the 4th digit.

Your array of keys doesn't include a decimal point, so the type of add, float, and the type of the function you never call, float, doesn't make any sense.

I'm sorry, I'll read up on arrays now. :frowning: I didn't understand what you meant.... Should I just stop what i'm doing and get a grasp of what everything does or how to use it.... :frowning:

All you can enter is integers.

Yea, this is all I can do.

Every time you add a character to the userinput array, also add a NULL in the next position (without incrementing the index). Then, when the '*' is pressed, call atoi() with the userinput array, to get a integer value.

Honestly, I don't understand, but I'll read up on everything I don't understand and hopefully I'll doing something right.

Thanks for taking your time and helping me. If you think I should just start from the basics and stop what I'm trying to do then I'll consider doing that. I know this is a forum and not somewhere to really learn the basics from. I just over estimated my code. :frowning:

So please bare with me.

I'll bear with you while you take your clothes off. I'll be keeping mine on.

Is this a bit better?

Looks the same do-nothing code you had before.

Sorry, I don't really understand what you mean by this.

In a function prototype, you can just say that a function has three arguments, for instance, and that the types are int, int, and float.

In a function definition, you actually have to give the arguments names, or you can't use the value passed in.

So, the current code only displays the numbers up to 3 digits or clears the numbers.

When you do what? Take your clothes off and do the hokey pokey? You need to say what YOU do, too.

Get the keypad off of pin 1 so you can use Serial to debug your program. That is orders of magnitude easier than trying to use an LCD to debug it.

Honestly, I don't understand, but I'll read up on everything I don't understand and hopefully I'll doing something right.

   char key = keypad.getKey();
   if(key != NO_KEY)
   {
      userinput[count++] = key; // Store the key in the next position AND increment the index
      userinput[count] = '\0'; // Store a NULL in the next position but do NOT increment the index
   }

This way, userinput is a string, and you can Serial.print(userinput) to see what it contains. You can also call atoi() on it, to get an integer.

I didn't understand what you meant.... Should I just stop what i'm doing and get a grasp of what everything does or how to use it...

NO. Keep studying, yes. Keep asking questions. Keep trying. You are probably closer than you think.

I'll do the hokey pokey only if you bare with me.

Get the keypad off of pin 1 so you can use Serial to debug your program. That is orders of magnitude easier than trying to use an LCD to debug it.

so I wasn't sure what to do after unplugging the pin. do I have to change everything from lcd to serial in the code? In the end, I just left it so I could see what's going on....

You need to say what YOU do, too.

So after messing with the code, while pressing numbers on the keypad the numbers would show, but it only goes up to 3 digits and then clears. I wrote the code to clear at 7 digits, so I'm assuming I did something wrong. Also, when I press # it prints out 350.00. Also for some reason the 3rd row on the keypad doesn't seen to do anything when I press on the keys and the other numbers show 49, 50, and so on. The star key works like I put in the code though.

 if (key != NO_KEY)
  {
    userinput[count++] = key; // Store the key in the next position AND increment the index
      userinput[count] = '\0'; // Store a NULL in the next position but do NOT increment the index
    lcd.print(key);
    count++;
    if (count >= 7)

I'm not sure if I added that in the right spot of the code, but I added it. I also made a few changes. I put this above the earlier part you told me to add to the code.

 int num;
  static char userinput [7];
  static int count = 0;
  float add;
  num = atoi(userinput);

I change the function.

float calc(int num)
{
  int add = 31 + num;
  return add;
}

I'm not sure if this is better than the "same do-nothing code", but I'm add the function calc hoping it would do something, but it doesn't do what I thought it'd do.

if (key == '#')
     {
      memset (userinput, 0, sizeof(userinput));
      calc (key);
    lcd.print(add);
    }

Am I making progress? It's still not working how I want it to and I'm making changes, not really knowing if it changed anything.

if (key != NO_KEY)
  {
    userinput[count++] = key; // Store the key in the next position AND increment the index
      userinput[count] = '\0'; // Store a NULL in the next position but do NOT increment the index
    key = (key - '0');
    lcd.print(key);
    count++;

I found how to get the numbers I want to see using that. However, my A,B,C,D sends back 17,18,19,20 and my * and # gives me -6,-13. I think it's because I changed key into int and since I set key -'0', it gives me the decimal value - 48. I'm not sure how to go about making it so A,B,C,D,* AND # show as characters.

Also, I can't get # to work how I want it to. I feel that once i figure out how to fix the above problem, the # should work.

Look at http://www.asciitable.com/
You may have to use a lookup table to determine what to print when key is <48 or more than 57.

@CrossRoads

Thanks, that's what I looked at to figure out key-'0'. That's also where I found out why A,B,C,D,* and # are giving me the numbers. Example: A=65, 0=48 so 65-48=17. and that's what I get for A.

What I would like to find out is how to get the characters A,B,C,D,* and # instead.

Also, I used this site ASCII Table I'm not sure why, but the site you posted didn't work.

Could always brute force it:

if (key == 65){lcd.print('A');
if (key == 66){lcd.print('B');
if (key == 67){lcd.print('C');
if (key == 68){lcd.print('D');
if (key == 42){lcd.print('*');
if (key == 35){lcd.print('#');

@CrossRoads

hmmmm I'll try that and maybe change my if statements to work with those numbers instead of the characters. Or is there a better way to do it?

@CrossRoads

So, I thought about what you said to do and I ended up switching my if statements that used the characters with it's corresponding number from key - '0'.

Now my problem is trying to run a function when '#' on the keypad or -13 in the code is pressed.

 if (key == -13)
     {
      calc (num);
    lcd.print(add);
    }

this is the function I have on it.

int calc(int num)
{
  int add = 31 + num;
  return add;
}

I get the error 'calc' cannot be used as afunction

Might be a syntax problem. Can you post the whole code you have now?

yup

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>

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

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

LiquidCrystal_I2C lcd(0x27, 16, 2);
int key = keypad.getKey();

void setup()
{
  lcd.begin();
  // Turn on the blacklight and print a message.
  lcd.backlight();
  lcd.print("Enter Number!");
  lcd.setCursor(0, 1);
  lcd.print("Number= ");
}

void loop()
{
  int num;
  static char userinput [7];
  static int count = 0;
  int calc;
  int add;
  int key = keypad.getKey();
  num = atoi(userinput);
  if (key != NO_KEY)
  {
    userinput[count++] = key; // Store the key in the next position AND increment the index
      userinput[count] = '\0'; // Store a NULL in the next position but do NOT increment the index
    key = (key - '0');
    lcd.print(key);
    count++;
    if (count >= 7)
    {
      lcd.clear();
      lcd.print("Enter Number!");
      lcd.setCursor(0, 1);
      lcd.print("Number= ");
      count = 0;
    } 
    if (key == -13)
     {
      calc (num);
    lcd.print(add);
    }
    if (key == -6)
    {
      lcd.clear();
      lcd.print("Enter Number!");
      lcd.setCursor(0, 1);
      lcd.print("Number= ");
      count = 0;
     }
     if (key == 17)
    {
       lcd.clear();
       lcd.print("Enter Number!");
       lcd.setCursor(0, 1);
       lcd.print("Number= ");
      count = 0;
     }
     if (key == 18)
    {
       lcd.clear();
       lcd.print("Enter Number!");
       lcd.setCursor(0, 1);
       lcd.print("Number= ");
      count = 0;
     }
     if (key == 19)
    {
       lcd.clear();
       lcd.print("Enter Number!");
       lcd.setCursor(0, 1);
       lcd.print("Number= ");
      count = 0;
     }
     if (key == 20)
    {
       lcd.clear();
       lcd.print("Enter Number!");
       lcd.setCursor(0, 1);
       lcd.print("Number= ");
      count = 0;
     }
  }
}
int calc(int num)
{
  int add = 31 + num;
  return add;
}

The variable "add" doesn't exist outside the calc() function so you can't print it in loop(). And the variable "num" only exists as a parameter to calc() so you can't pass it in from the main program (where it doesn't exist).

Steve

Ok, so I put add as a global variable, but what do I do with num then? I don't understand what you meant for num.

The way I think of what I did was to set num to equal the userinput, which is an array of key. Then I'm calling num to be used in calc. i'm kinda confused.....

You need to read up on how functions are defined and used because what you understand isn't what happens. Try Arduino Playground - Function Tutorial

But since there's only one useful line of code in that function and you only call it once I can't really see why you need a function in the first place.

Steve

Looks like a good opportunity to learn the switch/case statement. It's a shortcut for when you want to compare one integer (in your case, 'key') against a bunch of integer constants. It's neater than a pile of separate 'if' statements.

void loop()
{
  static unsigned long value = 0;  // Need room for 7 digits (9,999,999)
  static int count = 0;


  char key = keypad.getKey();
  switch (key) {
    case NO_KEY:  // No input, do nothing
      break;


    case '0'...'9':
      // A digit
      count++;
      value *= 10;
      value += (key - '0');
      if (count <= 7)
        break;  // If too many characters, drop through to treat as invalid input


    case '*':
    case 'A' ... 'D':
      // Invalid inputs.  Clear the buffer and re-prompt
      lcd.clear();
      lcd.print("Enter Number!");
      lcd.setCursor(0, 1);
      lcd.print("Number= ");
      value = 0;
      count = 0;
      break;


    case '#':
      // ENTER character
      lcd.print(value);  // Display the accumulated value
      value = 0;
      count = 0;
      break;


  } // End Switch
}

@slipstick

I read the link you sent me, I'm still kinda lost on what you meant. I understand what a function needs and how to set it from reading the link you sent me. I guess what I don't understand is why num won't be sent to it. I thought that if i made it something in the main program, it would save it and send it to the function to compute.

Also, I making it a function because I'm learning to incorporate functions to code. After understanding how to do this, I am aiming to do another program that will need a function.....at least, I think it would. It's also part of learning for me.

@johnwasser

Thanks for letting me know. I actually tried to make a switch/case version since I came across it while trying to figure things out for my program. The problem that came to my mind was that because I change key to int, A - D and * and # were numbers instead. I'm not sure if that is a problem or not, but I was worried it wouldn't work, so I stuck with if statements.

I change key to int because PaulS said I must turn the character into a number..... Now thinking about it, maybe change the key from char to int isn't what I was suppose to do....

Also, Do you mind explaining what at the end, you wrote value = 0? is it to rest it?

Thank you everyone for helping me with my coding problems. Trying my best to learn and make this code work correctly.

AphroWill:
@slipstick

I read the link you sent me, I'm still kinda lost on what you meant. I understand what a function needs and how to set it from reading the link you sent me. I guess what I don't understand is why num won't be sent to it. I thought that if i made it something in the main program, it would save it and send it to the function to compute.

Also, I making it a function because I'm learning to incorporate functions to code. After understanding how to do this, I am aiming to do another program that will need a function.....at least, I think it would. It's also part of learning for me.

Wanting to learn is a good enough reason. But with functions I think what you have missed is that the names of the parameters, i.e. the stuff in parentheses in the function definition, and return values are only used INSIDE the function. The actual value that you pass in can be any variable of the correct type. So if you define your function:

int calc (int num)
{
do stuff with num
return add;
}

when you call it in the main program loop() you call it as something like

int x;
int y;
int result1;
int result2;

loop()
{
// do stuff then
result1 = calc(x);
// perhaps do some more then
result2 = calc(y);
//
}

The point of having a function is that you can call it lots of times passing it different parameters and getting different results from it. Inside your calc() function the first time you call it "num" has the value of "x" and the second time you call it "num" has the value of "y". And the thing you return which you call "add" is put into "result1" the first time you call the function and into "result2" the second time.

Does that help or just confuse you more?

Steve

AphroWill:
The problem that came to my mind was that because I change key to int, A - D and * and # were numbers instead. I'm not sure if that is a problem or not, but I was worried it wouldn't work, so I stuck with if statements.

The type "char" is just another kind of integer. On an 8-bit Arduino it means "signed, 8-bit integer" just like "int" means "signed, 16-bit integer". They display differently in .print() because 'char' types are shown as a single character and 'int' types are shown as the numeric value of the integer.

The .getKey() function returns a 'char' so 'char' is the most appropriate type for 'key'.

If you want to display the numeric value for 'key' (or any 'char' variable) you can use a 'cast' operation:

    Serial.print((int)key);  // Traditional C syntax
    Serial.print(int(key));  // Alternative syntax

The cast tells the compiler to convert the value to a different type before using it so the .print() function for 'int' is called instead of the .print() function for 'char'.

The 'switch/case' statement works on integers of any size. The character constants: 'A', 'B', '#' (note the 'single quotes') all represent numbers (ASCII character codes). You can compare them to other integers of any size: char, int, long int.

AphroWill:
Also, Do you mind explaining what at the end, you wrote value = 0? is it to rest it?

Yes, it was to reset it after displaying the value. Naturally you would put whatever code that acted on the value BEFORE reseting the value. :slight_smile: