How to prevent extra button pushes from interrupting millis() timed statement

I've created a simple circuit where I have an LED connected to one pin as an OUTPUT, and a push button connected to another pin as an INPUT.

WHAT HAPPENS CURRENTLY:

  1. The LED is normally on.
  2. When I push the button once, the LED turns off for 5 seconds then turns back on automatically.

THE ISSUE:
If I hold the button down or push it repeatedly after the LED has turned off, the LED stays off until I release the button or stop pushing it. I could theoretically hold the button down forever and the LED would stay off forever.

I'd like to figure out how to ignore any additional presses of the button (whether held down or pressed multiple times) during the 5 second timer in which the LED is off so that the LED turns back on after 5 seconds regardless. At this point the statement would reset and the button could be pushed again to turn off the LED again (or if the button was held down for the entire duration, then it could be released and pushed again).

My (inexperienced) hunch is when the ledState1 == LOW, if there was a way to stop the digitalRead of buttonPin1 until the 5 second timer ends. I feel like the solution could be stupidly simple and I'm just walking around it but I want to double check I'm not overlooking something more complicated here so I apologize in advance if that's the case!

Any help is greatly appreciated.

Here's the simplified code:

byte buttonState1 = 0;

byte buttonPin1 = 10;

byte ledPin1 = 13;

byte ledState1 = HIGH;

unsigned long previousMillis1 = 0;

long offTime1 = 5000;



void setup() {
 
  // Push button setup.
  pinMode(buttonPin1, INPUT);


  // LED output setup.
  pinMode(ledPin1, OUTPUT);

}



