Need Help with LCD Menu scroll Program

Hello,

I am having trouble scrolling through a menu on a LCD (20x4) after going into a sub menu. The code works fine and the menu also scrolls when the buttons are pressed. But once i go to sub menu (like case ‘A’ or Case ‘B’), and press * to get back to the home page the scrolling stops. All the functions work; I can still go to sub menu but cannot scroll down or up.

I would highly appreciate if you guys can help me out on this issue.

Regards,

#include <LiquidCrystal.h>
#include <Keypad.h>

int value=0;
int Cement_Weight = 0;
int Sand_Weight = 0;
int Water_Weight = 0;
char selection;

int page_counter=1 ;    
int up = 52;              
int down = 53;                        

boolean current_up = LOW;          
boolean last_up=LOW;            
boolean last_down = LOW;
boolean current_down = LOW;

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] = {14,15,16,17}; //row pinouts of the keypad (L1, L2, L3, L4)
byte colPins[COLS] = {18,19,20,21}; //column pinouts of the keypad (R1, R2, R3)

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


LiquidCrystal lcd1(2,3,4,5,6,7);
LiquidCrystal lcd2(2,9,4,5,6,7);

void setup()
{
  Serial.begin(9600);
  lcd1.begin(20,4);  
  lcd2.begin(20,4);  
  lcd1.clear();
  lcd2.clear();

  Live_Weight_Display();  
  keypad.addEventListener(keypadEvent);
}
  
boolean debounce(boolean last, int pin)
 {
  boolean current = digitalRead(pin);
  if (last != current)
  {
   delay(5);
   current = digitalRead(pin);
  }
  return current;
 }


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

void Scroll()
{
  
 
  current_up = debounce(last_up, up);         
  current_down = debounce(last_down, down);

  
    
//Page Up
  if (last_up== LOW && current_up == HIGH)
   { 
    lcd1.clear();                     //When page is changed, lcd clear to print new page   
    if(page_counter <3)
    {              //Page counter never higher than 3(total of pages)
    page_counter= page_counter +1;   //Page up
    }
    else
    {
     page_counter= 1;                //return to page 1
    }
   }
  last_up = current_up;

//Page Down
   if (last_down== LOW && current_down == HIGH)
    {
     lcd1.clear();                     //When page is changed, lcd clear to print new page    
     if(page_counter >1)
     {              //Page counter never lower than 1 (total of pages)
      page_counter= page_counter -1;   //Page down
     }
     else
     {
     page_counter= 3;              //return to page 3
     }
    }
  last_down = current_down;

  switch (page_counter) 
  {
   case 1:
   {     
    menu();
   }
    break;

   case 2: 
   { //Design of page 3
     lcd1.setCursor(5,0);
     lcd1.print("This is");
     lcd1.setCursor(4,1);
     lcd1.print("Page 3");
     
   }
    break;

   case 3: 
   {   //Design of page 2 
     lcd1.setCursor(1,0);
     lcd1.print("You are now on");
     lcd1.setCursor(4,1);
     lcd1.print("Page 2");
     
    }
    break;
  }
  
}

void Live_Weight_Display()
{
  lcd2.clear();
  lcd2.print("  Weight  Settings");
  lcd2.setCursor(0,1);
  lcd2.print("Cement  Sand  Water");
  lcd2.setCursor(0,2);
  lcd2.print(Cement_Weight);
  lcd2.print(" kg");
  lcd2.setCursor(8,2);
  lcd2.print(Sand_Weight);
  lcd2.print(" kg");
  lcd2.setCursor(14,2);
  lcd2.print(Water_Weight);
  lcd2.print(" kg");
} 

void menu()
{
 lcd1.setCursor(0,0);
 lcd1.print("Menu: ");
 lcd1.setCursor(0,1);
 lcd1.print("For Cement Press A");
 lcd1.setCursor(0,2);
 lcd1.print("For Sand   Press B");
 lcd1.setCursor(0,3);
 lcd1.print("For Water  Press C");
}

