Run once while button input HIGH in loop

Ok, I have started a new topic since my old one was getting messy and hard to understand. This code has been driving me nuts and I am only on my 3rd day of programing so I don’t understand much more than the commands I am using in this code.

Basically This code flashes a green led under normal operation,
when my “push button” (I am actually using a switch) is LOW I want the Green LED to flash non stop

When I flip my switch and my “button input” goes HIGH I want to light my red LED for 2 seconds, than
have the RED go out and than flash my yellow LED non stop until my switch is flipped and my "push button input returns to LOW.

At that point it will go back to the normal operation of flashing GREEN until the switch is flipped again.

Now, What I am getting is when my switch goes HIGH, My RED LED comes on for 2 seconds, than goes out and my yellow light flashes ONCE… Than the RED LED comes on again for 2 seconds, than the YELLOW flashes again and so on until the switch goes LOW.

I would like this RED LED to ONLY come on once when the switch is flipped, than just flash the YELLOW LED until the “push button” input goes low.

Could someone please give me an understanding of how this could be done?

const int redPin = 10;           //RED LED ON PIN 10
const int yelPin = 11;           //YELLOW LED ON 11
const int greenPin = 12;         //GREEN LED ON 12
const int pushbutton = 2;         //SWITCH FOR BUTTON ON PIN 2
 
int buttonState1 = 0;   

