title: Arduino Uno Controlling multiple LEDs with one button for different amounts of time
body: <p>Thanks in advance for your help. </p>
  
  <h2>Scenario Overview</h2>
  
  <p>In the real world, I am using one button to open two mechanical valves, but one of those valves should close after a period of time that we will hard code into the sketch, and the other valve stays open for as long as the button is pushed. For proof of concept, I am lighting two LEDs as stand-ins for the valves.</p>
  
  <h2>Pseudocode</h2>
  
  <p>If Button One is pressed, Valve One should Open, and Valve Two should also Open for 200ms then Close.</p>
  
  <h2>Initial Solution</h2>
  
  <p>Within the main loop, I look for the button to be pushed as part of an if statement. When that condition is passed, I used a while loop and timer to keep "valve2" open until the time is up. LEDs work, and all is superficially great. However...</p>
  
  <h2>The Issue</h2>
  
  <p>When my partner starts putting the actual mechanicals together, valve2 doesn't open because the while loop is cycling so quickly that the voltage required to initiate the opening of the valve is not high enough. </p>
  
  <h2>My Question</h2>
  
  <ol>
  <li>Is it possible to isolate (without using delays) the loop &amp; evaluation of the timer condition from the main loop in order to allow full power to be sent to the valve mechanism (or LED in this case)? Or am I overthinking this whole thing (likely the case)?</li>
  </ol>
  
  <h2>The Code</h2>
  
  <pre><code>const int button1 = 2;      //Pin for switch 1
          const int button2 = 3;      //Pin for switch 2
          const int valve1 = 12;    //Pin for relay 1
          const int valve2 = 13;    //Pin for relay 2
  
          // variables will change:
          int state1 = 0;         // variable for reading the pushbutton status
          int state2 = 0;         // variable for reading the pushbutton status
  
          //THIS IS THE TIME IN MILLISECONDS FOR valve2 WHEN button1 IS DEPRESSED
          int valve2time = 200;
  
          void setup() {
            //switches
            pinMode(button1,INPUT);       //Set button1 as input
            pinMode(button2, INPUT);     //Set button2 as input
            //relays
            pinMode(valve1, OUTPUT);      //Set valve1 as output
            pinMode(valve2, OUTPUT);      //Set valve2 as output
            Serial.begin(9600);
          }
  
          void loop(){
            state1 = digitalRead(button1);              //state1 returns the state of button1, up or down.
            state2 = digitalRead(button2);              //state2 returns the state of button2, up or down.
            int duration = switchTime();            //Create variable to capture duration of switch press
  
            if (state1 == LOW &amp;&amp; state2 == LOW){     //if no buttons are pressed
              digitalWrite(valve1,LOW);                //make sure valve1 is off
              digitalWrite(valve2,LOW);                //make sure valve2 is off
  
            }
            else if (state1 == HIGH &amp;&amp; state2 == LOW) { //if JUST button one is pressed    
              digitalWrite(valve1,HIGH);               //turn on valve1
  
              while (duration &lt;= valve2time){           //as long as the timer is below or = to what we defined up top....
                digitalWrite(valve2,HIGH);             //...Turn on valve2...
                break;                               //...Then stop the while loop...
              }
  
              digitalWrite(valve2,LOW);                //...and finally turn off valve2
  
            }
            else if (state2 == HIGH){              //final condition, if button two is pressed
              digitalWrite(valve1,HIGH);               //turn on valve1
              digitalWrite(valve2,HIGH);               //turn on valve2
            }
  
          }
  
  
          //return the time in ms that the switch has been pressed (LOW) 
          long switchTime(){
            //these variables are static
            static unsigned long startTime = 0;   //the time the switch state was first detected
            static boolean state;         //the current state of the switch
  
            if(digitalRead(button1) != state){    //check to see if the switch has changed state
              state = ! state;                //yes, invert the state
              startTime = millis();           //store the time
            }
  
            if(state == HIGH){
              return millis() - startTime;    //switch pushed, return time in ms
            }
            else{
              return 0;                   //return 0 if the switch is not pushed (in the HIGH state)
            }
  
          }
  </code></pre>
  
  <h2>UPDATE: The working Code</h2>
  
  <pre><code>    //button pins
  const int BUTTON1_PIN = 2;
  const int BUTTON2_PIN = 3;
      const int VALVE1_PIN = 0; //mml for tiny
      const int VALVE2_PIN = 1; //mml for tiny
  
  // IO Channels - Used to simulate arduino IO
  boolean inputChannels[] = {LOW, LOW};   // digital input channels "Button1" and "Button2"
  boolean outputChannels[] = {LOW, LOW};  // digital output channels "Valve1" and "Valve2"
  
  // =============================================================================================================
  // You can probably ignore everything above this line
  
  // State machine variables
  const int STATE_CLOSED = 0;
  const int STATE_BUTTON1_PRESSED = 1;
  const int STATE_BUTTON1_RELEASED = 2;
  const int STATE_BUTTON2_PRESSED = 3;
  const int STATE_BUTTON2_RELEASED = 4;
  int currentState = 0;
  int lastState = 0;
  
  // button debounce time in ms
  unsigned long BUTTON_DEBOUNCE = 200;
      unsigned long BUTTON1_PRESSED_VALVE2_FLASH = 350;
      unsigned long BUTTON1_RELEASE_VALVE2_FLASH = 1000;
  
  // state tracking arrays
  boolean buttonState[] = {LOW, LOW};
  boolean buttonDebounce[] = {LOW, LOW};
  unsigned long buttonTimers[] = {0, 0};
  unsigned long valveTimers[] = {0, 0};
  
  void setup(){
      pinMode(BUTTON1_PIN, INPUT);
      digitalWrite(BUTTON1_PIN, HIGH); //MML
      pinMode(BUTTON2_PIN, INPUT);
      digitalWrite(BUTTON2_PIN, HIGH); //MML
      pinMode(VALVE1_PIN, OUTPUT);
      pinMode(VALVE2_PIN, OUTPUT);
  }
  /**
   * Main control loop
   */
  void loop() {
  
      switch (currentState) {
  
      case STATE_CLOSED:
          handleClosedState();
          lastState = STATE_CLOSED;
          break;
  
      case STATE_BUTTON1_PRESSED:
          handleButton1PressedState();
          lastState = STATE_BUTTON1_PRESSED;
          break;
  
      case STATE_BUTTON1_RELEASED:
          handleButton1ReleasedState();
          lastState = STATE_BUTTON1_RELEASED;
          break;
  
      case STATE_BUTTON2_PRESSED:
          handleButton2PressedState();
          lastState = STATE_BUTTON2_PRESSED;
          break;
  
      case STATE_BUTTON2_RELEASED:
          handleButton2ReleasedState();
          lastState = STATE_BUTTON2_RELEASED;
          break;
  
      default:;
      }
  }
  
  /**
   * Handler method for STATE_CLOSED
   */
  void handleClosedState() {
  
      // ensure valves are closed
      if (digitalRead(VALVE1_PIN) == HIGH) {
          digitalWrite(VALVE1_PIN, LOW);
      }
      if (digitalRead(VALVE1_PIN) == HIGH) {
          digitalWrite(VALVE2_PIN, LOW);
      }
  
      // wait for button1 press
      if (LOW == debouncedDigitalRead(BUTTON1_PIN, BUTTON_DEBOUNCE)) {
          buttonState[BUTTON1_PIN] = LOW;
          currentState = STATE_BUTTON1_PRESSED;
      }
  }
  
  /**
   * Handler method for STATE_BUTTON1_PRESSED
   */
  void handleButton1PressedState() {
  
      // check for button1 release
      if (HIGH == debouncedDigitalRead(BUTTON1_PIN, BUTTON_DEBOUNCE)) {
          currentState = STATE_BUTTON1_RELEASED;
          return;
      }
  
      // open valve1
      if (digitalRead(VALVE1_PIN) == LOW) {
          valveTimers[VALVE1_PIN] = millis();
          digitalWrite(VALVE1_PIN, HIGH);
      }
  
      // on state change open valve2
      if (lastState != currentState) {
          valveTimers[VALVE2_PIN] = millis();
          digitalWrite(VALVE2_PIN, HIGH);
      }
      // and close it after 200 ms
      else if ((millis() - valveTimers[VALVE2_PIN]) &gt; BUTTON1_PRESSED_VALVE2_FLASH &amp;&amp; digitalRead(VALVE2_PIN) == HIGH) {
          digitalWrite(VALVE2_PIN, LOW);
      }
  
      // check for button2 press
      if (LOW == debouncedDigitalRead(BUTTON2_PIN, BUTTON_DEBOUNCE)) {
          currentState = STATE_BUTTON2_PRESSED;
      }
  }
  
  /**
   * Handler method for STATE_BUTTON1_RELEASED
   */
  void handleButton1ReleasedState() {
      // open valve2
      if (lastState != currentState) {
          valveTimers[VALVE2_PIN] = millis();
          digitalWrite(VALVE2_PIN, HIGH);
          digitalWrite(VALVE1_PIN, LOW);
      }
      // and close valve2 after 1000ms
      else if ((millis() - valveTimers[VALVE2_PIN] &gt; BUTTON1_RELEASE_VALVE2_FLASH)) {
          digitalWrite(VALVE2_PIN, LOW);
          currentState = STATE_CLOSED;
      }
  }
  
  /**
   * Handler method for STATE_BUTTON2_PRESSED
   */
  void handleButton2PressedState() {
  
      // open valve2
      if (digitalRead(VALVE2_PIN) == LOW){
          digitalWrite(VALVE2_PIN, HIGH);
          digitalWrite(VALVE1_PIN, HIGH);
      }
  
      // check for button1 release
      if (HIGH == debouncedDigitalRead(BUTTON1_PIN, BUTTON_DEBOUNCE)) {
          currentState = STATE_BUTTON1_RELEASED;
      }
      // check for button2 release
      else if (HIGH == debouncedDigitalRead(BUTTON2_PIN, BUTTON_DEBOUNCE)) {
          currentState = STATE_BUTTON2_RELEASED;
      }
  }
  
  /**
  * Handler method for STATE_BUTTON2_PRESSED
  */
  void handleButton2ReleasedState() {
  
      // open valve2
      if (digitalRead(VALVE2_PIN) == HIGH){
          digitalWrite(VALVE2_PIN, LOW);
          digitalWrite(VALVE1_PIN, HIGH);
      }
  
      // check for button1 release
      if (HIGH == debouncedDigitalRead(BUTTON1_PIN, BUTTON_DEBOUNCE)) {
          currentState = STATE_BUTTON1_RELEASED;
      }
      // check for button2 press
      else if (LOW == debouncedDigitalRead(BUTTON2_PIN, BUTTON_DEBOUNCE)) {
          currentState = STATE_BUTTON2_PRESSED;
      }
  }
  
  /**
   * Utility for debouncing input channels
   * @param channel
   * @param debounce
   * @return
   */
  boolean debouncedDigitalRead(int channel, unsigned long debounce) {
      int input = digitalRead(channel);
      if (input != buttonState[channel] &amp;&amp; HIGH == buttonDebounce[channel]) {
          buttonTimers[channel] = millis();
          buttonDebounce[channel] = LOW;
      }
      if ((millis() - buttonTimers[channel]) &gt; debounce) {
          buttonState[channel] = input;
          buttonDebounce[channel] = HIGH;
      }
      return buttonState[channel];
  }
  </code></pre>