Array comparison and debounce of multiple buttons

Hi guys,

I’m new to coding and have managed to come up with a working sketch, but it doesn’t look pretty and I’m sure there’s a better way to achieve this. It’s used for a puzzle box with three buttons, where the user has to press the buttons in the right sequence to open the box.

I found a similar thread on here but the final part, comparing the arrays, didn’t work for me. I know it can be achieved with a for loop, but I don’t know how yet.

Here’s what I have so far:

const int buttonPin1 = 10;
const int buttonPin2 = 11;
const int buttonPin3 = 12;
const byte ledRed = 5;
const byte ledGreen = 4;

unsigned long lastDebounceTime1 = 0; // I could only get the debounce to work if I use three variables
unsigned long lastDebounceTime2 = 0;
unsigned long lastDebounceTime3 = 0;
unsigned long debounceDelay = 80;

// changing variables
byte buttonState1 = 0;
byte buttonState2 = 0;
byte buttonState3 = 0;
byte lastButtonState1 = 0;
byte lastButtonState2 = 0;
byte lastButtonState3 = 0;

int pwcount = 0;
int arrUser[6]; // will hold user input

void setup() {
  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);
  pinMode(buttonPin3, INPUT);
  pinMode(ledRed, OUTPUT);
  pinMode(ledGreen, OUTPUT);
  Serial.begin(9600);
}

void loop() {
// read initial buttonStates
  buttonState1 = digitalRead(buttonPin1); 
  buttonState2 = digitalRead(buttonPin2);
  buttonState3 = digitalRead(buttonPin3);

// write user input into arrUser
  if ( (millis() - lastDebounceTime1) > debounceDelay) {
    if (buttonState1 != lastButtonState1) {
      if (buttonState1 == HIGH) {
        arrUser[pwcount] = 1;
        pwcount++;
        delay(200);
        Serial.println(F("1"));
      }
    }
    lastButtonState1 = buttonState1;
    lastDebounceTime1 = millis(); //set the current time
  }

  if ( (millis() - lastDebounceTime2) > debounceDelay) {
    if (buttonState2 != lastButtonState2) {
      if (buttonState2 == HIGH) {
        arrUser[pwcount] = 2;
        pwcount++;
        delay(200);
        Serial.println(F("2"));
      }
    }
    lastButtonState2 = buttonState2;
    lastDebounceTime2 = millis(); //set the current time
  }

  if ( (millis() - lastDebounceTime3) > debounceDelay) {
    if (buttonState3 != lastButtonState3) {
      if (buttonState3 == HIGH) {
        arrUser[pwcount] = 3;
        pwcount++;
        delay(200);
        Serial.println(F("3"));
      }
    }
    lastButtonState3 = buttonState3;
    lastDebounceTime3 = millis(); //set the current time
  }

//compare arrays
  if (arrUser[0] == 1 && arrUser[1] == 2 && arrUser[2] == 3 && arrUser[3] == 1 && arrUser[4] == 2 && arrUser[5] == 3 && pwcount >= 6) {
    digitalWrite(ledGreen, HIGH);
    Serial.println(F("Correct"));
    pwcount = 0;
    delay(2000);
    digitalWrite(ledGreen, LOW);
  }
  else if (pwcount >= 6) {
    digitalWrite(ledRed, HIGH);
    Serial.println(F("Wrong"));
    pwcount = 0;
    delay(2000);
    digitalWrite(ledRed, LOW);
  }
}

tl;dr

  1. I thought I could improve the array comparision with this, but it didn’t work.
for(byte n = 0; n <=6; n++){
    if (arrUser[pwcount] == arrPw[pwcount] && pwcount >=6){
      statement
 }}
  1. Is there a better way to debounce multiple buttons?

I’m thankful for any input!!

If you have multiple identical complicated things, then classes are the way to go. Have a look at the page in my sig block.

Thanks for brining that up, certainly looks like a nice way to code and to debounce multiple buttons! Any ideas regarding the for-loop to compare arrays? :)

What about memcmp(…) ?

Something like:

int arrUser[6] ;
int arrPw[6] ;
void setup() {}
void loop()
{
	int result = memcmp(arrUser,arrPw,sizeof arrPw) ;
	/*
	 * if result == 0 then there is a match.
	 * if result != 0 then there is not a match.
	 * (If necessary, more details are available by
	 *  determining whether result is >0 or <0 .)
	 */
}