void setup() {
  pinMode(redPin, OUTPUT);
  pinMode(pushbutton, INPUT);    //SETS OUTPUTS
  pinMode(yelPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
}

void loop() {
 
  buttonState1 = digitalRead(pushbutton);
  
  if (buttonState1 == HIGH) {{  
 
digitalWrite(redPin, HIGH);
delay(1500);                       // THIS IS THE OPERATION I ONLY WANT TO RUN ONCE 
digitalWrite(redPin, LOW);

 
 digitalWrite(yelPin, HIGH);
 delay(538);                       // THIS IS THE OPERATION I WANT TO LOOP WHILE BUTTON IS HIGH
 digitalWrite(yelPin, LOW);
 delay(538);
  }}

  else {
  digitalWrite(greenPin, HIGH);
  delay(500);                      //BUTTON LOW, FLASH GREEN
  digitalWrite(greenPin, LOW);
delay(500);   
  
}}

Do you know about the concept of using a state machine with the Arduino?

No, I am not familiar with state machines yet.

This might work (untested), but a good thing to learn is using the "blink without delay" method so you can free-up the MCU to do other things.

const int redPin = 10;           //RED LED ON PIN 10
const int yelPin = 11;           //YELLOW LED ON 11
const int greenPin = 12;         //GREEN LED ON 12
const int pushbutton = 2;         //SWITCH FOR BUTTON ON PIN 2

int buttonState1 = 0;
int previousbuttonState1 = 0;


void setup() {
  pinMode(redPin, OUTPUT);
  pinMode(pushbutton, INPUT);    //SETS OUTPUTS
  pinMode(yelPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
}

void loop() {

  buttonState1 = digitalRead(pushbutton);

  if (buttonState1 == HIGH) {

    if (previousbuttonState1 == LOW) {
      digitalWrite(redPin, HIGH);
      delay(1500);                       // THIS IS THE OPERATION I ONLY WANT TO RUN ONCE
      digitalWrite(redPin, LOW);
    }

    digitalWrite(yelPin, HIGH);
    delay(538);                       // THIS IS THE OPERATION I WANT TO LOOP WHILE BUTTON IS HIGH
    digitalWrite(yelPin, LOW);
    delay(538);
  }

  else {
    digitalWrite(greenPin, HIGH);
    delay(500);                      //BUTTON LOW, FLASH GREEN
    digitalWrite(greenPin, LOW);
    delay(500);
  }
  previousbuttonState1 = buttonState1;
}

Also when you get time see if you can follow this example:

//State machine skeleton

const unsigned long AppleWaitTime  = 50UL;   //time to wait, 50ms 
const unsigned long OrangeWaitTime = 100UL;  //time to wait, 100ms
const unsigned long PearWaitTime   = 500UL;  //time to wait, 1/2Sec
const unsigned long KiwiWaitTime   = 1000UL; //time to wait, 1Sec
//add more as needed

unsigned long AppleMillis;                   //used to calculate when 
unsigned long OrangeMillis;                  //the associated machine state
unsigned long PearMillis;                    //code will be run next
unsigned long KiwiMillis;                    //
//add more as needed

//other variables
const byte ledPin = 13;
const byte buttonPin =2;

unsigned long currentMillis;              //stores the return value from millis() 

//define the available machine states that we can have for this sketch
enum States{
  stateStart, stateApple, stateOrange, statePear, stateKiwi};
//add more states as needed

States mState = stateStart;              //we start out in this machine state 


//======================================================================
void setup()
{
  //Serial.begin(9600);

  currentMillis = millis();
  AppleMillis  = currentMillis;          //initailize all times 
  OrangeMillis = currentMillis;          //
  PearMillis   = currentMillis;          //
  KiwiMillis   = currentMillis;          //

  pinMode(ledPin,OUTPUT);                //
  pinMode(buttonPin,INPUT_PULLUP);

  mState = stateStart;                   //we start out in this machine state 

} //        >>>>>>>>>>>>>> END OF setup() <<<<<<<<<<<<<<<<<

//======================================================================
void loop()
{
  // keep this line here
  currentMillis = millis();  


  //*********** Other loop stuff goes here ************ 



  //************** State Machine section ************** 
  switch (mState)
  {
    //***************************
  case stateStart:
    //code for this state goes here

    //example below, how to change the machine state
    mState = stateApple;          //now switching to this state
    AppleMillis = currentMillis;  //initialize the state delay if there is one

    break;

    //***************************
  case stateApple:
    //is it time to run this section of code?
    if (currentMillis - AppleMillis >= AppleWaitTime) 
    {
      AppleMillis = currentMillis;  //get ready for the next iteration

      //example, toggle a LED
      digitalWrite(ledPin, !digitalRead(ledPin));
    }

    //other state code here
    if (digitalRead(buttonPin) == LOW)
    {
      mState = stateOrange;          //now switching to this state
      OrangeMillis = currentMillis;  //initialize the state delay if there is one
    }  

    break;

    //***************************
  case stateOrange:
    //is it time to run this section of code?
    if (currentMillis - OrangeMillis >= OrangeWaitTime) 
    {
      OrangeMillis = currentMillis;  //get ready for the next iteration

      //other state code here
      digitalWrite(ledPin, !digitalRead(ledPin));
    }

    //other state code here
    if (digitalRead(buttonPin) == HIGH)
    {
      mState = stateApple;          //now switching to this state
      AppleMillis = currentMillis;  //initialize the state delay if there is one
    }  

    break;

    //***************************
  case statePear:
    //is it time to run this section of code?
    if (currentMillis - PearMillis >= PearWaitTime) 
    {
      PearMillis = currentMillis;  //get ready for the next iteration
      //other state code here
    }

    //other state code here
    break;

    //***************************
  case stateKiwi:
    //is it time to run this section of code?
    if (currentMillis - KiwiMillis >= KiwiWaitTime) 
    {
      KiwiMillis = currentMillis;  //get ready for the next iteration
      //other state code here
    }

    //other state code here
    break;

    //***************************
  default: 
    // default code goes here
    break;

    //***************************

  } // end of switch/case


} //        >>>>>>>>>>>>>> END OF loop() <<<<<<<<<<<<<<<<<



//                    F U N C T I O N S
//======================================================================




//======================================================================
//                             END OF CODE
//======================================================================

Edit added one line to sketch to initialize time delay.
See also State Machine

I tried following along that example however as a newbie it is still a little overwhelming. I just want to write a simple program that will run a 3 color traffic light.. red and green times set as random from 15,000 to 50,000 millsec. yellow always set at 4,000 millsec. and have 2 switchs that go to flash the red led or yellow led the instant it is pressed and goes back to normal opp. the second the button is released. I am still at a loss on how this is done. could anyone point me in the right direction?

Try this.

#define redPin 10           //RED LED ON PIN 10
#define yelPin 11           //YELLOW LED ON 11
#define greenPin 12         //GREEN LED ON 12
#define pushbutton 2         //SWITCH FOR BUTTON ON PIN 2

volatile int state = LOW;

void setup() {
  pinMode(pushbutton, INPUT);    //SETS OUTPUTS
  pinMode(redPin, OUTPUT);
  pinMode(yelPin, OUTPUT);
  pinMode(greenPin, OUTPUT);

  digitalWrite(redPin, LOW);
  digitalWrite(yelPin, LOW);
  digitalWrite(greenPin, LOW);
  digitalWrite(pushbutton, LOW);
  
  attachInterrupt(0, begin, HIGH);
}

void loop() {
  digitalWrite(greenPin, HIGH);
  delay(500);                      //BUTTON LOW, FLASH GREEN
  digitalWrite(greenPin, LOW);
  delay(500);   
  if(state == HIGH) {
    triggerRedAndYellow();
  }
}

void triggerRedAndYellow() {
  digitalWrite(redPin, HIGH);
  delay(1500);                       // THIS IS THE OPERATION I ONLY WANT TO RUN ONCE 
  digitalWrite(redPin, LOW);
  digitalWrite(yelPin, HIGH);
  delay(500);                       // THIS IS THE OPERATION I WANT TO LOOP WHILE BUTTON IS HIGH
  digitalWrite(yelPin, LOW);
  state = LOW;
}

void begin() {
  state = HIGH;
}

steve101100: I tried following along that example however as a newbie it is still a little overwhelming. I just want to write a simple program that will run a 3 color traffic light.. red and green times set as random from 15,000 to 50,000 millsec. yellow always set at 4,000 millsec. and have 2 switchs that go to flash the red led or yellow led the instant it is pressed and goes back to normal opp. the second the button is released. I am still at a loss on how this is done. could anyone point me in the right direction?

What parts have you done? What part are you having trouble with? Show us the sketch as it now sits.

random from 15,000 to 50,000

See: HERE

The simple answer is to put your switch test in the bottom of setup().

while ( digitalRead( switchPin ) == LOW );

That will loop around until the pin reads HIGH. Loop() won't run till setup() is done.

And here's a tip: Use the built-in pullup resistors where possible with your buttons, switches, etc. Every digital pin has a 20k to 50k resistor available to use in the chip by setting pin mode like:

pinMode( myPin, INPUT_PULLUP );

So now myPin needs no external resistor to work safely. You can ground it all day and the pullup resistor will limit current drained through that pin to a safe low amount.

However now the pin will read the opposite of what you might expect. When not grounded, the pullup will make it HIGH and when grounded (switch to ground is close) it will read LOW. That's no big deal as long as you know to expect it, so your wait for switch might read

while ( digitalRead( switchPin ) == HIGH );

unless you simply turn the switch over to reverse the switch itself. ;o)

get used to being able to flex both your code and wiring, it may help keep your mind from getting stuck.

You need to use an interrupt and let me say why. During the flashing cycle you have 2 delays. During the delays non of the code it executed. So you have 1 second of what I call dead time where nothing is executed. If you were to push and release the button during this time the arduino would never see it.

TexasStingray: You need to use an interrupt and let me say why. During the flashing cycle you have 2 delays. During the delays non of the code it executed. So you have 1 second of what I call dead time where nothing is executed. If you were to push and release the button during this time the arduino would never see it.

This is why it is requested people use the Blink Without Delay technique rather than delay().

The use of delay() doesn't begin until loop(). Putting the switch test in setup() would work because loop() comes after setup().

Getting rid of the delays is one of the best lessons that Steve could learn at this point, but it's not required to make his sketch work as he has stated so far.

The problem with the delays is that even doing as I suggested, all further changes are limited by those damned delays.

steve101100: I tried following along that example however as a newbie it is still a little overwhelming. I just want to write a simple program that will run a 3 color traffic light.. red and green times set as random from 15,000 to 50,000 millsec. yellow always set at 4,000 millsec. and have 2 switchs that go to flash the red led or yellow led the instant it is pressed and goes back to normal opp. the second the button is released. I am still at a loss on how this is done. could anyone point me in the right direction?

There's a beautiful solution where every part of your traffic light behaves as a separate element. The key to that is learning one of the many lessons based on Blink Without Delay. The first link of the 3 at the bottom of my post has a complete what/how/why tutorial on the subject. Robin2 has a less complete tutorial. Your IDE has the standard BWD Example under IDE File->Examples->02.Digital->BlinkWithoutDelay.

Learn it somewhere and you will be able to write Arduino code that acts like an RTS game plays.

The code I have now (below) only goes into flashing mode if you push and hold the buttons for one whole cycle (in between the yellow and red light is where the "check button state is located) as it is only checking the buttons once per cycle instead of constantly. I would like it to instantly go into flach mode when the buttons are pressed and stay in flash mode for the whole time the button is pushed (I plan on replacing the buttons with a switch in the final project).

Thanks again for all your help guys

const int redPin = 10;             //RED LED OUTPUT PIN 10
const int yelPin = 11;             //YELLOW OUTPUT ON 11
const int grnPin = 12;             //GREEN OUTPUT ON 12
const int pushbuttonY = 2;         //SWITCH FOR YELLOW FLASH SWITCH ON PIN 2
const int pushbuttonR = 3;         //SWITCH FOR RED FLASH SWITCH ON PIN 3

int buttonState1 = 0;
int buttonState2 = 0;
int previousbuttonState1 = 0;
int previousbuttonState2 = 0;

void setup() {
  pinMode(redPin, OUTPUT);
  pinMode(yelPin, OUTPUT);
  pinMode(grnPin, OUTPUT);
  pinMode(pushbuttonR, INPUT);   
  pinMode(pushbuttonY, INPUT);  
}

void loop() {
  
  previousbuttonState1 = buttonState1;
  
    buttonState1 = digitalRead(pushbuttonR);

  if (buttonState1 == HIGH) {

    if (previousbuttonState1 == LOW) {
      digitalWrite(redPin, HIGH);
      delay(2000);                       // THIS IS THE OPERATION I ONLY WANT TO RUN ONCE
      digitalWrite(redPin, LOW);
    }

    digitalWrite(redPin, HIGH);
    delay(538);                       // THIS IS THE OPERATION I WANT TO LOOP WHILE BUTTON IS HIGH
    digitalWrite(redPin, LOW);
    delay(538);
  }

  else {{
     
    buttonState2 = digitalRead(pushbuttonY);

  if (buttonState2 == HIGH) {

    if (previousbuttonState2 == LOW) {
      digitalWrite(redPin, HIGH);
      delay(2000);                       // THIS IS THE OPERATION I ONLY WANT TO RUN ONCE
      digitalWrite(redPin, LOW);
    }

    digitalWrite(yelPin, HIGH);
    delay(538);                       // THIS IS THE OPERATION I WANT TO LOOP WHILE BUTTON IS HIGH
    digitalWrite(yelPin, LOW);
    delay(538);
  }
     

else {
  
  digitalWrite(redPin, HIGH);
  delay(random(16000, 55000));
  digitalWrite(redPin, LOW);

  digitalWrite(grnPin, HIGH);
  delay(random(10000, 48000));
  digitalWrite(grnPin, LOW);

  digitalWrite(yelPin, HIGH);
  delay(4000);                   
  digitalWrite(yelPin, LOW);
  }

  previousbuttonState2 = buttonState2;

}}}

Here is an example you can run with an Arduino and 1 jumper.
It is very simple.
Ground the jumper (cheap button) on the Arduino USB port one time and 1 second later the pin 13 led comes on. You can lift the jumper pin off the port (that silver box the USB cable plugs into) right away or wait but lift it to unground the jumper and the sketch behaves the same either way. Ground the jumper again and the pin 13 led turns off immediately. Next time the ungrounded jumper is grounded, the led will light 1 second later.

Each time the pin is grounded from ungrounded, the program acts according to what went before.
This shows different behaviors for the same action based on what is happening.

Note that the sketch has different sections for INPUT, CONTROL, and OUTPUT. Each can be changed or replaced without having to touch the others. The INPUT code does debounce the button, a necessary thing for most contact buttons once your code gets past being delay-bound.

If 1 button and 1 led are not enough, first see how this works (it has serial monitor output, baud rate is 115200) and if you need more I can give you multiple everything. But I won’t do your project for you.

This is only to show technique and approach leading to event-driven coding. Learn this and you can make all kinds of things work together all at once, each as a separate simple piece you can debug in a test sketch then add without dead-ending or ending up with spaghetti-code.

// All you need to do this example is an Arduino and a button on pin 2.
// Push the button once, led lights after delay. Again, led turns off.
// Button is debounced and wired directly to ground. The button can be a 
// jumper from pin 2 grounded on USB connector. Tested with jumper.
// By GoForSmoke for free public use. Using Arduino 1.0.5-r2

const byte ledPin =  13;      // this is the onboard led pin
const byte buttonPin = 2;


byte setLedPin = 0;
const unsigned long ledDelay = 1000UL; // blink interval
unsigned long ledDelayStart = 0U; // 16 bit blink (on or off) time ms

// button variables
byte buttonRead;  // wired for pullup -- if down then LOW, if up then HIGH 
byte lastButtonRead = HIGH; // so debounce knows previous read
byte checkDebounce = 0; // only checks decounce after every button pin change
byte lastButtonState = 0; // last stable button state
byte buttonState = 0;  // stable button state
// 0 = button is up after debounce
// 1 = button is down after debounce

// button debounce timing variables
const unsigned long debounceDelayMs = 100UL; 
unsigned long debounceStartMs; 
unsigned long msNow; 


byte processState = 0; 


void setup() 
{
  Serial.begin( 115200 );

  pinMode( ledPin, OUTPUT );  // default is LOW 
  pinMode( buttonPin, INPUT_PULLUP ); // my button connects to ground, not 5V
  // however that means that when the button is pressed the pin is LOW.
}

void loop() // make sure that loop() runs fast and stays in the "now".
{

  // BUTTON CODE BLOCK, it handles debouncing. 
  // the task is to set the variable buttonState when a Stable Button State is reached.
  // other sensor code could change the same variable if desired

  // read the pin which may be changing fast and often as the button bounces
  buttonRead = digitalRead( buttonPin ); // momentary state

  msNow = millis(); 

  if ( buttonRead != lastButtonRead )
  {
    debounceStartMs = msNow;
    checkDebounce = 1;
  }
  else if ( checkDebounce )
  { 
    if ( msNow - debounceStartMs >= debounceDelayMs ) // stable button state achieved
    {
      buttonState = !buttonRead; // mission accomplished, button is stable
      // note that buttonState is opposite buttonRead
      checkDebounce = 0; // stop debounce checking until pin change
    }
  }
  lastButtonRead = buttonRead;
  //
  // End of the BUTTON CODE BLOCK

  //==================================================================================

  // CONTROL CODE BLOCK that uses buttonState and processState
  
  if ( lastButtonState != buttonState )
  {
    lastButtonState = buttonState;

    Serial.println( F( "============================================================" ));    
    Serial.print( F( "processState " ));
    Serial.print( processState );
    Serial.print( F( "  buttonState " ));
    Serial.println( buttonState );
    Serial.print( F( "  millis " ));
    Serial.println( msNow ); 
    Serial.println( F( "============================================================" ));    

    switch ( processState )
    {
    case 0: 
      if ( buttonState == 1 ) // button is pressed 
      {
        processState = 1;
        setLedPin = 1;
        ledDelayStart = millis();
      }
      break; 

    case 1: 
      if ( buttonState == 0 ) // button is released 
      {
        processState = 2;
      }
      break; 

    case 2: 
      if ( buttonState == 1 ) // button is pressed 
      {
        processState = 3;
        setLedPin = 2;
      }
      break; 

    case 3: 
      if ( buttonState == 0 ) // button is released 
      {
        processState = 0; 
      }
      break; 
    } 
  }
  // End of the CONTROL CODE

  //==================================================================================

  // LED BLINK CODE BLOCK
  if ( setLedPin == 1 )
  { 
    if ( millis() - ledDelayStart >= ledDelay )
    { 
      digitalWrite(ledPin, HIGH );
      setLedPin = 0;
    }
  }
  else if ( setLedPin == 2 )
  {
    digitalWrite(ledPin, LOW );
    setLedPin = 0;
  }
  // End of the LED BLINK CODE

  //==================================================================================

  // Want to add serial commands and args input? 
  // this is a good spot. Serial is so slow it can usually go last.
}