In short, I am attempting to debounce several buttons using something like a while loop instead of delays.
This code runs in a box with a series of buttons on it, if the correct sequence of buttons is pressed, then the arduino will run a flashing LED sequence and open a solenoid. There are two correct sequences, a "right" answer (Green LED), and a master code (Blue LED). Anything else results in the failed sequence (Red LED). The problem I am currently having is that my current debouncing system is very finicky, I would like to implement something allowing more flexibility for speed of button press etc.
The problem currently is I am relying on delay to debounce. If I delay long enough it becomes difficult to type the correct code in because the user has to know to wait a certain amount of time before pressing the next key. If I do not delay long enough my combination is regularly corrupted with extraneous button pushes.
Below is my code, The debouncing occurs on lines 128-160. Below that is a lot of LED flashing.
#define CPU_RESTART_ADDR (uint32_t *)0xE000ED0C
#define CPU_RESTART_VAL 0x5FA0004
#define CPU_RESTART (*CPU_RESTART_ADDR = CPU_RESTART_VAL);
const int button5 = 2; //fifth button is on pin 2
const int button4 = 3; //fourth button is on pin 3
const int button3 = 4; //third button is on pin 4
const int button2 = 5; //second button is on pin 5
const int button1 = 6; //first button is on pin 6
const int systemLED = 7; //Red LED on front of Box (Power Indicator)
const int redLed1 = 8; //red LED is on pin 7
const int greenLed1 = 9; //green LED is on pin 8
const int blueLed1 = 10; //blue LED is on pin 9
const int redLed2 = 11; //red LED is on pin 10
const int greenLed2 = 12; //green LED is on pin 11
const int blueLed2 = 13; //blue LED is on pin 12
const int solenoid = 14; //activates solenoid Relay Circuit
const int relay2 = 15; // >:-}
int code[] = {1,2,3,4,5}; //the desired code is entered in this array, separated by commas
int entered[5]; //create a new empty array for the code entered by the user (has 4 elements)
void setup(){ //run once at sketch startup
Serial.begin(9600); //begin Serial
pinMode(systemLED, OUTPUT);
pinMode(button1, INPUT); //button 1 is an input
pinMode(button2, INPUT); //button 2 is an input
pinMode(button3, INPUT); //button 3 is an input
pinMode(button4, INPUT); //button 4 is an input
pinMode(button5, INPUT); //button 5 is an input
pinMode(redLed1, OUTPUT); //the red LED is an output
pinMode(redLed2, OUTPUT); //the red LED is an output
pinMode(greenLed1, OUTPUT); // the green LED is an output
pinMode(greenLed2, OUTPUT); // the green LED is an output
pinMode(blueLed1, OUTPUT);
pinMode(blueLed2, OUTPUT);
pinMode(relay2, INPUT_PULLUP); //enable relay outputs as input_pullup in order to prevent triggering when initial power is provided
pinMode(solenoid, INPUT_PULLUP);
delay(500);
pinMode(relay2, OUTPUT); //convert pinmode for relay back to operable mode
pinMode(solenoid, OUTPUT);//this prevents the relay and relay2 from triggering at startup
digitalWrite(relay2, HIGH);
digitalWrite(solenoid, HIGH);
digitalWrite(blueLed1, HIGH); //turn both
digitalWrite(greenLed1, HIGH);
digitalWrite(blueLed2, HIGH);
digitalWrite(greenLed2, HIGH); //LEDs on
delay(100); //wait
digitalWrite(blueLed1, LOW); //turn both
digitalWrite(greenLed1, LOW);
digitalWrite(blueLed2, LOW);
digitalWrite(greenLed2, LOW); //LEDs off
digitalWrite(systemLED, HIGH); //turn the red LED on
delay(75); //wait
for (int i = 0; i < 5;i++){ //work through numbers 0-4
Serial.println(code[i]); //print each digit of the code
Serial.println(entered[i]); //print each element of the entered[] array (this was for me to check that it started at 0)
}
}
void checkEntered1(int button /* define the 1,2,3 or 4 as an integer called button */){ //check the first element of the entered[] array
if (entered[0] != 0){ //if it is not a zero, i.e. it has already been input
checkEntered2(button); //move on to checkEntered2, passing it "button"
}
else if(entered[0] == 0){ //if it is zero, i.e. if it hasn't been defined with a button yet
entered[0] = button; //set the first element as the button that has been pressed
Serial.print("1: ");Serial.println(entered[0]); //for debugging
}
}
void checkEntered2(int button){ //check the second element of the entered[] array
if (entered[1] != 0){ //if it is not a zero, i.e. it has already been input
checkEntered3(button); //move on to checkEntered3, passing it "button"
}
else if(entered[1] == 0){ //if it is zero, i.e. if it hasn't been defined with a button yet
entered[1] = button; //set the second element as the button that has been pressed
Serial.print("2: ");Serial.println(entered[1]); //for debugging
}
}
void checkEntered3(int button){ //check the third element of the entered[] array
if (entered[2] != 0){ //if it is not a zero, i.e. it has already been input
checkEntered4(button); //move on to checkEntered4, passing it "button"
}
else if (entered[2] == 0){ //if it is zero, i.e. if it hasn't been defined with a button yet
entered[2] = button; //set the third element as the button that has been pressed
Serial.print("3: ");Serial.println(entered[2]); //for debugging
}
}
void checkEntered4(int button){ //check the fourth element of the entered[] array
if (entered[3] != 0){ //if it is not a zero, i.e. it has already been input
checkEntered5(button); //set the final element as the button that has been pressed
}
else if (entered[3] == 0){ //if it is zero, i.e. if it hasn't been defined with a button yet
entered[3] = button; //set the fourth element as the button that has been pressed
Serial.print("4: ");Serial.println(entered[3]); //for debugging
}
}
This is where I need help debouncing, as can be seen I have attempted to debounce with delay(75)
originally I had delay(1000)
as the debounce which worked but required the user to wait or break normal rhythm while entering the code due to the long delay between inputs being accepted.
void checkEntered5(int button){ //check the fifth element of the entered[] array
if (entered[4] == 0){ //if it is zero, i.e. if it hasn't been defined with a button yet
entered[4] = button; //set the final element as the button that has been pressed
Serial.print("5: ");Serial.println(entered[4]); //for debugging
delay(100); //allow time for processing
compareCode(); //call the compareCode function
}
}
void loop(){ //run repeatedly
if (digitalRead(button1) == HIGH){ //if button1 is pressed
checkEntered1(1); //call checkEntered and pass it a 1
//delay(1000); //wait
while( digitalRead(button1) == HIGH) { } // do nothing
delay(75);//wait, needed for correct functioning, otherwise
//buttons are deemed to be pressed more than once
}
else if (digitalRead(button2) == HIGH){ //if button2 is pressed
checkEntered1(2); //call checkEntered1 and pass it a 2
//delay(1000); //wait
while( digitalRead(button2) == HIGH) { } // do nothing
delay(75); //wait
}
else if (digitalRead(button3) == HIGH){ //if button3 is pressed
checkEntered1(3); //call checkEntered1 and pass it a 3
//delay(1000); //wait
while( digitalRead(button3) == HIGH) { } // do nothing
delay(75); //wait
}
else if (digitalRead(button4) == HIGH){ //if button4 is pressed
checkEntered1(4); //call checkEntered1 and pass it a 4
//delay(1000); //wait
while( digitalRead(button4) == HIGH) { } // do nothing
delay(75); //wait
}
else if (digitalRead(button5) == HIGH){ //if button4 is pressed
checkEntered1(5); //call checkEntered1 and pass it a 5
//delay(1000); //wait
while( digitalRead(button5) == HIGH) { } // do nothing
delay(75); //wait
}
}
Everything below this point is included simply to provide context for the check entered code seen above. Everything functions as is expected except that the debounce is imperfect.
void compareCode(){ //checks if the code entered is correct by comparing the code[] array with the entered[] array
for (int i = 0; i<4;i++){
Serial.write(entered[i]);
}
if ((entered[0]==code[0]) && (entered[1]==code[1]) && (entered[2]==code[2]) && (entered[3]==code[3]) && (entered[4]==code[4])){ //if all the elements of each array match the passcode
//--. .-. . . -.
digitalWrite(solenoid, LOW);
digitalWrite(greenLed1, HIGH); //turn the green LED on
digitalWrite(greenLed2, HIGH); //turn the green LED on
delay(50); //wait for a bit
digitalWrite(greenLed1, LOW); //turn the green LED off
digitalWrite(greenLed2, LOW); //turn the green LED off
delay(500);
digitalWrite(solenoid, HIGH);
delay(2500);
}
else if ((entered[0]==code[4]) && (entered[1]==code[2]) && (entered[2]==code[0]) && (entered[3]==code[3]) && (entered[4]==code[1])){
//-... .-.. ..- .
digitalWrite(blueLed1, HIGH);
digitalWrite(blueLed2, HIGH);
delay(1000);
digitalWrite(solenoid, LOW);
delay(4000);
digitalWrite(blueLed1, LOW);
digitalWrite(blueLed2, LOW);
delay(50);
digitalWrite(redLed1, HIGH);
digitalWrite(redLed2, HIGH);
delay(1000);
digitalWrite(redLed1, LOW);
digitalWrite(redLed2, LOW);
delay(50);
digitalWrite(solenoid, HIGH);
delay(1000);
}
else { //if you (or the intruder) get the code wrong
flash(); //call the flash function
for (int i = 0; i < 4; i++){ //this next loop is for debugging
entered[i] = 0;
Serial.println(entered[i]);
}
}
}
void flash(){ // this is basically the blink example
//.-. . -..
digitalWrite(relay2, LOW);
digitalWrite(redLed1, HIGH);
digitalWrite(redLed2, HIGH);
delay(50);
digitalWrite(redLed1, LOW);
digitalWrite(redLed2, LOW);
delay(250);
digitalWrite(redLed1, HIGH);
digitalWrite(redLed2, HIGH);
delay(50);
digitalWrite(redLed1, LOW);
digitalWrite(redLed2, LOW);
digitalWrite(relay2, HIGH);
delay(2500);
CPU_RESTART;