Help with menu display 16x2 keypad 4x4

Hello, I’m designing a wire cutting machine, where the operator inserts the size value and the amount of wire count to be cut. The motor will rotate T seconds to pull the wire and then actuate the guillotine to cut the wire.

I’m at the beginning of the program, with a menu problem that I can not solve at all.

My problem is when I enter the values, the arduino throws a “0” in the field, and I have to press many times for a number to be inserted, making it unfeasible.

Can you help me? Or some simpler way, even without a menu, but you can type a number of digits and store in a variable to control the engine time in the future.

Below my code:

int first = 0;
int second = 0;
int caso = 0;
int z = 0;
int i = 0;
int j= 0;
int y= 0;


#include <Keypad.h>
#include <LiquidCrystal.h>//display library

LiquidCrystal lcd(8, 9, 7, 6, 5, 4);

const byte ROWS = 4;
const byte COLS = 4;
// Define o Keypad (circuit map)
char keys[ROWS][COLS] =
{
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

byte rowPins[ROWS] = { 31, 33, 35, 37 };
byte colPins[COLS] = { 39, 41, 43, 45 };

Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); // Objeto do keypad

char tecla = kpd.getKey(); //Variable to get the key pressed

void setup() {
  lcd.begin(16, 2); //Begin the LCD 16x2
}
void loop()
{
  char tecla = kpd.getKey();
  z=0;
  if (tecla) // Menu initially white
    {
     switch (tecla)
     {
      case 'A':
      lcd.clear();
      lcd.setCursor (0,0);
      lcd.print ("TAMANHO [B]"); //Shows in the menu that pressing B goes to the size menu
      lcd.setCursor (0,1);
      lcd.print ("QUANTIDADE [C]"); //Shows in the menu that pressing C goes to the quantify menu
      menu();
      break;      
     }
    }
}
//=============================================

void menu() //void dos menus
{
  while (z<1) // Variable to run function IF
  {
    char tecla = kpd.getKey();
    delay (100);

    if (tecla == 'B') // If press B goes to size menu
    {
      lcd.clear();
      lcd.setCursor (0,0);
      lcd.print ("INSIRA O TAMANHO");    
      lcd.setCursor (0,1);
      tamanho();

      }    

      if (tecla == 'C') // If press C goes to quantify menu
      {
       lcd.clear();
       lcd.setCursor (0,0);
       lcd.print ("INSIRA A QTDE");
       qtde();

      }

  }
}
//========================================

void tamanho () // loop of size
{
  while (q<1)
  {
  char tecla = kpd.getKey();
  valort();
  lcd.setCursor (0,1);
  lcd.print(first); // here there are my problem

  }
 }

//IGNORE above code, just testing !
void qtde ()
{
  char tecla = kpd.getKey();
  valorq();
  lcd.setCursor (0,1);
  lcd.print(second); 
}

//=====================================

void valort() //void of size value
{
  for (i=0; i<=4; i++){
  char tecla = kpd.getKey();
  switch (tecla)
  {
    case '0' ... '9':
    lcd.setCursor (0,1);
    first = first * 10 + (tecla - '0'); // function to accumulate numbers, like (example : 142)
  }
  }
}


//ignore above code, just testing
void valorq()
{
  char tecla = kpd.getKey();
  switch (tecla)
  {
    case '0' ... '9':
    lcd.setCursor (0,1);
    second = second * 10 + (tecla - '0');

  }
}
char tecla = kpd.getKey(); //Variable to get the key pressed

Unless you are pressing a key when the Arduino boots up, tecla will contain NO_KEY.

