Issue reading Matrix Keypad

I am using the UNO and have a 4x4 Matrix keypad interfaced and a LCD for user messages. I am using the keypad.cpp Version 3.1

Basically things work.

However I am not sure how to use the keypad effectively to get user entered numeric values one after another. Refer the code :

 // Read the Matrix KeyPad. This is inside the loop().

  char UserKey = customKeypad.getKey();

 if (UserKey !=NO_KEY){                  // User wants to enter EDIT..
    if ( UserKey == 'M') {
       RTC_Disp_Gate = LOW;
       lcd.clear();
       location = 14;
       lcd.cursor();
       lcd.print( "ENTER HOURS :"  );    // Set the display for getting Hours input from user
       delay(1000);
   }} 
 
     
  if ( UserKey !=NO_KEY) {             // Get user input numeric for Tens place
    lcd.print (UserKey);
    lcd.setCursor(location,0);
   }

Problem I have is : When user enters 'M' to enter EDIT mode, the LCD message changes as required but instead of waiting for user numeric entry, it prints the character 'M' first and then takes the user entered numeric value. How to prevent the 'M' from printing ? ( I am running the loop() with a 50ms delay. )

So I think the way I have implemented the Keypad routine is not correct. Please help correct it.

I don't see the rest of the code, but something like the following could work:

 // Read the Matrix KeyPad. This is inside the loop().

  char UserKey = customKeypad.getKey();

 if (UserKey !=NO_KEY){                  // User wants to enter EDIT..
    if ( UserKey == 'M') {
       RTC_Disp_Gate = LOW;
       lcd.clear();
       location = 14;
       lcd.cursor();
       lcd.print( "ENTER HOURS :"  );    // Set the display for getting Hours input from user
       delay(1000);
   }}
 
     
  if ( UserKey !=NO_KEY && UserKey != 'M' ) {             // Get user input numeric for Tens place
    lcd.print (UserKey);
    lcd.setCursor(location,0);
   }

Luisilva

Yeah for sure that will work. But there are many such specific keys that I need to check as part of the user EDIT routine and it will be not practical to AND the different key values every time.

I still have not been able to study the Keypad.cpp in detail but maybe there is some function to say a particular key has been released ( in my case 'M' ) so that till, I get that signal I will not check for another keypress ?

Thanks for your time.

but maybe there is some function to say a particular key has been released ( in my case 'M' ) so that till, I get that signal I will not check for another keypress ?

No, there is not. You need to think of interfacing with the keypad in terms of event driven programming. Until there is an event, there is nothing to do. When there is an event, what to do may (and in your case, does) depend on what else has already happened.

In my case I am invoking the getkey() once every 50ms as part of the loop().

PaulS:
.... When there is an event, what to do may (and in your case, does) depend on what else has already happened.

I am not sure I follow that...could you elaborate a bit please ? Thanks.

I am not sure I follow that...could you elaborate a bit please ? Thanks.

You call getKey(). If it returns that a key is pressed, that is an event.

Is it the first of 4 that you expect? Is it the 3rd of 4? Is it the enter key? Is it the backspace key?

The action that you perform (save the data) when an event occurs (a key is pressed) depends on what actions and events have already occurred.

P.S. You are planning to allow for a backspace key, aren't you?

OK this code works and I am able to get the hour value ( 0 to 24 ) from user and save it to EEPROM. But somehow its quite big and I need to create similar ones for Minutes, day of month, month and year and over all the code size will be quite large. Any other better ideas ??