void keypadEvent(KeypadEvent key)
{
 switch (key)
 {
  case 'A':
      lcd1.clear();
      lcd1.print("Enter Cement Weight");
      lcd1.setCursor(0,1);
      lcd1.print("& Then Press #");
      lcd1.setCursor(5,2);
      lcd1.print("kg");
      Cement_Weight = getTheNumber();
      Live_Weight_Display(); 
      break;

  case 'B':
      lcd1.clear();
      lcd1.print("Enter Sand Weight");
      lcd1.setCursor(0,1);
      lcd1.print("& Then Press #");
      lcd1.setCursor(5,2);
      lcd1.print("kg");
      Sand_Weight = getTheNumber();
      Serial.print (Sand_Weight);
      Live_Weight_Display(); 
      break;

  case 'C':
      lcd1.clear();
      lcd1.print("Enter Water Weight");
      lcd1.setCursor(0,1);
      lcd1.print("& Then Press #");
      lcd1.setCursor(5,2);
      lcd1.print("kg");
      Water_Weight = getTheNumber();  
      Live_Weight_Display();
      break;
    
  case 'D':
      lcd1.clear();
      lcd1.print("Cement:");
      lcd1.setCursor(7,0);
      lcd1.print(Cement_Weight);
      lcd1.print(" kg");
      lcd1.setCursor(0,1);
      lcd1.print("Sand  :");
      lcd1.setCursor(7,1);
      lcd1.print(Sand_Weight);
      lcd1.print(" kg");
      lcd1.setCursor(0,2);
      lcd1.print("Water :");
      lcd1.setCursor(7,2);
      lcd1.print(Water_Weight);
      lcd1.print(" kg");
      lcd1.setCursor(0,3);
      lcd1.print("Hold # to reset");    
      break;

   case '*':
      lcd1.clear();
      page_counter= 1;
      loop();
      break;
 }
 switch (keypad.getState())
 {
  case HOLD:
      if (key == '#') 
      {
          Cement_Weight = 0;
          Sand_Weight = 0;
          Water_Weight = 0;
          lcd1.clear();
          lcd1.print("Cement:");
          lcd1.setCursor(7,0);
          lcd1.print(Cement_Weight);
          lcd1.print(" kg");
          lcd1.setCursor(0,1);
          lcd1.print("Sand  :");
          lcd1.setCursor(7,1);
          lcd1.print(Sand_Weight);
          lcd1.print(" kg");
          lcd1.setCursor(0,2);
          lcd1.print("Water :");
          lcd1.setCursor(7,2);
          lcd1.print(Water_Weight);
          lcd1.print(" kg");
          lcd1.setCursor(0,3);
          lcd1.print("Hold # to reset");
          Live_Weight_Display();          
       }
          break;
 }
}

int getTheNumber()
{
    
    char buffer[4];

    // Input up to 3 numbers until we find a * or #
    int i=0;
    while (1)
    {
        char key = keypad.getKey();

        // If it's a number AND we have space left, add to our string
        if ('0' <= key && key <= '9' && i < 3)
        {
            buffer[i] = key;
            i++;    
            Serial.print(key);
            lcd1.setCursor(i,2);
            lcd1.print(key);
            
        }
        // If it's a * or #, end
        else if ('#' == key && i > 0)
        {
            // Null terminate
            buffer[i] = 0;
            int value = atoi(buffer);  // Convert to an integer
            i = 0;
            return value;
            break;
        }    
    }
}