void loop()
{
  char tecla = kpd.getKey();

Then, you create another variable with the same name as the global variable. That is just too confusing to deal with. Stop doing that.

It almost seems as though you expect getKey() to wait for a key to be pressed. It does not.

I just follow this example :

and he use too the same variable =(

What you can recommend for do so?

Guys, im not using pull down resistor, maybe this the problem?

luhocruz:
Guys, im not using pull down resistor, maybe this the problem?

Not using it for what? keypads don't need pullup, pulldown, or pullsideways resistors.

You do need to fix your code so it is readable and does NOT duplicate variable names.

You also need to define more clearly what the problem is. Are you expecting that every time you call getKey() that you will get a key? If so, that is not a reasonable expectation. If so, you should be using waitForKey().

So you mean that for every time I to run a command over the keyboard has to be a different variable?

My problem is the time to enter the value of the size of the wire to be cut, I often press whatever number and get delay to appears on the display, as if it were overloaded, and I can not leave the menu after I enter it, I am very lazy in menus, I created this one step by step, so I believe there are many mistakes still, I will try to record a video to improve it explains, thanks for the time Paul, I need to finish this for my company before Christmas and I’m desperate.

I think the same thing every time I see a newbie asking for programming advice on an "industrial" project --- please make sure your setup is such that nobody will get hurt if your code fcks up. Or, more likely, you fck up the code. Basing your design on something you saw in a youtube video is not going to impress OSHA in the least.

I am in the fifth year of mechatronics engineering, the director of the company where I work as a mechanical engineer, he is with me, I work with electronics for 5 years, I am entering programming now, you can rest assured nobody will get hurt because the project I am only having a doubt in the program, not in it, but in a specific part, because everything else is working, I do not think I'm that stupid, because I just got the Example of YouTube and I wrote my own program, I accept constructive criticism, now criticism that will not heal my doubt, which at the same time may be the doubt of another I do not accept, thank you! Thanks for Paul being patiently helping me so far.

This is one of your problematic functions, I think. @PaulS already pointed it out

PaulS:
It almost seems as though you expect getKey() to wait for a key to be pressed. It does not.

Your code

void valort() //void of size value
{
  for (i = 0; i <= 4; i++)
  {
    char tecla = kpd.getKey();
    switch (tecla)
    {
      case '0' ... '9':
        lcd.setCursor (0, 1);
        first = first * 10 + (tecla - '0'); // function to accumulate numbers, like (example : 142)
    }
  }
}

If no key is pressed, the for-loop still counts 0, 1, 2, 3 and we’re done. Your ‘case’ is also not correct (as far as I know).

The below will do what you want

void valort() //void of size value
{
  int counter = 0;

  do
  {
    /// read key from keypad
    char tecla = kpd.getKey();
    // if value between '0' and '9' (both included)
    if(tecla >= '0' && tecla <= '9')
    {
      first = first * 10 + (tecla - '0'); // function to accumulate numbers, like (example : 142)
      counter++;
    }
  } while (counter < 4);
}

There is probably a lot of improvement possible in your code; e.g. you might want to reset the variable first when calling valort().
You might also want to give the user a chance to correct errors (e.g. using the ‘*’) and to submit the entry (e.g. using ‘#’); you might also want to give feedback on the lcd while the user is entering data.

You should get rid of single character variable names, especially when they are global (there are e.g. 86 occurrences if the character ‘i’ in your code only 4 of them refer to the variable :slight_smile: Trying to find that variable in your code. Also, ‘i’ is only used in the for-loop in valort(); no reason to make it global.

luhocruz:
So you mean that for every time I to run a command over the keyboard has to be a different variable?

...snip...

No, use one variable. Define it just once.

So you mean that for every time I to run a command over the keyboard has to be a different variable?

I really have no idea how you think you can "run a command over the keyboard". So, your question is like asking how to paint an elephant. First, you get the elephant to hold still...

sterretje:
This is one of your problematic functions, I think. @PaulS already pointed it out
Your code

void valort() //void of size value

{
  for (i = 0; i <= 4; i++)
  {
    char tecla = kpd.getKey();
    switch (tecla)
    {
      case ‘0’ … ‘9’:
        lcd.setCursor (0, 1);
        first = first * 10 + (tecla - ‘0’); // function to accumulate numbers, like (example : 142)
    }
  }
}



If no key is pressed, the for-loop still counts 0, 1, 2, 3 and we're done. Your 'case' is also not correct (as far as I know).

The below will do what you want


void valort() //void of size value
{
  int counter = 0;

do
  {
    /// read key from keypad
    char tecla = kpd.getKey();
    // if value between ‘0’ and ‘9’ (both included)
    if(tecla >= ‘0’ && tecla <= ‘9’)
    {
      first = first * 10 + (tecla - ‘0’); // function to accumulate numbers, like (example : 142)
      counter++;
    }
  } while (counter < 4);
}




There is probably a lot of improvement possible in your code; e.g. you might want to reset the variable *first* when calling valort().
You might also want to give the user a chance to correct errors (e.g. using the '*') and to submit the entry (e.g. using '#'); you might also want to give feedback on the lcd while the user is entering data.

You should get rid of single character variable names, especially when they are global (there are e.g. 86 occurrences if the character 'i' in your code only 4 of them refer to the variable :) Trying to find that variable in your code. Also, 'i' is only used in the for-loop in valort(); no reason to make it global.

I did this, and I put a Serial.println in the counter, and it stays in 0, and it does not limit the number of digits, the counter is not counting, I do not know why. What you mentioned was exactly what I would like to do, have a specific key for the “enter” as you said, using the “*” and a “#” reset key, but I think it is very complex for me, I am sad. And I know it’s not impossible, but nothing works = (

but I think it is very complex for me

If you won’t make the effort to use meaningful names, and limit their scope, it will never get easier.

If you can not clearly state your requirements, or expectations, it will never get any easier.

PaulS:
If you won’t make the effort to use meaningful names, and limit their scope, it will never get easier.

If you can not clearly state your requirements, or expectations, it will never get any easier.

Okay, I’ll try to explain in detail.

I have a 4x4 membrane keypad, I need to enter a value on the keypad, this value will be shown on the display and stored in a variable, in order to be able to use the same variable in the control of how long the engine will be turned on. I’m having trouble creating this menu, where it inserts the values. I think my program has many errors, so I would like to make a new one maybe, even if it were simpler but functional. I will now record a video of how the current program works.

That im trying to show the problem

That im trying to show the problem

I do not need to watch a video to know that you still have not stated whether you expect getKey() to wait for input, or not.

PaulS:
I do not need to watch a video to know that you still have not stated whether you expect getKey() to wait for input, or not.

I already entered the command "if (key! = NO_KEY) but it does not work too, I'm not understanding what I mean, sorry for my ignorance

Waiting for a key to be pressed, and dealing with no key being pressed, are NOT the same thing. A simple one word answer is needed to this question:

Are you expecting getKey() to wait for a key to be pressed, before it returns?

Yes or no.

Yes! Now I understood the question.

The program wait a key to be pressed, and when it pressed, he returns to me

Yes! Now I understood the question.

The program wait a key to be pressed, and when it pressed, he returns to me

OK. Now we can make progress.

The getKey() method does NOT wait. It simply determines if a key is BEING pressed at the time the function is called.

The waitForKey() method DOES wait. It will simply burn cycles until a key BECOMES pressed, when it will return which key became pressed.

So, if you want to do nothing until a key is pressed, you need to use waitForKey(), not getKey().