press button 5 seconds to start a sequence and....

hey everybody, I am looking for someone to show me how to add this to my sketch. I have looked at the statechange function but don’t think / don’t know if it applies. I don’t want to turn the sequence on or off with the button. I would like it to be you have to HOLD the button down for 5 seconds to start the sequence. a safety switch so to speak. in case someone pushes it momentarily nothing will happen. thanks if you can be of help. here is the basic code stripped of all the stuff I tried that didn’t work.

int pwrSbBlueLed = 9;
int rgbBlue = 4;
int rgbGreen = 5;
int rgbRed = 6;
int yellowLed = 10;
int button = 7;
int buttonSignal = 8;
int numrgbBlueBlinks = 5;
int numrgbGreenBlinks = 5;
int numrgbRedBlinks = 1;
int ledTimeOn1 = 1000;
int ledTimeOff1 = 1000;
int ledTimeOn2 = 10000;
int ledTimeOff2 = 10000;







void setup() {
  pinMode(pwrSbBlueLed, OUTPUT);
  pinMode(rgbBlue, OUTPUT);
  pinMode(rgbGreen, OUTPUT);
  pinMode(rgbRed, OUTPUT);
  pinMode(yellowLed, OUTPUT);
  pinMode(button, OUTPUT);     //sends 5v to button, when pressed it sends signal to pin 8
  pinMode(buttonSignal, INPUT);


  digitalWrite(pwrSbBlueLed, HIGH);    //fix to run for 60 seconds if possible WITHOUT DELAY
  //digitalWrite(button, HIGH);        //IF, button is pressed for more than 5 seconds, BLINK the RGB LED in the sequence that follows
  for (int j = 1; j <= numrgbBlueBlinks; j = j + 1)
  {
    digitalWrite(rgbBlue, HIGH);
    delay (ledTimeOn1);
    digitalWrite(rgbBlue, LOW);
    delay (ledTimeOff1);
  }
  for (int j = 1; j <= numrgbGreenBlinks; j = j + 1)
  {
    digitalWrite(rgbGreen, HIGH);
    delay(ledTimeOn1);
    digitalWrite(rgbGreen, LOW);
    delay(ledTimeOff1);
  }
  for (int j = 1; j <= numrgbRedBlinks; j = j + 1)
  {
    digitalWrite(rgbRed, HIGH);
    delay (ledTimeOn2);
    digitalWrite(rgbRed, LOW);
    delay(ledTimeOff2);
  }

  //digitalWrite(button, LOW);


  {
    digitalWrite(yellowLed, HIGH);
    delay(ledTimeOn1);
    digitalWrite(yellowLed, LOW);
  }


}

void loop() {
  // put your main code here, to run repeatedly:

}

I would like it to be you have to HOLD the button down for 5 seconds to start the sequence. a safety switch so to speak.

On each pass through loop(), you read the state of the switch. If it is pressed now, but was not pressed then (then being last time through loop()), then a state change has occurred (to pressed), so you record when that happens.

On each pass through loop(), you also check, if the switch is pressed, if now minus then (when the switch became pressed) is greater then 5 seconds. If so, you do whatever needs doing.

I suggest two steps, the first is to pull the sequence out to its own function:

void doSequence()
{
  for (int j = 1; j <= numrgbBlueBlinks; j = j + 1)
  {
    digitalWrite(rgbBlue, HIGH);
    delay (ledTimeOn1);
    digitalWrite(rgbBlue, LOW);
    delay (ledTimeOff1);
  }
  for (int j = 1; j <= numrgbGreenBlinks; j = j + 1)
  {
    digitalWrite(rgbGreen, HIGH);
    delay(ledTimeOn1);
    digitalWrite(rgbGreen, LOW);
    delay(ledTimeOff1);
  }
  for (int j = 1; j <= numrgbRedBlinks; j = j + 1)
  {
    digitalWrite(rgbRed, HIGH);
    delay (ledTimeOn2);
    digitalWrite(rgbRed, LOW);
    delay(ledTimeOff2);
  }

  for (int j = 1; j <= numrgbYelloBlinks; j = j + 1) // need to add numrgbYelloBlinks
  {
    digitalWrite(yellowLed, HIGH);
    delay(ledTimeOn1);
    digitalWrite(yellowLed, LOW);
  }

}

Try calling doSequence() in loop() to see if it does what you want.

Once that works add the code to check the button. When the button goes down start a timer When the timer hits 5 seconds and the button is still down do the sequence and reset the timer to fire in another five seconds if the button is still down.

long startSequenceTime;
int buttonValue = LOW; 
int oldButtonValue = LOW;

void loop() {

  // read button value
  buttonValue = digitalRead(button);

  // if button is down
  if( buttonValue == HIGH )
  {
    // if it just went down
    if( buttonValue != oldButtonValue )
    { 
      // start in five seconds
      startSequenceTime = millis() + 5000;

    } 
    else {

      // check if it's time to start sequence
      if( millis() >= startSequenceTime ) 
      {
        doSequence();

        // reset start time
        startSequenceTime = millis() + 5000;

      }

    }

  } 

  // save button state
  oldButtonValue = buttonValue;

}

This is untested, check it out and see if it works.

The code in this link should do what you want.

The trick is to reset the timer when the button is NOT pressed.

...R

When the button goes down start a timer

That’s overkill. The state change detection example is all that is needed. There is a time when the switch becomes pressed. There is a time when the switch becomes released.

The difference is the time the switch was pressed.

Making a function to do the important stuff was a good idea, but the name is terrible. flashLEDs() would have been my choice.

Robin2:
The code in this link should do what you want.