It appears that you grabbed a snippet of code from one source and grabbed another from a different source. (In one switch/case block you use an unnecessary set of braces for the case blocks, but didn't in another set.) When using a switch/case statement block, I find it useful to always have a default case like:

  switch (page_counter) {
     case 1:
        menu();
        break;

     // more cases...

     default:
        Serial.print("I shouldn't be here. page_counter = ");
        Serial.println(page_counter);
        break;
   }

Try to better organize your code so it's easier to read. Virtually every program has The Five Program Steps:

  1. Initialization -- set the environment for the program (e.g., Serial.begin(), setting pins, etc.) This belongs in setup
  2. Input -- where and how am I going to get the data used in the program? How should I validate it?
  3. Process -- Programs usually take data in one form, chew on it, and end up with new data. The chewing process is dictated by an algorithm--your plan for converting the data
  4. Output -- how and where am I going to show/use the results of this program?
  5. Termination -- release claimed resources back to the op system, close databases, ports, etc. Often this is Step 1 in reverse. However, many microcontroller programs are designed to run until power is removed, there's a Reset, or a component fails.

See if reorganizing your program doesn't help make it easier to debug it.

Good advice from econjack. Let me add another few points:

  case '*':
      lcd1.clear();
      page_counter= 1;
      loop();
      break;

Never explicitly call the loop() function; you could end up with excessive recursion and then failure. In this particular case, you could simply return from the function.

char key = keypad.getKey();

In case you are not aware, every time you call getKey(), and there is a key press pending, it will implicitly call your event listener function (keypadEvent). So for example, in getTheNumber() the event listener function will be called after every key press. It may or may not be a problem at the moment, but you need to be aware of it.

void keypadEvent(KeypadEvent key)
{
  switch (key)
  {
    case 'A':
    // ...
  }

If my understanding of the keypad library is correct, the keypad event can be PRESSED, HOLD and RELEASED (ignoring IDLE). That means that 'A' (etc.) will happen at least twice; once for press and once for release. You need to be aware of that too. That means that the '*' case is called twice, and therefore the evil explicit loop() is being called twice.

As a matter of style, I would have just the one switch statement in keypadEvent() and handled the key states within. Sort of like this:

void keypadEvent(KeypadEvent key)
{
  KeyState keyState = keypad.getState();
  switch (key)
  {
    // other cases here...

    case '#':
      if (keyState == HOLD) {
        // all that stuff
      }
      break;

    case '*':
      if (keyState == PRESSED) {
        lcd1.clear();
        page_counter = 1;
      }
      break;
  }
}

econjack:
It appears that you grabbed a snippet of code from one source and grabbed another from a different source.

I am new at this so i took some help from internet and found the scroll menu code but most of the entire code is written by me.

Thank you for the valuable feedback and advice.

arduarn:
Never explicitly call the loop() function; you could end up with excessive recursion and then failure. In this particular case, you could simply return from the function.

Where will the return come in the case ‘*’ part?
like this:

case '*':
      if (keyState == PRESSED) {
        lcd1.clear();
        page_counter = 1;
        return;
      }
      break;

In case you are not aware, every time you call getKey(), and there is a key press pending, it will implicitly call your event listener function (keypadEvent). So for example, in getTheNumber() the event listener function will be called after every key press. It may or may not be a problem at the moment, but you need to be aware of it.

Actually, I am facing this problem as sometimes if I press the numbers on the home screen; they start printing on the lcd. But I didnt know it was because of the issue you mentioned.

How can this be solved?

staccato: Where will the return come in the case '*' part? like this:

I doubt you need the return at all; I just presented it as the "anything is better than explicitly calling loop()" alternative.

staccato: Actually, I am facing this problem as sometimes if I press the numbers on the home screen; they start printing on the lcd. But I didnt know it was because of the issue you mentioned.

How can this be solved?

Without dramatically changing your program structure and style, you could improve things by:

  • removing keypad.addEventListener(keypadEvent), you simply don't need the event handling with your existing code
  • refactor void keypadEvent(KeypadEvent key) to void checkKeypad()
  • call checkKeypad() in loop() instead of char key = keypad.getKey()
  • checkKeypad() then becomes (no return needed)
void checkKeypad()
{
  const char key = keypad.getKey();
  const KeyState keyState = keypad.getState();
  switch (key)
  {
    // other cases here...

    case '#':
      if (keyState == HOLD) {
        // all that stuff
      }
      break;

    case '*':
      if (keyState == PRESSED) {
        lcd1.clear();
        page_counter = 1;
      }
      break;

    case NO_KEY: // fall through to default
    default: // ignore
  }
}
  • hmm, I think that's probably it

Try that first and see how things work. If you run into any problems, then make sure you post your updated code.

Hey,

Thanks for your reply. I modified my code as per your instructions. However, I am facing some issues:

  1. When compiling the code, there’s an error (please refer to the attached picture)

  2. When I remove the last 2 lines before error, the code compiles but still there are issues
    a. Once I go to sub menu the “*” option (to go back to menu) doesn’t work.
    b. When I press “D” the lcd clear function doesn’t work and the characters just overwrite the current
    screen.
    c. Holding the “#” button function doesn’t work.
    d. When I go to sub menu and enter the value and press “#” to store it; it saves the value goes automatically back to
    the previous screen (without lcd.clear).

I highly appreciate your kind help.

#include <Keypad.h>

#include <LiquidCrystal.h>

int value=0;
int Cement_Weight = 0;
int Sand_Weight = 0;
int Water_Weight = 0;
char selection;

int page_counter=1 ;    
const int up = 52;              
const int down = 53;
const int test = 50;    

long startTime ;                   
long elapsedTime ;
int fractional;

boolean current_up = LOW;          
boolean last_up=LOW;            
boolean last_down = LOW;
boolean current_down = LOW;

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] = {14,15,16,17}; //row pinouts of the keypad (L1, L2, L3, L4)
byte colPins[COLS] = {18,19,20,21}; //column pinouts of the keypad (R1, R2, R3)

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


LiquidCrystal lcd1(2,3,4,5,6,7);
LiquidCrystal lcd2(2,9,4,5,6,7);

void setup()
{
  Serial.begin(9600);
  lcd1.begin(20,4);  
  lcd2.begin(20,4);  
  lcd1.clear();
  lcd2.clear();

  pinMode(test, INPUT);
  pinMode(up, INPUT);
  pinMode(down, INPUT);

  Live_Weight_Display();  
//  keypad.addEventListener(checkkeypad);
}
  
boolean debounce(boolean last, int pin)
 {
  boolean current = digitalRead(pin);
  if (last != current)
  {
   delay(5);
   current = digitalRead(pin);
  }
  return current;
 }


void loop()
{
   
  
  checkkeypad();
  Scroll();   
  
}

void Scroll()
{
  
 
  current_up = debounce(last_up, up);         
  current_down = debounce(last_down, down);
     
//Page Up
  if (last_up== LOW && current_up == HIGH)
   { 
    lcd1.clear();                     //When page is changed, lcd clear to print new page   
    if(page_counter <3)
    {              //Page counter never higher than 3(total of pages)
    page_counter= page_counter +1;   //Page up
    }
    else
    {
     page_counter= 1;                //return to page 1
    }
   }
  last_up = current_up;

//Page Down
   if (last_down== LOW && current_down == HIGH)
    {
     lcd1.clear();                     //When page is changed, lcd clear to print new page    
     if(page_counter >1)
     {              //Page counter never lower than 1 (total of pages)
      page_counter= page_counter -1;   //Page down
     }
     else
     {
     page_counter= 3;              //return to page 3
     }
    }
  last_down = current_down;

  switch (page_counter) 
  {
   case 1:     
    menu();
    break;

   case 2:  //Design of page 3
    lcd1.setCursor(5,0);
    lcd1.print("This is");
    lcd1.setCursor(4,1);
    lcd1.print("Page 3");
    break;

   case 3:   //Design of page 2 
    lcd1.setCursor(1,0);
    lcd1.print("You are now on");
    lcd1.setCursor(4,1);
    lcd1.print("Page 2"); 
    break;
  } 
}

void Live_Weight_Display()
{
  lcd2.clear();
  lcd2.print("  Weight  Settings");
  lcd2.setCursor(0,1);
  lcd2.print("Cement  Sand  Water");
  lcd2.setCursor(0,2);
  lcd2.print(Cement_Weight);
  lcd2.print(" kg");
  lcd2.setCursor(8,2);
  lcd2.print(Sand_Weight);
  lcd2.print(" kg");
  lcd2.setCursor(14,2);
  lcd2.print(Water_Weight);
  lcd2.print(" kg");
} 

void menu()
{
 lcd1.setCursor(0,0);
 lcd1.print("Menu: ");
 lcd1.setCursor(0,1);
 lcd1.print("For Cement Press A");
 lcd1.setCursor(0,2);
 lcd1.print("For Sand   Press B");
 lcd1.setCursor(0,3);
 lcd1.print("For Water  Press C");
}



void checkkeypad()
{
 const char key = keypad.getKey();
 const KeyState keyState = keypad.getState();
 switch (key)
 {
  case 'A':
      lcd1.clear();
      lcd1.print("Enter Cement Weight");
      lcd1.setCursor(0,1);
      lcd1.print("& Then Press #");
      lcd1.setCursor(5,2);
      lcd1.print("kg");
      Cement_Weight = getTheNumber();
      Live_Weight_Display(); 
      break;

  case 'B':
      lcd1.clear();
      lcd1.print("Enter Sand Weight");
      lcd1.setCursor(0,1);
      lcd1.print("& Then Press #");
      lcd1.setCursor(5,2);
      lcd1.print("kg");
      Sand_Weight = getTheNumber();
      Serial.print (Sand_Weight);
      Live_Weight_Display(); 
      break;

  case 'C':
      lcd1.clear();
      lcd1.print("Enter Water Weight");
      lcd1.setCursor(0,1);
      lcd1.print("& Then Press #");
      lcd1.setCursor(5,2);
      lcd1.print("kg");
      Water_Weight = getTheNumber();  
      Live_Weight_Display();
      break;
    
  case 'D':
      lcd1.clear();
      lcd1.print("Cement:");
      lcd1.setCursor(7,0);
      lcd1.print(Cement_Weight);
      lcd1.print(" kg");
      lcd1.setCursor(0,1);
      lcd1.print("Sand  :");
      lcd1.setCursor(7,1);
      lcd1.print(Sand_Weight);
      lcd1.print(" kg");
      lcd1.setCursor(0,2);
      lcd1.print("Water :");
      lcd1.setCursor(7,2);
      lcd1.print(Water_Weight);
      lcd1.print(" kg");
      lcd1.setCursor(0,3);
      lcd1.print("Hold # to reset");    
      break;
      
   case '#':
      if (keyState == HOLD)
      {
       Cement_Weight = 0;
       Sand_Weight = 0;
       Water_Weight = 0;
       lcd1.clear();
       lcd1.print("Cement:");
       lcd1.setCursor(7,0);
       lcd1.print(Cement_Weight);
       lcd1.print(" kg");
       lcd1.setCursor(0,1);
       lcd1.print("Sand  :");
       lcd1.setCursor(7,1);
       lcd1.print(Sand_Weight);
       lcd1.print(" kg");
       lcd1.setCursor(0,2);
       lcd1.print("Water :");
       lcd1.setCursor(7,2);
       lcd1.print(Water_Weight);
       lcd1.print(" kg");
       lcd1.setCursor(0,3);
       lcd1.print("Hold # to reset");
       Live_Weight_Display(); 
      }
      break;

   case '*':
      if (keyState == PRESSED)
      {
       lcd1.clear();
       page_counter= 1;
      }
      break;

   case NO_KEY: // fall through to default
   default: // ignore
 }
}

int getTheNumber()
{
    
    char buffer[4];

    // Input up to 3 numbers until we find a * or #
    int i=0;
    while (1)
    {
        char key = keypad.getKey();

        // If it's a number AND we have space left, add to our string
        if ('0' <= key && key <= '9' && i < 3)
        {
            buffer[i] = key;
            i++;    
            Serial.print(key);
            lcd1.setCursor(i,2);
            lcd1.print(key);
            
        }
        // If it's a * or #, end
        else if ('#' == key && i > 0)
        {
            // Null terminate
            buffer[i] = 0;
            int value = atoi(buffer);  // Convert to an integer
            i = 0;
            return value;
            break;
        }    
    }
}

staccato:

  1. When compiling the code, there’s an error (please refer to the attached picture)

Ok, that’s me being a lemon: i forgot the ;

    default: ; // ignore

staccato:
2. When I remove the last 2 lines before error, the code compiles but still there are issues
a. Once I go to sub menu the “*” option (to go back to menu) doesn’t work.

That’s a little unexpected. Print something to serial after the case ‘*’ and then again from within the if PRESSED block to see if the PRESSED is causing a problem.

staccato:
b. When I press “D” the lcd clear function doesn’t work and the characters just overwrite the current
screen.

This is to be expected as the Scroll() function will overwrite the pages on top of the existing text.

staccato:
c. Holding the “#” button function doesn’t work.

After looking in the library implementation, it seems getKey() only returns a key press for PRESSED, and not for the other states. That’s a tad annoying.

staccato:
d. When I go to sub menu and enter the value and press “#” to store it; it saves the value goes automatically back to
the previous screen (without lcd.clear).

See b.

Let’s figure out a. first, then we’ll look at the others.

Tell you what, try these few tweaks and see if they bring it any closer to what you want:

#include <Keypad.h>

#include <LiquidCrystal.h>

int value=0;
int Cement_Weight = 0;
int Sand_Weight = 0;
int Water_Weight = 0;
char selection;

int page_counter=1;   
const int up = 52;             
const int down = 53;
const int test = 50;   

long startTime;                   
long elapsedTime;
int fractional;

boolean current_up = LOW;         
boolean last_up=LOW;           
boolean last_down = LOW;
boolean current_down = LOW;

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] = {14,15,16,17}; //row pinouts of the keypad (L1, L2, L3, L4)
byte colPins[COLS] = {18,19,20,21}; //column pinouts of the keypad (R1, R2, R3)

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

