Question about 4x4 keypad code and input codes

Hi. So i have a program i have written for stepper motors and motor movement, and now i’m trying to incorporate a keypad and lcd into this project. I borrowed some code from a secret code entry using a keypad because that’s about the only examples i could find using a keypad, so i added more code under the checkKey() to look for other numbers. What i’m looking to do is there are several settings in my stepper program that i’d like to easily changed, mainly just speeds, and possibly how many steps to take in certain cases, and i plan to have a setup code for each setting that i can manually change whenever i want.

below is my code that i’ve put together, and i know it’s not pretty, but for the moment it’s working enough i can show someone what i’m trying to do, but i’m trying to figure it out. What i was curious was is there a better way to rewrite checkKey() so it will check the input codes to see if it’s correct, which gives me the serial option input for the change… or is this basically how it’s done?

thanks

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


const byte ROWS = 4; 
const byte COLS = 4; 
char keys[ROWS][COLS] =
{
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {46, 48, 50, 52}; 
byte colPins[COLS] = {47, 49, 51, 53}; 


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

LiquidCrystal_I2C lcd(0x3F,20,4);

char KEY[4] = {'1','2','3','4'};    // default secret key
char KEY2[4] = {'4','3','2','1'};
char KEY3[4] = {'2','2','2','2'};

  char attempt[4] = {0,0,0,0};

int z=0;
int stepSpeed;

void setup(){
  
   Serial.begin(115200);

  lcd.init();
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("stepSpeed #");

     
   }

void correctKEY(){                     // do this if the correct KEY is entered

 
       Serial.println(" KEY ACCEPTED...");
       Serial.println(" ");
     Serial.print(" Manual Speed Change;  1-200");
    while (Serial.available()==0) {   }
       stepSpeed = Serial.parseInt();
    while (Serial.available() != 0 ) {Serial.read();}
         Serial.print("      #");
         Serial.print(stepSpeed);
         Serial.println(" ");
     
      lcd.setCursor(12,0);
      lcd.print(stepSpeed);
   }

void correctKEY2(){                     // do this if the correct KEY is entered

   Serial.println(" KEY2 ACCEPTED...");
   }

void correctKEY3(){                    // do this if the correct KEY is entered
   Serial.println("KEY3 ACCEPTED...");
   }

void checkKEY(){
  
   int correct=0;
   int correct2=0;
   int correct3=0;
   int i;
     for ( i = 0; i < 4 ; i++ ){
          
          if (attempt[i]==KEY[i]){
             correct++;
         }
         
         if (attempt[i]==KEY2[i]){
            correct2++;
         }

          if (attempt[i]==KEY3[i]){
              correct3++;
         }
          
      }
   
    if (correct==4){
  
      correctKEY();
      }
     if (correct2==4){
      
      correctKEY2();
      }
     if (correct3==4){
      
      correctKEY3();
     }



    for (int zz=0; zz<4; zz++){             // clear previous key input
      
      attempt[zz]=0;
     }
}
void readKeypad(){
  
   char key = keypad.getKey();
   
   if (key != NO_KEY){
    
      switch(key){
        
      case '*':
         z=0;
         break;
      case '#':
         delay(100);                         // added debounce
        checkKEY();
         break;
        default:
           attempt[z]=key;
          z++;
      }
   }
}
void loop(){
  
   readKeypad();
}

[code\]

Code written like that is difficult to change and maintain. You want to make your check function take a key sequence to compare to the attempt as a parameter. That way you never have to change the code no matter how many sequences you have.

If you store the key sequences in a two dimensional array instead of separate arrays it will be easy to add and remove sequences from the program. Compare the attempt to each sequence in the array and stop when you have a match.

Demo code blow to demonstrate what I’m talking about.

// sequence size
const byte SEQ_SIZE = 4;

// all valid key sequences
char keys[][SEQ_SIZE] = {{'1', '2', '3', '4'}, {'4', '3', '2', '1'}, {'2', '2', '2', '2'}};

char attempt[SEQ_SIZE] = {0, 0, 0, 0};

// # of sequences
const byte  NUM_SEQ = sizeof(keys) / sizeof(keys[0]);


void setup()
{
  Serial.begin(9600);


  // copy sequence
  int seq = 0;       // set this to 0, 1 or 2 to test
  for (int i = 0; i < SEQ_SIZE; i++) attempt[i] = keys[seq][i];

  // check for each sequence
  for ( int i = 0; i < NUM_SEQ; i++)
  {
    // found sequence?
    if ( checkKeys(keys[i]) )
    {
      // do whatever the key sequence calls for
      gotSequence(i);
      break;

    } // if

  } // for

}


void gotSequence(int sNum)
{
  // print which sequence was read
  Serial.print("Got sequence ");
  Serial.print(sNum);

}

// return true if attempt matches passed sequence
bool checkKeys(char k[])
{
  int idx;

  // look at each key
  for (idx = 0; idx < SEQ_SIZE; idx++)
  {

    // stop on first mismatch
    if ( k[idx] != attempt[idx] ) break;

  } // for

  // got sequence if all keys were compared
  return (idx == SEQ_SIZE);

}


void loop() {}

I would write a function that just reads a userEntry from the keypad. As an example

/*
  read user entry from keypad into global userEntry variable
  Returns:
    true if completed, else false
*/
bool readUserEntry()
{
  // index where to store character in userEntry array
  static uint8_t idx = 0;

  // read key
  char key = keypad.getKey();

  if (key != NO_KEY)
  {
    // add to userEntry and increment index
    userEntry[idx++] = key;
  }

  // if all characters entered
  if (idx == NUMELEMENTS(userEntry))
  {
    // reset index for next time
    idx = 0;
    // indicate we have required number of keys
    return true;
  }
  else
  {
    // indicate that we haven't got the number of chars yet
    return false;
  }
}

For this to work, add the below before setup()

// a macro that gives the number of elements in any type of array
#define NUMELEMENTS(x) (sizeof(x)/sizeof(x[0]))

#include <Keypad.h>

const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] =
{
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {46, 48, 50, 52};
byte colPins[COLS] = {47, 49, 51, 53};


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


// array to store user entry from keypad
char userEntry[4];

// passwords that give access
char passwords[][NUMELEMENTS(userEntry)] =
{
  {'1', '2', '3', '4'},
  {'2', '2', '3', '3'},
  // add more here
};

loop() that makes use of the readUserEntry() function; it uses memcmp to compare the user entry against the known passwords.

void loop()
{
  bool found = false;
  // if user completed the entry
  if (readUserEntry() == true)
  {
    // loop through all valid passwords
    for (uint8_t pwdCount = 0; pwdCount < NUMELEMENTS(passwords); pwdCount++)
    {
      // compare with user entry
      if (memcmp(passwords[pwdCount], userEntry, NUMELEMENTS(userEntry)) == 0)
      {
        found = true;
      }
    }
  }
  
  if(found == true)
  {
    // do whatever needs to be done
    Serial.println(F("Access granted"));
  }
}

And the simple demo setup()

void setup()
{
  Serial.begin(57600);
}

Not tested, but does compile.

Thanks for the info. I’m gonna play with them to see if i can get it figured out. so how would i get each sequence to do something different? That’s what i was looking for, which is why i originally had them in different arrays but wasn’t sure if that was right. but once their written in code, the sequences themselves won’t be changed like a password or the such, the command behind the sequence may be modified a little until i get everything lined out, and then it won’t be messed with much