Evaluate Switch State During Loop -

I'm working on a simple project that keeps my garage door closed, as my neighbor continues to forget to close it even though we've been burglarized >:(

All the code works properly (relevant section pasted below) assuming the door is not closed manually while the loop is running. But I've been struggling with the proper way to cancel the loop if the switchstate becomes low. I tried a few different things, including a while loop, a second if statement within the loop, and ISR but to no avail. My research suggests an interrupt is the correct method as it is continuously evaluating for the state to change, but the application of that code is still a bit beyond my level. Any ideas?

void setup() {
  pinMode(8, OUTPUT);   // Relay
  pinMode(2, INPUT);    // Switch
  pinMode(13, OUTPUT);  // LED
}

void loop() {

  switchstate = digitalRead(2);

  if (switchstate == HIGH) {  // If Garage Door is open
    delay(2 * 60 * 1000UL);  // Wait a pre-determined amount of time (2 minutes)
    blink1(10);             // Warning LED blinks : 10 seconds
    blink2(10);             // Blink faster: 5 seconds
    blink3(22);             // Blink super fast: 5 seconds

    ! // Determine if switch state has changed, and if so, cancel program and return to beginning of loop
    
    digitalWrite(8, HIGH);  // Activate relay
    delay(500);             // For half a second
    digitalWrite(8, LOW);   // Relay off
    delay(1 * 1000UL);      // Program paused while door closes. (replace 1 with # of seconds this takes)
    return;                 // Return to detecting door state
    }
  }

The Loop function itself cannot be terminated as the Arduino will simply restart it every time. That said, I think what you are looking for is to detect that all those blinking warnings had the desired effect and the door has subsequently been closed.

If that is what you want, simple read the Input pin (Switch) again after blinking all those lights and skip over the part to Close the door if it is already closed. To do that, insert

switchstate = digitalRead(2); // Check the door again
if (switchstate == HIGH) { // If Garage Door is STILL open

replace the return Statement at the end with a closing brace to end the if.

That should solve your immediate Problem but be advised that you still have many other Problems to solve.

For example, digitalRead(2) may be insufficient to check the Switch because it may Need debouncing.

Assuming that the door was closed within the first warning stage (Warning LED blinks : 10 seconds), would you really want to advance to the next warning Level?

While blinking, for example, for ten seconds, would you want to immediately stop blinking if the door had been closed or would you continue to blink for the remaining 9 seconds?

Do away with delay() in your code and use switch/case to run the code for the state that the that the door may be in at any time using millis() for timing.

How many states can the door be in ?

JaBa:
The Loop function itself cannot be terminated as the Arduino will simply restart it every time.

This is the point -- the loop begins with the "if" condition, which only runs the program if the door is open. If the program is returned because the door has been closed, the program won't run again because the condition to start it hasn't been met.

JaBa:
Assuming that the door was closed within the first warning stage (Warning LED blinks : 10 seconds), would you really want to advance to the next warning Level?

No, naturally the best solution is for the program to be halted by the door being closed manually - regardless of what stage it's in. The question is whether I'll be advanced enough to code it that well.

UKHeliBob:
Do away with delay() in your code and use switch/case to run the code for the state that the that the door may be in at any time using millis() for timing.

How many states can the door be in ?

As this is my first attempt at programming, I figured I'd start with delay because it is simpler, but once I have proof of concept and feel comfortable moving on, I do plan to alter the code in this way. I suppose the door has three potential states: open, closed, and stuck in the middle. My current prototype relies solely on the door open sensor switch, though I have plans for "rev. 2" to include a door closed sensor switch allowing me to define each state accurately, and prevent the door from getting stuck half-closed.

nathanalef:
I'm working on a simple project that keeps my garage door closed, as my neighbor continues to forget to close it even though we've been burglarized >:(

All the code works properly (relevant section pasted below) assuming the door is not closed manually while the loop is running. But I've been struggling with the proper way to cancel the loop if the switchstate becomes low. I tried a few different things, including a while loop, a second if statement within the loop, and ISR but to no avail. My research suggests an interrupt is the correct method as it is continuously evaluating for the state to change, but the application of that code is still a bit beyond my level. Any ideas?

void setup() {

pinMode(8, OUTPUT);  // Relay
  pinMode(2, INPUT);    // Switch
  pinMode(13, OUTPUT);  // LED
}

void loop() {

switchstate = digitalRead(2);

if (switchstate == HIGH) {  // If Garage Door is open
    delay(2 * 60 * 1000UL);  // Wait a pre-determined amount of time (2 minutes)
    blink1(10);            // Warning LED blinks : 10 seconds
    blink2(10);            // Blink faster: 5 seconds
    blink3(22);            // Blink super fast: 5 seconds

! // Determine if switch state has changed, and if so, cancel program and return to beginning of loop
   
    digitalWrite(8, HIGH);  // Activate relay
    delay(500);            // For half a second
    digitalWrite(8, LOW);  // Relay off
    delay(1 * 1000UL);      // Program paused while door closes. (replace 1 with # of seconds this takes)
    return;                // Return to detecting door state
    }
  }

As pointed out to you - you need to control the loop()execution.
if () construct is not the best way - the code gets convoluted in a hurry.

Also in digital world you actually have only off (closed) or on (open).
To detrmine "stuck" state one of the solution is to monitor the time elapsed between changing between these two "digital" states.

Take a look at while construct / loop.
Here are some examples how your while could be controlling the loop:

while(garage closed)
wait for eternal event to start opening it - change state to opening and start openning
...

while( opening timer is running and door not open )
run opening timer and check it for expected value
flash LED during operation - make sure use non blocking flash - this my get tricky at first
...

Check what stopped the above while loop
if(is door open or timed out)
...

nathanalef:
I suppose the door has three potential states: open, closed, and stuck in the middle.

There is also 'closing' and 'opening'. Check out this garage door example. Don't get bogged down in the stage/ladder logic stuff, focus instead on the state diagrams - the concept is almost identical to a switch/case construction.

Excellent post on "stage " programming.
( even with "stage" goofy terminology )

Scroll down to step by step "how to ".

Here is another link to help program "state machine".
I am partial to "old fashioned " flow charts.

I am not sure how "user friendly" latest Arduino IDE is using YAKINDU.
I am using another IDE.

Best off luck

This is the point -- the loop begins with the "if" condition, which only runs the program if the door is open. If the program is returned because the door has been closed, the program won't run again because the condition to start it hasn't been met.

This Statement is not true. Fact is, the first line of code within the Loop function you wrote is

switchstate = digitalRead(2);

followed by the if (switchstate == HIGH)

If switchstate is not HIGH the rest of the Loop function will be skipped over. The Loop function will terminate. The Arduino Basic coding will automatically restart the Loop function and the first line of the Loop function will still be

switchstate = digitalRead(2);

Followed by the same old if Statement except that at some Point switchstate will be HIGH because the door will be open and the rest your programming will execute.

nathanalef:
As this is my first attempt at programming, I figured I'd start with delay because it is simpler, but once I have proof of concept and feel comfortable moving on, I do plan to alter the code in this way.

I don't see you being able to achieve the proof of concept using delay. Delay effectively stops execution, so once you hit the delay function, the switch won't be re-read until the delay has expired and your code returns from the loop function. To respond to the switch in real time, your code needs to return from the loop function fast enough, for the switch to be re-read before a change of switch state gets missed.

You don't need an ISR. You need to rethink the program flow. The Blink Without Delay example is about the best place to start.

I would go at this from a different perspective and ask: why is your neighbour responsible for closing your garage door in the first?

The demo Several Things at a Time is an extended example of BWoD and illustrates the use of millis() to manage timing without blocking. It may help with understanding the technique.

It is usually best to post the complete program so we can see the problem in the right context.

...R