LiquidCrystal lcd1(2,3,4,5,6,7);
LiquidCrystal lcd2(2,9,4,5,6,7);

void setup()
{
  Serial.begin(9600);
  lcd1.begin(20, 4);
  lcd2.begin(20, 4);
  lcd1.clear();
  lcd2.clear();

  pinMode(test, INPUT);
  pinMode(up, INPUT);
  pinMode(down, INPUT);

  displayTopMenu();
  displayLiveWeight();
}

boolean debounce(boolean last, int pin)
{
  boolean current = digitalRead(pin);
  if (last != current)
  {
    delay(5);
    current = digitalRead(pin);
  }
  return current;
}

void loop()
{
  checkKeypad();
  checkScroll();
}

void checkScroll()
{

  current_up = debounce(last_up, up);
  current_down = debounce(last_down, down);

  //Page Up
  if (last_up == LOW && current_up == HIGH)
  {
    if (page_counter < 3)
    { //Page counter never higher than 3(total of pages)
      page_counter = page_counter + 1; //Page up
    }
    else
    {
      page_counter = 1;               //return to page 1
    }
    displayTopMenu();
  }
  last_up = current_up;

  //Page Down
  if (last_down == LOW && current_down == HIGH)
  {
    if (page_counter > 1)
    { //Page counter never lower than 1 (total of pages)
      page_counter = page_counter - 1; //Page down
    }
    else
    {
      page_counter = 3;             //return to page 3
    }
    displayTopMenu();
  }
  last_down = current_down;
}

