Programming a held button press

Hello, I've programmed a button to turn on an LED if it is held for 2 seconds. The LED is turned off once the button is released;

int buttonPin2 = 3;
int LEDred = 8;
int buttonStatus2 = 0;


void setup() {
  
  pinMode(LEDred, OUTPUT);
  pinMode(buttonPin2, INPUT);
 
}
void loop() {


  buttonStatus2 = digitalRead(buttonPin2);


   static uint32_t previous = millis();
   


  if (buttonStatus2 == HIGH ) { 
    if (millis() - previous > 2000) //switches on the LED after 2 second press and hold
    digitalWrite(8, HIGH);
 
  }
  else {
    
    previous = millis();
    digitalWrite(8, LOW); //switch off LED on button release
}
}

However, I also want the LED to turn off when held for 3 total seconds.

in summary; you hold the button for 2 seconds and the LED turns on. If button is remained held for an additional second, the LED turns off (and remains off if the button is continued to be held).

the process can be repeated once the button is released.

I figured the code could look like this, were the IF statement is only true if the duration of the button press is between 2000 and 3000 milliseconds (using the && function below) but this didn't seem to work;

//wrong code

void loop() {

  buttonStatus2 = digitalRead(buttonPin2);

   static uint32_t previous = millis();
   

  if (buttonStatus2 == HIGH ) { 
    if (millis() - previous > 2000 && millis() - previous < 3000 ) //switches on the LED after 2 second press, and switches off after 3 second press.
    digitalWrite(8, HIGH);
 
  }
  else {
    
    previous = millis();
    digitalWrite(8, LOW); //switch off on button release
}
}

I would very much appreciate any solution to this!!! hopefully it's just a simple modification :slight_smile:

thank you!

I think I would program it like this

previousButtonState = buttonState;
buttonState = digitalRead(buttonPin);
if(buttonState == LOW and previousButtonState == HIGH) {  // assumes low = pressed)
         buttonStartMillis = millis(); // recording the time the button was first pressed
}
if (millis() - buttonStartMIllis >= 2000 and ledState == 0) {
     ledState = 1;
}
if (millis() - buttonStartMillis >= 3000 and ledState == 1) {
    ledState = 0;
}
digitalWrite(ledPin, ledState);

...R

Robin2:
I think I would program it like this

previousButtonState = buttonState;

buttonState = digitalRead(buttonPin);
if(buttonState == LOW and previousButtonState == HIGH) {  // assumes low = pressed)
        buttonStartMillis = millis(); // recording the time the button was first pressed
}
if (millis() - buttonStartMIllis >= 2000 and ledState == 0) {
    ledState = 1;
}
if (millis() - buttonStartMillis >= 3000 and ledState == 1) {
    ledState = 0;
}
digitalWrite(ledPin, ledState);




...R

I couldn't fully figure out how to use your code, but it got me thinking and I ended up getting this code to work;

int buttonPin2 = 3;
int LEDred = 8;
int buttonStatus2 = 0;
int ledState = LOW; 

void setup() {
  pinMode(LEDred, OUTPUT);
  pinMode(buttonPin2, INPUT);
}
void loop() {
 twosecondloop();
 threesecondloop();
}
void twosecondloop() {
  buttonStatus2 = digitalRead(buttonPin2);
   static uint32_t previous = millis(); 
 
  if (buttonStatus2 == HIGH && ledState == LOW) {  //ledState = HIGH when 3 second press
    if (millis() - previous > 2000) //LEDred on after 2 seconds press
    digitalWrite(8, HIGH);
  }
  else {   
    previous = millis();
    digitalWrite(8, LOW); 
}
}
 void threesecondloop() {
     buttonStatus2 = digitalRead(buttonPin2);
   static uint32_t previous2= millis();
   
    if (buttonStatus2 == HIGH) {
    if (millis() - previous2 > 3000) 
    ledState = HIGH;
    }
    else {   
    previous2 = millis();
    ledState = LOW;
    }
 }

thanks for the help :slight_smile:

The one thing you missed is turning off the light:

    if (millis() - previous > 2000 && millis() - previous < 3000 ) //switches on the LED after 2 second press, and switches off after 3 second press.
    digitalWrite(8, HIGH);

That code will turn ON the light if the time is in the 2-second to 3-second range, but it won't turn off the light.

    if (millis() - previous > 2000 && millis() - previous < 3000 ) //switches on the LED after 2 second press, and switches off after 3 second press.
    digitalWrite(8, HIGH);
  else
    digitalWrite(8, LOW);

This will turn the light ON when in the range and turn the light OFF when not in the range.

johnwasser:
The one thing you missed is turning off the light:

    if (millis() - previous > 2000 && millis() - previous < 3000 ) //switches on the LED after 2 second press, and switches off after 3 second press.

digitalWrite(8, HIGH);



That code will turn ON the light if the time is in the 2-second to 3-second range, but it won't turn off the light.


if (millis() - previous > 2000 && millis() - previous < 3000 ) //switches on the LED after 2 second press, and switches off after 3 second press.
   digitalWrite(8, HIGH);
 else
   digitalWrite(8, LOW);



This will turn the light ON when in the range and turn the light OFF when not in the range.

I did actually include an else statement in my original code, but strangely it still doesn't work :confused:

jtardu:

void loop() {

buttonStatus2 = digitalRead(buttonPin2);

static uint32_t previous = millis();
 if (buttonStatus2 == HIGH ) {
   if (millis() - previous > 2000 && millis() - previous < 3000 ) //switches on the LED after 2 second press, and switches off after 3 second press.
   digitalWrite(8, HIGH);
 }
 else {    
   previous = millis();
   digitalWrite(8, LOW); //switch off on button release
}
}

You have an else for "pressed vs. not pressed", but you need another one for "in the time range vs. outside the time range". That is a separate 'if' statement and needs it's own 'else'.

johnwasser:
You have an else for "pressed vs. not pressed", but you need another one for "in the time range vs. outside the time range". That is a separate 'if' statement and needs it's own 'else'.

I see. will try wrap my head around it. Otherwise, my alternate solution should suffice. thanks!

finally figured it out. phew :grinning:

   static uint32_t previous = millis();
   
   
if (buttonStatus2 == HIGH) { 
    if (millis() - previous > 1000 && millis() - previous < 3000) 
    digitalWrite(8, HIGH);
  if (millis() - previous > 3000)
  digitalWrite(8, LOW);}
  
    else {
    previous = millis();
    digitalWrite(8, LOW);