Why does my keypad save the input from switch case?

Hi, I am building an automatic pet feeder using UNO and I am creating a simple menu using a switch case from the keypad. This is the sample code where the user enters A to set the number of times the pet needs to be fed. When I click A on the keypad it asks for the user to set the number. However, the keypad still somehow saves the input of A that is initially pressed. I want the system to ask for another input. How would I clear the memory of the keypad? Here is the code attached

/* Hello Wokwi! */
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
const int ROW_NUM    = 4; // four rows
const int COLUMN_NUM = 4; // four columns
char keys[ROW_NUM][COLUMN_NUM] = {
  {'1','2','3', 'A'},
  {'4','5','6', 'B'},
  {'7','8','9', 'C'},
  {'*','0','#', 'D'}
};
int col = 0, row =0;
byte pin_rows[ROW_NUM] = {10,9,8,7};      // connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {6,5,4,3}; // connect to the column pinouts of the keypad
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, 16 column and 2 rows
Keypad keypad = Keypad(makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );

void setup () {

  lcd.init(); // initialize the lcd
  lcd.backlight();
  lcd.setCursor(col,row); // move cursor to   (cursorColumn, 0)
  lcd.print("HI OWNER");
  delay(3000);
}
int h1,h2,hf1,min1,min2,minf1;
int numfed,setnofeed=0;

void loop() {
  
  char key = keypad.getKey();
  if(!key){
    displaytime();
  }

  switch(key){
    case 'A': 
      lcd.setCursor(col,row);
    lcd.print("SET NO. OF");
    lcd.setCursor(col,1);
    lcd.print("FEEDING TIMES");
    delay(3000);

    lcd.clear();
    lcd.setCursor(col,row);
    lcd.print("MAX 5 MIN 2");
    col=0;
    lcd.setCursor(col,1);
    if (col==0&&setnofeed==0){
      numfed=key-48;
      lcd.print(numfed);
      delay(1000);
      col=1;
    }
    else if(col==1){
    lcd.setCursor(col,1);
    lcd.clear();
    lcd.print("NO. OF FEEDING");
    lcd.setCursor(col,1);
    lcd.print("SET");
    delay(2000);
    setnofeed=1;
    }
   
    break;


  }
  
}
void displaytime(){

      lcd.setCursor(0,0); // move cursor to   (cursorColumn, 0)
    lcd.print("Time now:");
}

Hi @michfil

welcome to the arduino-forum.
well done to post your code as a code-section.

This line reads in the keypress

The switch-case that is that part of the code that does the evaluation of the keypress.

Depending on the first keypress you have add code that reads in the keypad a second time and treats the keypress according to the now different way you want to treat it.

This means you have to add logic that sets a new variable to different values and depending on this value you assign the second keypress to the according variable.

If this is your very first program this task is quite demanding. It is Ok to try it and is ok to ask many questions here in the forum.

google for keywords like "arduino keypad enter digits"
best regards Stefan

Hi @StefanL38

Thank you for your reply
I will try your solution out first
Again I appreciate the help

Best,
Michael

Hi Sorry I still cant quite figure out what to add. I have added a new char variable and it did not work.
Could anyone help me as I am a tad bit lost?

Thank you

i don't see where anything other than 'A' is recognized from the keypad.

looks like the code normally displays "Time now:". when it sees an 'A' it updates the display several times with delays between the updates, but never checks the keypad.