void displayTopMenu()
{
  lcd1.clear();
  switch (page_counter)
  {
    case 1:
      lcd1.setCursor(0, 0);
      lcd1.print("Menu: ");
      lcd1.setCursor(0, 1);
      lcd1.print("For Cement Press A");
      lcd1.setCursor(0, 2);
      lcd1.print("For Sand   Press B");
      lcd1.setCursor(0, 3);
      lcd1.print("For Water  Press C");
      break;

    case 2:  //Design of page 3
      lcd1.setCursor(5, 0);
      lcd1.print("This is");
      lcd1.setCursor(4, 1);
      lcd1.print("Page 3");
      break;

    case 3:   //Design of page 2
      lcd1.setCursor(1, 0);
      lcd1.print("You are now on");
      lcd1.setCursor(4, 1);
      lcd1.print("Page 2");
      break;
  }
}

void displayLiveWeight()
{
  lcd2.clear();
  lcd2.print("  Weight  Settings");
  lcd2.setCursor(0, 1);
  lcd2.print("Cement  Sand  Water");
  lcd2.setCursor(0, 2);
  lcd2.print(Cement_Weight);
  lcd2.print(" kg");
  lcd2.setCursor(8, 2);
  lcd2.print(Sand_Weight);
  lcd2.print(" kg");
  lcd2.setCursor(14, 2);
  lcd2.print(Water_Weight);
  lcd2.print(" kg");
}

