/*
Forum: https://forum.arduino.cc/t/check-for-4-buttons-being-pressed-when-1-button-pressed-cancel-other-3/1424266
Wokwi: https://wokwi.com/projects/452690693128804353
ec2021
Example for reading four buttons after being released by one
master button (black)
The sketch uses a button class that can be used for bouncing
buttons, however in this specific case debounceTime is set to
zero as each button press (master or player) changes the state
of the state machine so that any bouncing becomes irrelevant.
BtnClass provides the ability to read the press time in millis()
so that even very close presses of buttons can be evaluated
down to the millisecond (while having two buttons pressed that
close is very unlikely). However this feature allows to calculate
the time between the release by the master button and the player's
reaction.
*/
constexpr unsigned long debounceTime {0};
constexpr byte ledPin {9};
constexpr byte masterPin {8};
constexpr byte playerPin[] {2, 3, 4, 5};
constexpr int players = sizeof(playerPin) / sizeof(playerPin[0]);
enum class GAME {IDLE, PLAY, FINISHED};
GAME state = GAME::IDLE;
class BtnClass {
private:
byte pin;
byte state;
byte lastState;
unsigned long lastChange;
unsigned long lastPressTime;
public:
init(byte p) {
pin = p;
pinMode(pin, INPUT_PULLUP);
lastPressTime = 0;
}
unsigned long getLastPressTime() {
return lastPressTime;
};
void reset() {
lastPressTime = 0;
}
boolean pressed() {
byte actState = digitalRead(pin);
if (actState != lastState) {
lastChange = millis();
lastState = actState;
};
if (actState != state && millis() - lastChange > debounceTime) {
state = actState;
if (!state) lastPressTime = lastChange;
return !state;
}
return false;
}
};
BtnClass master;
BtnClass player[players];
void setup() {
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
master.init(masterPin);
for (int i = 0; i < players; i++) {
player[i].init(playerPin[i]);
}
}
void loop() {
stateMachine();
}
void stateMachine() {
switch (state) {
case GAME::IDLE:
if (master.pressed()) {
digitalWrite(ledPin, HIGH);
state = GAME::PLAY;
for (int i = 0; i < players; i++) {
player[i].reset();
}
}
break;
case GAME::PLAY:
for (int i = 0; i < players; i++) {
if (player[i].pressed()) {
digitalWrite(ledPin, LOW);
state = GAME::FINISHED;
}
}
break;
case GAME::FINISHED:
for (int i = 0; i < players; i++) {
if (player[i].getLastPressTime() > 0) {
Serial.print("Player ");
Serial.print(i + 1);
Serial.print(" pressed after ");
Serial.println(player[i].getLastPressTime() - master.getLastPressTime());
}
}
state = GAME::IDLE;
break;
}
}