Use a search engine (such as Google) to look for memcmp for more details. I used information at memcmp - C++ Reference

The array comparison that you wrote is not correct because you let “n” go to 6 and the highest legal array index is 5. It seems to me that you do not want to do any comparison until there have been exactly 6 button presses, so you should not do any comparisons unless pwcount is 6.

To debounce multiple buttons you could keep an array of structures with all the button information and then call a function in loop() with an index into the array that does just what you are already doing.

Below is some sample code that is my translation from your code to my suggestions. It gets information on button presses until 6 are read and compares the presses to the correct sequence.

[EDIT] Fixed two mistakes based on OP’s feedback.

const int numButtons = 3;
unsigned long debounceDelay = 80;
const int pwLen = 6;
int pwcount = 0;
int arrUser[pwLen]; // will hold user input
int arrPw[pwLen] = {1, 2, 3, 1, 2, 3};
const byte ledRed = 5;
const byte ledGreen = 4;

const int buttonPins[numButtons] = {10, 11, 12};

// structure to hold info for one button
typedef struct {

  int pin;
  unsigned long lastDebounceTime;
  byte buttonState;
  byte lastButtonState;

} buttonInfo;

buttonInfo buttons[numButtons];   // info for all buttons

// Initialize info for all buttons
void initButtons()
{
  for (int i = 0; i < numButtons; i++)
  {
    buttons[i].pin = buttonPins[i];
    pinMode(buttons[i].pin, INPUT);
    buttons[i].lastDebounceTime = 0UL;
    buttons[i].buttonState = 0;

  } // for
}

// check status of a button
void checkButton(int idx)
{
  // read button pin
  buttons[idx].buttonState = digitalRead(buttons[idx].pin);

  if ( (millis() - buttons[idx].lastDebounceTime) > debounceDelay) {
    if (buttons[idx].buttonState != buttons[idx].lastButtonState) {
      if ( buttons[idx].buttonState == HIGH) {
        arrUser[pwcount] = idx + 1;
        pwcount++;
        delay(200);
        Serial.println(idx+1);
      }
    }
    buttons[idx].lastButtonState = buttons[idx].buttonState;
    buttons[idx].lastDebounceTime = millis(); //set the current time
  }



}



void setup() {

  initButtons();  // initialize buttons

  pinMode(ledRed, OUTPUT);
  pinMode(ledGreen, OUTPUT);
  Serial.begin(9600);

}

void loop() {

  int i;

  // check sateus of each button
  for (i = 0; i < numButtons; i++) checkButton(i);

  // if we have enough button presses
  if ( pwcount == pwLen )
  {
    bool success = true;

    // check each value
    for ( i = 0; i < pwLen; i++ )
    {
      if ( arrUser[i] != arrPw[i] )
      {

        success = false;  // sequence not correct
        break;            // stop comparing

      } // if
    } // for

    if ( success )
    {
      digitalWrite(ledGreen, HIGH);
      Serial.println(F("Correct"));
      delay(2000);
      digitalWrite(ledGreen, LOW);

    } else {

      digitalWrite(ledRed, HIGH);
      Serial.println(F("Wrong"));
      delay(2000);
      digitalWrite(ledRed, LOW);
    }

    pwcount = 0;

  } // if

}

2) Is there a better way to debounce multiple buttons?

I like to use the Bounce2 library for multiple buttons.

Wow, thank you so much guys!

@vaj4088, that worked like a charm and looks super easy. I'll keep this one in mind for future projects!

@Blue Eyes, wow, pretty impressive sketch! Thanks a lot for translating my nooby sketch into something professional. I'll have a thorough look at it when I get home tonight. Seems like I could learn a lot from your sketch and that's exactly what I was hoping for by coming here. So thank you!

@cattledog, thanks for the hint! Seems like yet another easy soultion for the problem. Thanks!

@Blue Eyes, I couldn't wait and just went through everything in your sketch.

There were two tiny mistakes: Serial.println(F("1")idx + 1); ... if ( arrUser != arrPw[1i] ) But now it's working like a charm and most of all, I learned a ton from it, so thanks a bunch!