void displaySetWeight()
{
  lcd1.clear();
  lcd1.print("Cement:");
  lcd1.setCursor(7, 0);
  lcd1.print(Cement_Weight);
  lcd1.print(" kg");
  lcd1.setCursor(0, 1);
  lcd1.print("Sand  :");
  lcd1.setCursor(7, 1);
  lcd1.print(Sand_Weight);
  lcd1.print(" kg");
  lcd1.setCursor(0, 2);
  lcd1.print("Water :");
  lcd1.setCursor(7, 2);
  lcd1.print(Water_Weight);
  lcd1.print(" kg");
  lcd1.setCursor(0, 3);
  lcd1.print("Hold # to reset");
}

void checkKeypad()
{
  // based on the keypad implementation for getKey() but now for all states
  if (keypad.getKeys() && keypad.key[0].stateChanged) {
    const char key = keypad.key[0].kchar;
    const KeyState keyState = keypad.key[0].kstate;

    Serial.print("kchar: ");
    Serial.print(key);
    Serial.print(", kstate: ");
    Serial.println((keyState == PRESSED) ? "PRESSED"
                   : (keyState == HOLD) ? "HOLD"
                   : (keyState == RELEASED) ? "RELEASED"
                   : "IDLE");

    switch (key)
    {
      case 'A':
        if (keyState == PRESSED)
        {
          lcd1.clear();
          lcd1.print("Enter Cement Weight");
          lcd1.setCursor(0, 1);
          lcd1.print("& Then Press #");
          lcd1.setCursor(5, 2);
          lcd1.print("kg");
          Cement_Weight = getTheNumber();
          displayLiveWeight();
        }
        break;

      case 'B':
        if (keyState == PRESSED)
        {
          lcd1.clear();
          lcd1.print("Enter Sand Weight");
          lcd1.setCursor(0, 1);
          lcd1.print("& Then Press #");
          lcd1.setCursor(5, 2);
          lcd1.print("kg");
          Sand_Weight = getTheNumber();
          Serial.print (Sand_Weight);
          displayLiveWeight();
        }
        break;

      case 'C':
        if (keyState == PRESSED)
        {
          lcd1.clear();
          lcd1.print("Enter Water Weight");
          lcd1.setCursor(0, 1);
          lcd1.print("& Then Press #");
          lcd1.setCursor(5, 2);
          lcd1.print("kg");
          Water_Weight = getTheNumber();
          displayLiveWeight();
        }
        break;

      case 'D':
        if (keyState == PRESSED)
        {
          displaySetWeight();
        }
        break;

      case '#':
        if (keyState == HOLD)
        {
          Cement_Weight = 0;
          Sand_Weight = 0;
          Water_Weight = 0;
          displaySetWeight();
          displayLiveWeight();
        }
        break;

      case '*':
        if (keyState == PRESSED)
        {
          displayTopMenu();
        }
        break;

      case NO_KEY:  // fall through to default
      default: ; // ignore
    }
  }
}