i would expect it to change modes after recognizing the 'A', possibly updating a value with each numeric key (0-9) that is pressed (i.e. val = 10*val + key) and then setting something to that value when some end of entry key (e.g. '#") is recognized, possibly displaying that value for a short time before returning to the normal "display time" mode

see what you can do with this

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

const int ROW_NUM    = 4; // four rows
const int COLUMN_NUM = 4; // four columns
char keys[ROW_NUM][COLUMN_NUM] = {
    {'1','2','3', 'A'},
    {'4','5','6', 'B'},
    {'7','8','9', 'C'},
    {'*','0','#', 'D'}
};

int col = 0, row =0;
byte pin_rows[ROW_NUM] = {10,9,8,7};      // connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {6,5,4,3}; // connect to the column pinouts of the keypad
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, 16 column and 2 rows
Keypad keypad = Keypad(makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );

int h1,h2,hf1,min1,min2,minf1;
int numfed,setnofeed=0;

const unsigned long OneSecond = 1000;;
const unsigned long TenSecond = 10000;;
unsigned long msecPeriod;
unsigned long msecLst;
unsigned long msec;

unsigned val;

char s [20];

// -----------------------------------------------------------------------------
void setup ()
{
    lcd.init(); // initialize the lcd
    lcd.backlight();
    lcd.clear ();
    lcd.print ("HI OWNER");
}

// -----------------------------------------------------------------------------
void loop()
{
    msec = millis ();

    char key = keypad.getKey();

    if (! key)  {
        if (msec - msecLst > msecPeriod) {
            msecLst    = msec;
            msecPeriod = OneSecond;
            displaytime();
        }

        return;
    }

    msecPeriod = TenSecond;

    switch (key) {
    case 0:
        break;

    case '0'...'9':
        val = 10*val + key - '0';
        lcd.clear ();
        lcd.print (val);
        break;

    case '*':
        val = 0;
        break;

    case 'A':
        numfed = val;
        val    = 0;
        sprintf (s, "NO FEEDINGS %d", numfed);
        lcd.clear ();
        lcd.print (s);
        break;
    }
}

// -----------------------------------------------------------------------------
void displaytime()
{
    lcd.clear ();
    lcd.print (msec / 1000);
}

Yes
That is the problem. I would like the code to ask the user to set the number of feeding times. I don't know how to ask for another input and make the code read the keypad again.

As I am not clear what you want to achieve, I have uploaded the following sketch in my UNO and have achieved some interactive messages in my real LCD which may be helpful for you.

#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, 16 column and 2 rows

int h1, h2, hf1, min1, min2, minf1;
int numfed, setnofeed = 0;
bool flag = false;
byte feedTimes = 0;

const int ROW_NUM    = 4; // four rows
const int COLUMN_NUM = 4; // four columns
char keys[ROW_NUM][COLUMN_NUM] =
{
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

int col = 0, row = 0;
byte pin_rows[ROW_NUM] = {10, 9, 8, 7};   // R1-R4 connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {6, 5, 4, 3}; // C1-C4 connect to the column pinouts of the keypad

Keypad keypad = Keypad(makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );

void setup ()
{
  lcd.begin();//  lcd.init(); // initialize the lcd
  lcd.backlight();
  lcd.setCursor(col, row); // move cursor to   (cursorColumn, 0)
  lcd.print("HI OWNER");
  lcd.setCursor(0, 1);
  lcd.print("Press A for Menu");
  delay(3000);
}


void loop()
{
  char key = keypad.getKey();
  if (key != 0)
  {
    if (flag == false)
    {
      if (key == 'A')
      {
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Feeding Times?");
        lcd.setCursor(0, 1);
        flag = true;
      }
    }
    else
    {
      if (key >= '1' && key <= '5')
      {
        feedTimes = key - '0';
        lcd.print(key);
      }
    }
  }
}

What is the next input once you have finished/saved the "Feeding Times"?

So the idea was if the user pressed A on the keypad, it would ask the user for another input which is how many times would the user want to feed their pet and they would answer a number from 2-5 ( I
don't know how the code could ask the user for another input). If they did not press any button initially, it would just display "time now".

What is that input?

#undef MyHW
#ifdef MyHW
# include "sim.hh"
#else
# include <Keypad.h>
# include <LiquidCrystal_I2C.h>
#endif

const int ROW_NUM    = 4; // four rows
const int COLUMN_NUM = 4; // four columns
char keys[ROW_NUM][COLUMN_NUM] = {
    {'1','2','3', 'A'},
    {'4','5','6', 'B'},
    {'7','8','9', 'C'},
    {'*','0','#', 'D'}
};

int col = 0, row =0;
byte pin_rows[ROW_NUM] = {10,9,8,7};      // connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {6,5,4,3}; // connect to the column pinouts of the keypad
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, 16 column and 2 rows
Keypad keypad = Keypad(makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );

int h1,h2,hf1,min1,min2,minf1;
int numfed,setnofeed=0;

const unsigned long OneSecond = 1000;;
const unsigned long TenSecond = 10000;;
unsigned long msecPeriod;
unsigned long msecLst;
unsigned long msec;

enum { None, Fdings };
int mode = None;

unsigned val;

char fmt [20];
char s [20];

// -----------------------------------------------------------------------------
void setup ()
{
    lcd.init(); // initialize the lcd
    lcd.backlight();
    lcd.clear ();
    lcd.print ("HI OWNER");
}

// -----------------------------------------------------------------------------
void loop()
{
    msec = millis ();

    char key = keypad.getKey();

    if (! key)  {
        if (msec - msecLst > msecPeriod) {
            msecLst    = msec;
            msecPeriod = OneSecond;
            displaytime();
        }

        return;
    }

    msecPeriod = TenSecond;

    switch (key) {
    case 0:
        break;

    case '0'...'9':
        val = 10*val + key - '0';
        break;

    case '*':
        val = 0;
        break;

    case '#':
        mode       = None;
        val        = 0;
        break;

    case 'A':
        mode = Fdings;
        break;
    }

    switch (mode)  {
    case Fdings:
        numfed = val;
        sprintf (s, "NO FEEDINGS %d", numfed);
        lcd.clear ();
        lcd.print (s);
        break;
    }
}

// -----------------------------------------------------------------------------
void displaytime()
{
    lcd.clear ();
    lcd.print (msec / 1000);
}

I would like to ask the user how many times would they like the machine to feed their pet.

Hi @gcjr
Thank you for your reply I will test it out

[quote="gcjr, post:11, topic:1098807"]

#undef MyHW
#ifdef MyHW
# include "sim.hh"
#else
# include <Keypad.h>
# include <LiquidCrystal_I2C.h>
#endif

const int ROW_NUM    = 4; // four rows
const int COLUMN_NUM = 4; // four columns
char keys[ROW_NUM][COLUMN_NUM] = {
    {'1','2','3', 'A'},
    {'4','5','6', 'B'},
    {'7','8','9', 'C'},
    {'*','0','#', 'D'}
};

int col = 0, row =0;
byte pin_rows[ROW_NUM] = {10,9,8,7};      // connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {6,5,4,3}; // connect to the column pinouts of the keypad
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, 16 column and 2 rows
Keypad keypad = Keypad(makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );

int h1,h2,hf1,min1,min2,minf1;
int numfed,setnofeed=0;

const unsigned long OneSecond = 1000;;
const unsigned long TenSecond = 10000;;
unsigned long msecPeriod;
unsigned long msecLst;
unsigned long msec;

enum { None, Fdings };
int mode = None;

unsigned val;

char fmt [20];
char s [20];

// -----------------------------------------------------------------------------
void setup ()
{
    lcd.init(); // initialize the lcd
    lcd.backlight();
    lcd.clear ();
    lcd.print ("HI OWNER");
}

// -----------------------------------------------------------------------------
void loop()
{
    msec = millis ();

    char key = keypad.getKey();

    if (! key)  {
        if (msec - msecLst > msecPeriod) {
            msecLst    = msec;
            msecPeriod = OneSecond;
            displaytime();
        }

        return;
    }

    msecPeriod = TenSecond;

    switch (key) {
    case 0:
        break;

    case '0'...'9':
        val = 10*val + key - '0';
        break;

    case '*':
        val = 0;
        break;

    case '#':
        mode       = None;
        val        = 0;
        break;

    case 'A':
        mode = Fdings;
        break;
    }

    switch (mode)  {
    case Fdings:
        numfed = val;
        sprintf (s, "NO FEEDINGS %d", numfed);
        lcd.clear ();
        lcd.print (s);
        break;
    }
}

// -----------------------------------------------------------------------------
void displaytime()
{
    lcd.clear ();
    lcd.print (msec / 1000);
}

Thank you
This is what I have been kinda looking for. Thank you really

I would like to test your sketch in real setup. Would appreciate to know the outcomes of your sketch in the form of a Check List. I mean like this: do this, you will get/see this.

presumably you mean requirements?

there are several "flaws" in the code i posted, but it presumably demonstrate what the OP may want

  • by default, a time is updated every second (millis()/1000)
  • any key (e.g. 0-9) will suppress the reporting of time, but unless the key is something that sets "mode" (e.g. 'A') nothing is updated on the display
  • pressing the 'A' button sets mode to "Fding" which causes "NO FEEDINGS #" to be displayed.
  • the above always sets "numfed" to the "val" entered, so there's no way to see what "numfed" is set to
  • as number keys are pressed, the display should update, for example "NO FEEDINGS 3", "NO FEEDINGS 34"
  • pressing the '*" key clears resets "val"
  • pressing the '#' key clears the mode and resets "val", but not the time that the display of time is suppressed for
  • the mode and timeout will be reset after 10 seconds if no key is pressed for that time

the "flaws" can easily be fixed

1 Like

Excellent Check List. I will try to experiment it in my UNO, fix the possible bugs/flaws and report the result.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.