void loop() {
  

  // Start recording time.
  unsigned long currentMillis1 = millis();

  buttonState1 = digitalRead(buttonPin1);


  // Declare running state of LED where it is on and button is not pressed.
  if ((buttonState1 == LOW) && (currentMillis1 - previousMillis1 >= offTime1))  {
    ledState1 = HIGH;
    previousMillis1 = currentMillis1;
    digitalWrite(ledPin1, ledState1);
  }


  // Create condition where if button is pushed, the LED turns OFF for 5000ms, then turns back on.
  else if (buttonState1 == HIGH) {
    ledState1 = LOW;
    previousMillis1 = currentMillis1;
    digitalWrite(ledPin1, ledState1);
  }

You need to keep track of what state you are in (LED on & waiting for button push or LED off and waiting for delay to expire) and then act accordingly. Specifically, if you are waiting for the delay to happen, you ignore the state of the button.

An easy way to do this is to just use the delay() function which will effectively freeze your program for 500ms and then you can turn the led back on and go on your way.

It looks like you are trying to use the delay without millis() approach which is good if you every want your program to do other things while the 500ms is counting.

Right, so my original code will actually be powering 4 LEDs at once which is why I'm using the millis() function instead of delay. Each LED will have its own button but they will all act the same; i.e. if you push the button the corresponding LED turns off.

I guess I should've included this in my original question but ultimately the LEDs will be replaced with relays that will power fake fires (those halloween effect products that have little fans with LEDs and a piece of fabric that flutters in the wind) and there will be a fake fire hose with reed switches instead of buttons, that when pointed at each fire, turns the fire off for a period of time. It's for a "burning building" exhibit.

The point of having it be timed is if the person is unable to "put out" (turn off) all four fires within a certain amount of time, then they will all turn back on and "reset" if you will, so the next guest that approaches the exhibit can start from the beginning. If they do put out all of them within the set time, then there is a short celebration that happens (I've already figured out the celebration part).

Hopefully that clears some of it up. When the LED turns off, I want the Arduino to basically ignore any additional button presses (or reed switch senses) until the 5 second timer for the LED is up and it turns back on.

Have a look at the StateChangeDetection sketch. This code is the same, but expanded into arrays of buttons.

I'm not sure if a button is normally HIGH and goes LOW when pressed (typical) or the other way around since you did not provide a schematic. The logic may be reversed

const byte buttonPin[] = {10};
const byte totalPins = sizeof(buttonPin) / sizeof(buttonPin[0]);
byte lastButtonState[totalPins];
const byte ledPin[totalPins] = {13};   // must be same size as buttonPin[]
unsigned long previousMillis[totalPins];
const unsigned long offTime = 5000;   // make array if different for each LED

void setup() {
  Serial.begin(9600);
  while (!Serial);

  for (int i = 0; i < totalPins; ++i ) {
    pinMode(buttonPin[i], INPUT);    // assumed external pull-up resistors?  if not, use INTPUT_PULLUP
    pinMode(ledPin[i], OUTPUT);
    digitalWrite(ledPin[i], HIGH);
    previousMillis[i] = 0; // off
    lastButtonState[i] = digitalRead(buttonPin[i]);
  }
}

void loop() {

  unsigned long currentMillis = millis();     // Start recording time.

  // check if timers have expired
  // if a timer is 0, it is off
  for ( int i = 0; i < totalPins; ++i ) {
    if (previousMillis[i] != 0 && currentMillis - previousMillis[i] >= offTime) {
      // timer was running and has expired, turn LED back on and turn timer off
      previousMillis[i] = 0;    // signal timer off
      digitalWrite(ledPin[i], HIGH);
    }
  }

  // read the pushbuttons
  for (int i = 0; i < totalPins; ++i ) {
    int buttonState = digitalRead(buttonPin[i]);

    // compare the buttonState to its previous state
    if (buttonState != lastButtonState[i]) {
      if (buttonState == LOW) {
        // button was pushed so start timer if not already running
        // if timer is already running, do nothing (ignore button press)
        Serial.print("Button "); Serial.print(i); Serial.println(" pressed");
        if ( previousMillis[i] == 0 ) {
          previousMillis[i] = currentMillis;
          digitalWrite(ledPin[i], LOW);
        } else {
          // ignore button press so do nothing
        }
      } else {
        // button was released - do nothing
        Serial.print("Button "); Serial.print(i); Serial.println(" released");
      }
    }
    // save the current state as the last state, for next time through the loop
    lastButtonState[i] = buttonState;
  }
  delay(50);  // Delay a little bit to avoid bouncing
}

You want to check to see if the button has been pressed (i.e. made a high to low transition) rather than just seeing if it's low (i.e. being pressed.)

Something like this somewhat modified version of your code. Note that if you don't have any debouncing hardware (cap & resistor on your pin input) this might still trigger due to switching noise (can be fixed by adding debouncing code in the sketch...)

Note also that things like pin numbers and pin states are technically "int"s...

const int buttonPin1 = 10;
const int ledPin1 = 13;

const unsigned long offTime1 = 5000;

unsigned long 
    previousMillis1 = 0;
int
    ledState1,
    buttonState1,
    lastButtonState;

void setup() 
{
    // Push button setup.
    pinMode(buttonPin1, INPUT_PULLUP);
    
    // LED output setup.
    pinMode(ledPin1, OUTPUT);
    digitalWrite( ledPin1, HIGH );      //turn LED 'on'
    
    ledState1 = HIGH;
    previousMillis1 = millis();
    lastButtonState = digitalRead(buttonPin1);

}//setup

void loop() 
{
    // Start recording time.
    unsigned long 
        currentMillis1 = millis();

    if( ledState1 == LOW )
    {
        if( (currentMillis1 - previousMillis1) >= offTime1 )
        {
            //turn on the LED
            ledState1 = HIGH;
            digitalWrite(ledPin1, ledState1);
            
        }//if
        
    }//if
    else
    {
        buttonState1 = digitalRead(buttonPin1);
        if( buttonState1 == LOW && lastButtonState == HIGH )
        {
            //button press detected
            ledState1 = LOW;        //led off
            digitalWrite(ledPin1, ledState1);
            previousMillis1 = currentMillis1;
            
        }//if
        
        lastButtonState = buttonState1;
    
    }//else

}//loop

Blackfin:
You want to check to see if the button has been pressed (i.e. made a high to low transition) rather than
Note also that things like pin numbers and pin states are technically "int"s...

Nope. From Arduino.h

void pinMode(uint8_t, uint8_t);

if you declare them as constants, it doesn't really matter since the compiler will optimize away the actual variable storage.