int getTheNumber()
{

  char buffer[4];

  // Input up to 3 numbers until we find a * or #
  int i = 0;
  while (1)
  {
    if (keypad.getKeys() && keypad.key[0].stateChanged && keypad.key[0].kstate == PRESSED) {
      const char key = keypad.key[0].kchar;

      // If it's a number AND we have space left, add to our string
      if ('0' <= key && key <= '9' && i < 3)
      {
        buffer[i] = key;
        i++;
        Serial.print(key);
        lcd1.setCursor(i, 2);
        lcd1.print(key);

      }
      // If it's a * or #, end
      else if ('#' == key && i > 0)
      {
        // Null terminate
        buffer[i] = 0;
        int value = atoi(buffer);  // Convert to an integer
        i = 0;
        return value;
        break;
      }
    }
  }
}

Thank you very much for your help. The code works perfectly fine but one small minor issue.

Once I go to sub menu (for example CASE A). I can can not go back to the main menu unless I enter the value (weight) and store it.

staccato: Once I go to sub menu (for example CASE A). I can can not go back to the main menu unless I enter the value (weight) and store it.

Well, in getTheNumber() you have the following comment:

      }
      // If it's a * or #, end
      else if ('#' == key && i > 0)
      {

So perhaps you should make the code match the comment?

Of course you will run into the problem that if you cancel the weight input with *, the weight will be set anyway, which may not be what you want...

I dont think its a big issue and I can live with it

Thank you very much for your kind help.

Regards,