The trick is to reset the timer when the button is NOT pressed.

Or, do not even look at the timer value when the button is not pressed. We only need the timer when the button is being held down.

I don't agree.

How do you know when it is not pressed?

My code resets the timer when the button is NOT pressed so the only way it can timeout is by holding the button down continuously.

...R

so why doesn’t this work, it’s from the link?

int pwrSbBlueLed = 9;
int fiveToBtn = 7;
int btnPin = 8;
unsigned long previousMillis = 0;
unsigned long interval = 5000;
unsigned long lastBtnPressMillis;


void setup() {
  pinMode(pwrSbBlueLed, OUTPUT);
  pinMode(fiveToBtn, OUTPUT);
  digitalWrite(fiveToBtn, HIGH);
  pinMode(btnPin, INPUT);


  int btnVal = digitalRead(btnPin);
  if (btnVal == HIGH) {    // assumes btn is LOW when pressed
    lastBtnPressMillis = millis();   // btn not pressed so reset clock
  }
  if (millis() - lastBtnPressMillis >= interval) {
    digitalWrite(pwrSbBlueLed, HIGH);
  }


}

void loop() {
  // put your main code here, to run repeatedly:

}

Fredric58:
so why doesn't this work, it's from the link?

The code in the link was assumed to be inside loop() so it would be called over and over.

If you want to use it in setup() put it inside a WHILE loop(). I think this will work

while(true) {
  int btnVal = digitalRead(btnPin);
  if (btnVal == HIGH) {    // assumes btn is LOW when pressed
    lastBtnPressMillis = millis();   // btn not pressed so reset clock
  }
  if (millis() - lastBtnPressMillis >= interval) {
    break;
  }
}
digitalWrite(pwrSbBlueLed, HIGH);

...R

hey robin, that's pretty cool dude! it didn't work at first, but.......I changed the == HIGH to ==LOW and now when the button is pressed for 5 seconds it turns on. awesome, thanks for the help.

now I have to work on replacing the 1 LED with the sequence of the rgb LED.

may have a question later, but I have enough to work with right now. thanks again.

My code assumed the use of pinMode(pn, INPUT_PULLUP); which is the best way to avoid damage due to short circuits - hence an unpressed switch would read HIGH and the switch sould connect the pin to GND.

...R

yes, most of the things I see people use the 5v arduino output, however, I just use, and power the button with another arduino pin during setup and just turn it off when I’m finished then move to the loop.

the piece of code you sent works great to light the led. when I try to follow it with a sequence it just ignores the “wait for 5 second push of the button” and runs over and over.

is that a braces thing? I can change the sequence using millis if needed instead of delay if that would be more appropriate? or perhaps a “while” instead of “for”

int pwrSbBlueLed = 9;
int rgbBlue = 4;
int rgbGreen = 5;
int rgbRed = 6;
int yellowLed = 10;
int button = 7;
int buttonSignal = 8;
int numrgbBlueBlinks = 5;
int numrgbGreenBlinks = 5;
int numrgbRedBlinks = 1;
int ledTimeOn1 = 1000;
int ledTimeOff1 = 1000;
int ledTimeOn2 = 10000;
int ledTimeOff2 = 10000;
int btnVal;

unsigned long previousMillis = 0;
unsigned long interval = 60000;
unsigned long lastBtnPressMillis = millis();
long interval1 = 5000;








void setup() {
  pinMode(pwrSbBlueLed, OUTPUT);
  pinMode(rgbBlue, OUTPUT);
  pinMode(rgbGreen, OUTPUT);
  pinMode(rgbRed, OUTPUT);
  pinMode(yellowLed, OUTPUT);
  pinMode(button, OUTPUT);
  digitalWrite(button, HIGH);//sends 5v to button, when pressed it sends signal to pin 8
  pinMode(buttonSignal, INPUT);
  digitalWrite(pwrSbBlueLed, HIGH);




  while (true) {
    int btnVal = digitalRead(buttonSignal);
    if (btnVal == LOW) {    // assumes btn is LOW when pressed
      lastBtnPressMillis = millis();   // btn not pressed so reset clock
    }
    if (millis() - lastBtnPressMillis >= interval) {
      break;
    }
    for (int j = 1; j <= numrgbBlueBlinks; j = j + 1)
    {
      digitalWrite(rgbBlue, HIGH);
      delay (ledTimeOn1);
      digitalWrite(rgbBlue, LOW);
      delay (ledTimeOff1);
    }
    for (int j = 1; j <= numrgbGreenBlinks; j = j + 1)
    {
      digitalWrite(rgbGreen, HIGH);
      delay(ledTimeOn1);
      digitalWrite(rgbGreen, LOW);
      delay(ledTimeOff1);
    }

    {
      digitalWrite(rgbRed, HIGH);
      delay (ledTimeOn2);
      digitalWrite(rgbRed, LOW);
      delay(ledTimeOff2);
    }
    {
      digitalWrite(yellowLed, HIGH);
      delay(ledTimeOn1);
      digitalWrite(yellowLed, LOW);
    }


  }

}






void loop() {
  // put your main code here, to run repeatedly:

}

Of course, while (true) runs forever. You need a "while (millis() [...something]) {...}".

@aarg, the while(true) is intentional.

@Fredric58, your code is NOT organized like my example in Reply #8. You will see that my example breaks out of the WHILE when the test succeeds and the LED is turned on after the WHILE - not within it. Your example has no code after the WHILE.

...R

i'll study and compare, see if I can figure it out, thanks for the response. basically I am still inside the while?

UPDATE: thanks Robin, had to go back and re=write, works great now.