bennyscot27
bennyscot27

Reputation: 31

How can I trigger a series of LED events when a switch is HIGH, and how can I stop them whenever the switch is LOW?

I am trying to make this thing where every time a micro limit switch is HIGH (pressed), it starts this process that turns on a red LED for fifty seconds, then blinks the LED for about ten seconds, and then finally turns off the red, and turns on a green LED for about 50 seconds. Also, I am doing all of this on an Arduino.

The big problem that I am having pertains to breaking the loop every time the limit switch is not pressed. I want this series of LED events only to occur when the switch is pressed. The code below uses the delay method, which I know will not work for this project because the button state change will not be recognized during the LED events. I put it below just so you all can understand what I am trying to achieve.

Also, I am relatively new to the Arduino so every bit of help is greatly appreciated. Thanks.

Here is the code that I mentioned above :

const int buttonPin = 2;
const int ledPin = 12;
const int ledPin1 = 9;

int buttonState = 0;

void setup() {
  
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(ledPin1, OUTPUT);
  Serial.begin(115200);
}

void loop() {
  buttonState = digitalRead(buttonPin);

  if (buttonState == HIGH) {

    
    digitalWrite(ledPin, HIGH);
    delay(50000);
    digitalWrite(ledPin, LOW);
    delay(1000);
    digitalWrite(ledPin, HIGH);
    delay(1000);
    digitalWrite(ledPin, LOW);
    delay(1000);
    digitalWrite(ledPin, HIGH);
    delay(1000);
    digitalWrite(ledPin, LOW);
    delay(1000);
    digitalWrite(ledPin1, HIGH);
    delay(50000);
  }

  else if (buttonState == LOW) {

    digitalWrite(ledPin, LOW);
    digitalWrite(ledPin1, LOW);
  }

}

Upvotes: 3

Views: 756

Answers (2)

embedded_guy
embedded_guy

Reputation: 1967

For these types of problems I really like to use switch() statements to create a state machine. I would also recommend that you do not use the delay() function at all, but rather calculate how much time has passed since you had last looped. Here is a quick example that I came up with... I apologize if it has any errors in it, I was in a bit of a hurry. If you are having trouble following the logic, let me know and I will add more comments.

#define WAIT_TIME_50S   50000   /* 50,000ms = 50s */
#define WAIT_TIME_10S   10000   /* 10,000ms = 10s */
#define WAIT_TIME_1S    1000    /* 1,000ms  = 1s  */

/* Create an enumeration 'type' with the different states that you will
   be going through.  This keeps your switch statement very
   descriptive and you know exactly what happens as you go from
   state to state. */
typedef enum
{
    SWITCH_RELEASED,
    RED_LED_ON_50S,
    RED_LED_BLINK_10S,
    GREEN_LED_ON_50S,
    RESET_LEDS
} LedState_t;

const int buttonPin     = 2;
const int ledPinRed     = 12;
const int ledPinGreen   = 9;
int buttonState         = LOW;

void loop() 
{
    static LedState_t currentState = RESET_LEDS;
    static unsigned long previousTime_ms = 0;
    static unsigned long previousBlinkTime_ms = 0;
    unsigned long currentTime_ms = 0;
    static int ledState = LOW;

    buttonState = digitalRead(buttonPin);

    switch (currentState)
    {
        case SWITCH_RELEASED:
            if (buttonState == HIGH)
            {
                currentState = RED_LED_ON_50S;
                digitalWrite(ledPinRed, HIGH);
                previousTime_ms = millis();
            }
            break;

        case RED_LED_ON_50S:
            if (buttonState == LOW)
            {
                currentState = RESET_LEDS;
            }
            else
            {
                currentTime_ms = millis();

                if ((currentTime_ms - previousTime_ms) >= WAIT_TIME_50S)
                {
                    previousTime_ms = currentTime_ms;
                    previousBlinkTime_ms = currentTime_ms;

                    ledState = LOW;
                    digitalWrite(ledPinRed, ledState);
                    currentState = RED_LED_BLINK_10S;
                }
            }
            break;

        case RED_LED_BLINK_10S:
            if (buttonState = LOW)
            {
                currentState = RESET_LEDS;
            }
            else
            {
                currentTime_ms = millis();

                if ((currentTime_ms - previousTime_ms) >= WAIT_TIME_10S)
                {
                    previousTime_ms = currentTime_ms;

                    digitalWrite(ledPinRed, LOW);
                    digitalWrite(ledPinGreen, HIGH);

                    currentState = GREEN_LED_ON_50S;
                }
                else if ((currentTime_ms - previousBlinkTime_ms) >= WAIT_TIME_1S)
                {
                    previousBlinkTime_ms = currentTime_ms;

                    if (ledState == HIGH)
                    {
                        ledState = LOW;
                    }
                    else
                    {
                        ledState = HIGH;
                    }

                    digitalWrite(ledPinRed, ledState);
                }
            }
            break;

        case GREEN_LED_ON_50S:
            if (buttonState == LOW)
            {
                currentState = RESET_LEDS;
            }
            else
            {
                currentTime_ms = millis();

                if ((currentTime_ms - previousTime_ms) >= WAIT_TIME_50S)
                {
                    currentState = RESET_LEDS;
                }
            }
            break;

        case RESET_LEDS:
            digitalWrite(ledPinRed, LOW);
            digitalWrite(ledPinGreen, LOW);

            currentState = SWITCH_RELEASED;
            break;
    }
}

Upvotes: 0

Darth Hunterix
Darth Hunterix

Reputation: 1510

The simplest way to achieve what you want is splitting loop() function into several small functions, and splitting delays into many small delays. For example to handle your first waiting you need something like this:

bool wait50secondsOnHigh()
{
    for (int counter = 0; counter < 5000; counter++)
    {
        if (digitalRead(buttonPin) == LOW)
        {
            return false;
        }

        digitalWrite(ledPin, HIGH);
        delay(10);
    }

    return wait1secondOnLow();
}

loop()
{
    if (!wait50secondsOnHigh())
    {
        digitalWrite(ledPin, LOW);
        digitalWrite(ledPin1, LOW);
    }
}

Other waiting functions can be written in similar fashion: you check your button every 10 milliseconds N times, if it's HIGH you continue, if it's LOW you return false. After you're done, you call next function. Last function in sequence will simply return true:

bool wait50secondsOnHighLed1()
{
    for (int counter = 0; counter < 5000; counter++)
    {
        if (digitalRead(buttonPin) == LOW)
        {
            return false;
        }

        digitalWrite(ledPin1, HIGH);
        delay(10);
    }

    return true;
} 

Once you will have a function for each waiting you can refactor the code to avoid duplications, but I leave it as an exercise to you :)

You can also use special libraries for event handling, for example http://playground.arduino.cc/Code/QP but for a beginner I would recommend a simpler approach. Events are hard to debug, especially on Arduino. But one you get more comfortable with Arduino, you should try to experiment with them.

By the way: I think you should switch off led1 at the end.

Upvotes: 1

Related Questions