Detect if one of several buttons stays pressed

Hello,

A few days ago I posted another question on this forum and I got the following bit of code in response.

#include <Bounce2.h>

const byte buttonPins[] = {2, 3, 4, 5, 6, 7, 8, 9}; //now you can select any pin in any order
bool state = false;

Bounce buttons[sizeof(buttonPins)];

void setup () {
  for (byte i = 0; i < sizeof(buttonPins); i++) {
    buttons[i].attach(buttonPins[i], INPUT_PULLUP);
  }

    Serial.begin(9600);
    Serial.println("start");
}

void loop() {
  updateButtons();
 
  Serial.println(state); // prints a 1 or 0 so I can see if the value switched
}

void updateButtons(){
  for (byte i = 0; i < sizeof(buttonPins); i++) {
    buttons[i].update();
    //if a button is pressed but did not became pressed we skip checking for buttons becomming pressed
    if(!buttons[i].read() && !buttons[i].fell()){
      return;
    }
  }
  //otherwise we check for a button becomming pressed
  for (byte i = 0; i < sizeof(buttonPins); i++) {
    if (buttons[i].fell()) {
      state = !state;
      return;
    }
  }
}

I did not need this particular bit of code at the time as I did not care if a button was pressed while another button is pressed.

However I thought I could modify this bit of code to detect when a button would be pressed for 5 seconds and then trigger a action accordingly.

With my modifications I came to the following bit of code.

#include <Bounce2.h>              // library that handles all the debouncing
#include <elapsedMillis.h>        // library to keep track of millis

const int number_of_channels=10; //512 for 512 channels lower if you need both a reciever and sender 
byte buffer_channel_arduino[number_of_channels]; //buffer to store filetered DMX data

//create a array of the button pins
const byte defaultbuttonPins[] = {2, 3, 4, 5, 6, 7, 8, 9}; //now you can select any pin in any order
const byte control_channel = 0; // the control channels number 0=1 1=2 etc etc
bool state = false; // set the first state to false 

// bit of code that keeps track of timings
elapsedMillis button_held_down; // millis button is held down counts here
int button_hold_time = 5000; // button hold time is at 10 seconds

Bounce defaultbuttonsoverride[sizeof(defaultbuttonPins)]; //creates the buttons variable and links it to the bounce library

void setup() {
    for (byte i = 0; i < sizeof(defaultbuttonPins); i++) // creates byte i for 0 to the size of the defaultbuttonPins array 
  {
    defaultbuttonsoverride[i].attach(defaultbuttonPins[i], INPUT_PULLUP);
  }
  Serial.begin(9600);
}

void loop()
{
  artnet_override();
  Serial.println(button_held_down);
}


void artnet_override()
{
  for (byte i=0;i<sizeof(defaultbuttonPins); i++) 
  {
    defaultbuttonsoverride[i].update(); //defaultbuttonsoverride is needed otherwise all values are stored in same part
    if(!defaultbuttonsoverride[i].read() && !defaultbuttonsoverride[i].fell()) //if the button was low and still is low continue
    {
      if (button_held_down > button_hold_time) // if the button is hold for the time programmed then continue
      {
        buffer_channel_arduino[control_channel] = 0; // sets the control channel value to 0 thus allowing control by the buttons again
        state = false;   // sets the state to false so the output dmx value becomes 0
      }
      return;  // no clue why return needs to be here but it won't work without it
    }
    else
    {
      button_held_down = 0; // if button is not held down keep resetting the counter to 0
    }
  }
}

with this bit of code when you have a button connected to pin 3 you can keep this button pressed and the button_held_down value will rise till it reaches 5000 and is reset back to 0 (ofcourse I trigger another action in my code but this is for testing).

At this point I was happy as I thought the code functions as intended however when I tried to do it with a button connected to any of the other pins the counter does not start to rise.

I am guessing that there is a problem with the value of button 0 overwriting the value of for example button 3 on a loop.

Also why do I need to use return;? otherwise the code does not work.

You need full state for each button, ie use an array for button_held_down and state, so that
each button acts independently.

You'll eventually see that the nicest approach is to wrap all the state for a button into a struct
or class, and have an array of them that you process in loop(). Then the code can be turned
into a library that you can use in any sketch easily.

Hint: other people may already have done this and created button handling libraries that might
do what you want - things like detecting long presses, double clicks, plus deboucing and so forth.

Worth having a search around - even if a library doesn't do all you want you could extend it...

Thank you for pointing me in the right direction.

I have modified my code so that it now works for all the buttons.

I'm certain that there are better ways to do it and I am planning on comming back to this code to do just that.

For anyone wondering what changes I made this is my new code.

#include <Bounce2.h>              // library that handles all the debouncing
#include <elapsedMillis.h>        // library to keep track of millis

const int number_of_channels=10; //512 for 512 channels lower if you need both a reciever and sender
byte buffer_channel_arduino[number_of_channels]; //buffer to store filetered DMX data

//create a array of the button pins
const byte defaultbuttonPins[] = {2, 3, 4, 5, 6, 7, 8, 9}; //now you can select any pin in any order
const byte held_button_array[] = {2, 3, 4, 5, 6, 7, 8, 9};
const byte control_channel = 0; // the control channels number 0=1 1=2 etc etc
bool state = false; // set the first state to false

// bit of code that keeps track of timings
elapsedMillis button_held_down[sizeof(held_button_array)]; // millis button is held down counts here
int button_hold_time = 5000; // button hold time is at 10 seconds

Bounce defaultbuttonsoverride[sizeof(defaultbuttonPins)]; //creates the buttons variable and links it to the bounce library

void setup() {
    for (byte i = 0; i < sizeof(defaultbuttonPins); i++) // creates byte i for 0 to the size of the defaultbuttonPins array
  {
    defaultbuttonsoverride[i].attach(defaultbuttonPins[i], INPUT_PULLUP);
  }
  Serial.begin(9600);
}

void loop()
{
  artnet_override();
  for (byte i=0;i<sizeof(defaultbuttonPins); i++)
  Serial.println(button_held_down[i]);
}


void artnet_override()
{
  for (byte i=0;i<sizeof(defaultbuttonPins); i++)
  {
    defaultbuttonsoverride[i].update(); //defaultbuttonsoverride is needed otherwise all values are stored in same part
    if(!defaultbuttonsoverride[i].read() && !defaultbuttonsoverride[i].fell()) //if the button was low and still is low continue         
      {
      if (button_held_down[i] > button_hold_time) // if the button is hold for the time programmed then continue
      {               
        buffer_channel_arduino[control_channel] = 0; // sets the control channel value to 0 thus allowing control by the buttons again
        button_held_down[i] = 0;
        state = false;   // sets the state to false so the output dmx value becomes 0        
      }
      return;  // no clue why return needs to be here but it won't work without it    
    }
    else
    {
      button_held_down[i] = 0; // if button is not held down keep resetting the counter to 0
    }
  }
}