if (UserKey !=NO_KEY){                  // User wants to enter EDIT..
    if ( UserKey == 'M') {
       RTC_Disp_Gate = LOW;
       lcd.clear();
       lcd.cursor();
       location = ten;
       lcd.print( "ENTER HOURS :"  );    // Set the display for getting Hours input from user
       hour = bcdToDec(EEPROM.read(0));
       lcd.print (hour);
       lcd.setCursor(location,0);  
     }
   } 
  
  if (UserKey == 'L') {
       if ( location == ten) {
           location = unit;
           lcd.setCursor(location,0);   
         }}

    if ( location == ten) {
      switch (UserKey) {                    // Get user input numeric for Tens place of Hour 
            case '0': lcd.print("0");
            hour = 0;
            break;
            case '1': lcd.print("1");
            hour = 1;
            break;
            case '2': lcd.print("2");
            hour = 2;
            break;
           }
       lcd.setCursor(location,0);
       xhour = hour << 4;
       }  

    if ( location == unit) {
       switch (UserKey) {                    // Get user input numeric for Units place of Hour 
            case '0': lcd.print("0");
            thour = 0; 
            break;
            case '1': lcd.print("1");
            thour = 1; 
            break;
            case '2': lcd.print("2");
            thour = 2; 
            break;
            case '3': lcd.print("3");
            thour = 3; 
            break;
            }
        lcd.setCursor(location,0);
        }
 
  if (UserKey == 'E') {
     ahour = xhour | thour; 
     EEPROM.write(0, ahour);
    RTC_Disp_Gate = HIGH; 
  }

How do your cases differ from the value that selects the case?

      switch (UserKey) {                    // Get user input numeric for Tens place of Hour 
            case '0': lcd.print("0");
            hour = 0;
            break;
   <snip>

could be simply:

            // Get user input numeric for Tens place of Hour 
            lcd.print(UserKey);
            hour = UserKey;

Similar changes to the ones portion should be made.

Yes I too agree that my Switch case is rather convoluted to look ! But then the code as you suggested was the exact one I tried and posted the problem - refer my first post on this ...

Since there was no trap in between the user selecting the key "M" for edit mode and the code which sends the UserKey to LCD, I always ended up with "M" on the LCD before the user inputs any numeric. Reason why I was wondering if there is a function in KeyPad to identify "KeyRelase" .

Reason why I was wondering if there is a function in KeyPad to identify "KeyRelase" .

There isn't a function to do that. There is a property of the KeyPad class that tells you the state of the keypad. It's not terribly useful, unless you are looking to implement some kind of repeat action that kicks in when a key is held down.

Since there was no trap in between the user selecting the key "M" for edit mode and the code which sends the UserKey to LCD, I always ended up with "M" on the LCD before the user inputs any numeric.

That is an incredibly easy "problem" to fix. Don't print the key value if the key value is 'M'.

Although why providing feedback, that the code has entered "M" mode, is a problem escapes me. I'd be complaining if I did NOT get that feedback.

Now its fixed and working good to take a 4 digit numeric value from user :

if (UserKey !=NO_KEY){                  // User wants to enter EDIT..
    if ( UserKey == 'M') {
       RTC_Disp_Gate = LOW;
       location = thou;
       lcd.clear();
       lcd.cursor();
       lcd.print( "CYC TIME(S):" );    // Set the display for getting cycle time input from user
       EEPROM.get(0,cyctime );
       lcd.print (cyctime);
       lcd.setCursor(location,0);
       Par01_Gate = HIGH;  
     }
   } 

  if (UserKey !=NO_KEY){
  if (UserKey == 'L') {
       location++ ; 
       if ( location > 15) location = 12;
         }}

  if (Par01_Gate == HIGH ) {
    if (UserKey != NO_KEY) {
      numval = numkeyval(UserKey);
      lcd.setCursor(location,0);
      if (location == thou && numval != 'L') {A_CycTime[0] = UserKey;
      }
      if (location == hund && numval != 'L') {A_CycTime[1] = UserKey;
       }
      if (location == ten && numval != 'L') {A_CycTime[2] = UserKey;
       }
      if (location == unit && numval != 'L' && numval != 'E' ) {A_CycTime[3] = UserKey;  // If this 'E' is not checked, then the UNIT place prints 'E' insteda of number..
      }  

      if (UserKey == 'E') {
         cyctime = atoi(A_CycTime);
         //Serial.println(cyctime);
         EEPROM.put(0,cyctime);
         RTC_Disp_Gate = HIGH; 
         Par01_Gate = LOW;
      }
    }
  }

Thanks so much for your support.

Now its fixed and working good to take a 4 digit numeric value from user

As long as they never make a mistake and hit the wrong key...