4 buttons with separate button press detection, resulting action and display
This is the most complex version of the code presented here, and should only be studied when the earlier versions are properly understood. In larger sketches it can be useful to divide code up into smaller functions to make it tidy and make it easy to identify which bit of code does what. While not particularly necessary for the small sketches used here for demonstration purposes, this version of the code is split into 2 separate functions to deal with reading and debouncing the buttons then taking some action and displaying or printing the results. Each completed action is signalled to the next function by setting a flag. Only when the subsequent function detects a set flag does it carry out its task. This version uses the 4 button circuit in the previous version, and the output is exactly the same.
/* Debounce for multiple push to make buttons wired between ground (0V) and buttonPin */
/* This version separates the task of debouncing buttons from the subesqent action */
/* This is the most advanced version of the code and might be confusing if you are new to writing code */
/* Tested on a Nano Every, should work on any Arduino */
const uint8_t buttonPin[] = {2, 3, 4, 5}; // Inputs for buttons. On many Arduinos pins 0 and 1 are used for serial making pin 2 the first free pin.
const uint8_t buttonCount = 4; // Number of buttons.
bool buttonPressedFlag[buttonCount]; // Flags to indicate that a button has been detected as pressed and debounced
typedef void (* functionPtrs) (void);
functionPtrs functions[4] = {&buttonZero, &buttonOne, &buttonTwo, &buttonThree}; // Pointers to the above 4 functions, this is how a different function is selected depending on which button is pressed
void setup() {
Serial.begin(9600); // Start the serial monitor to see the results.
char fileName[] = {__FILE__};
Serial.println(fileName); // Prints the name of the file the location this sketch is in.
for (uint8_t i = 0; i < buttonCount; ++i) {
pinMode(buttonPin[i], INPUT_PULLUP); // Make the button pins inputs with the internal pull up resistor enabled.
}
}
void loop() {
Buttons(); // Calls the function to read the button.
doStuff(); // Does something in response to the input
// Your other code goes here, make sure it is non blocking (no delays, no loops that don't exit quickly)
}
/* This is the function that reads the state of the button, debounces it then sets a flag for the separate doStuff()function to do something */
void Buttons() {
#define buttonPressed LOW // When the button is pressed the input will be low, this is to remove the confusion this migth cause.
uint32_t currentMillis = millis(); // Millis times uses to debounce the button
static uint32_t lastMillis[buttonCount]; // Start of the debounce timeout for each button
const uint32_t bounceTimeout = 20; // Debounce time in milliseconds
bool currentButtonState[buttonCount]; // Holds the current state of each button
static bool lastButtonState[buttonCount]; // Holds the previous debounced state of the button
uint8_t i;
for (i = 0; i < buttonCount; ++i) {
currentButtonState[i] = digitalRead(buttonPin[i]); // Reads the current state of each button and saves the result
if (lastButtonState[i] != currentButtonState[i]) { // Checks to see if each button has been pressed or released, at this point each button has not been debounced
if (currentMillis - lastMillis[i] >= bounceTimeout) { // Checks to see if the state of each button has been stable for at least bounceTimeout duration
lastButtonState[i] = currentButtonState[i]; // At this point the button has been debounced, so save the last state
if (currentButtonState[i] == buttonPressed) { // The button might have been pressed or released, this make sure only presses are acted on, not releases
buttonPressedFlag[i] = true; // Button press has been detected and debounced, set a flag to indicate to the next function that some action can be taken
}
}
} else {
lastMillis[i] = currentMillis; // Saves the current value of millis in last millis so the debounce timer for each button starts from current millis
}
}
}
/* Selects one of the 4 functions buttonZero() etc depending on which button was pressed */
void doStuff() {
uint8_t i;
for (i = 0; i < buttonCount; ++i) {
if (buttonPressedFlag[i]) {
buttonPressedFlag[i] = false; // Clear the flag to ensure the action only happens once
functions[i](); // Calls one of the 4 functions depending on which button was pressed
}
}
}
// 4 functions, which are called depending on which button has been pressed
void buttonZero() {
Serial.println("Button 0 has been pressed"); // Your code for when button 0 is pressed goes here
}
void buttonOne() {
Serial.println("Button 1 has been pressed"); // Your code for when button 1 is pressed goes here
}
void buttonTwo() {
Serial.println("Button 2 has been pressed"); // Your code for when button 2 is pressed goes here
}
void buttonThree() {
Serial.println("Button 3 has been pressed"); // Your code for when button 3 is pressed goes here
}