Loop() Function Question

Hi all,

I am new to the Arduino and I have come up with some code that I don’t understand. I’m not looking to “fix” my code, merely understand what is happening.

What is the second loop() function doing in the code posted at the bottom of this post? I was going through the starter projects book and just finished the second project. For those that don’t know: there are two red lights, a green light and a switch. The original code was designed such that the neutral state would be to have the green light only on. When the switch was pressed, the green light would turn off, one red light would turn on and the other red light would blink for as long as the switch was pressed.

Leaving the circuit the same, I was playing around the code and came up with something that is giving me weird behaviour. I think it stems from me not understanding how the loop() function works.

With the code below, when the button is held, the green light flashes until the button is released. That part I get. What is weird however is that when the switch is released, the code starts from the beginning like it should when the switch is off (i.e. switchState == LOW) and turns on the green light but once it does that, the code executes all the code in the else statement that was after the loop() function.

For example. I start with no switch pressed. There is a solid green light. I press and hold the switch. The green light flashes for as long as I’m holding the switch, let’s say 15 cycles of on and off. When I release the button, the green light turns on and then the first red light will turn on and the second red light will flash the same number of times the green light flashed.

I guess I have two questions: What happens when the loop() is called in the else statement and how does the code “store” the remaining code and know to execute it the correct number of times after the else statement is false?

Anyone have any idea? This has left me quite puzzled. I can maybe try to get a video of the lights in action if my description was unclear.

Code below:

int switchState = 0;

void setup(){
 pinMode(2, INPUT);
 pinMode(3, OUTPUT);
 pinMode(4, OUTPUT);
 pinMode(5, OUTPUT);
}

void loop(){
 switchState = digitalRead(2);

 if (switchState == LOW) {
 // The Button is not pressed
   digitalWrite(3, HIGH);
   digitalWrite(4, LOW);
   digitalWrite(5, LOW);    
 }

 else {
 // The Button is pressed
   digitalWrite(3, LOW);
   delay(100);
   digitalWrite(3, HIGH);
   delay(100);
   loop();
     //digitalWrite(3, LOW); //This line was removed for troubleshooting. If I leave it in, the green light turns off when the red lights turn on.
     digitalWrite(4, HIGH);
     digitalWrite(5, HIGH);

     delay(250); //Wait for a quarter second
     //Toggle LEDs
     digitalWrite(4, HIGH);
     digitalWrite(5, LOW);
     delay(250);
 }
} //Go back to the beginning of the loop
 else {
  // The Button is pressed
    digitalWrite(3, LOW);
    delay(100);
    digitalWrite(3, HIGH);
    delay(100);
    loop();

Calling loop from within loop is a bad bad thing. This is called recursion. Any function that calls itself is recursion.

What happens is that the first call to loop calls loop. Now this first call never exits, it called loop. That loop calls loop instead of exiting. All those functions that haven't exited are building up on the stack. Eventually, the stack crashes into the heap and the whole thing crashes.

You should (almost) NEVER be calling loop from inside loop. There are some very edge cases where it is OK or even necessary, but you should stay far far away from that unless you know EXACTLY what you are doing and how to end the recursion and let all the previous calls exit.

Remember, loop is just a function. It's not any different from any other function. The only reason that it is special in Arduino world is because main calls it over and over again. But aside from that fact, it is no different to any other function you might write.

If there's a need to do some of the stuff currently parked in loop() under some circumstances, but not every time through loop(), you could most likely put that stuff in another function, void stuff() say.

Then in loop() you have a test in an if, and if it's appropriate you dive out and do stuff(). Once stuff()'s done, control goes back to where you were in loop().

That might answer your question about it "storing" the rest of the code.

Please use code tags (</> button on the toolbar) when you post code or warning/error messages. The reason is that the forum software can interpret parts of your code as markup, leading to confusion, wasted time, and a reduced chance for you to get help with your problem. This will also make it easier to read your code and to copy it to the IDE or editor. Using code tags and other important information is explained in the How to use this forum post. Please read it.

Thanks for your help all. I get it now. I didn't fully understand that when I was starting

void loop()

I was making a function called loop() that did everything within the {}. When I called the loop() function again in the else statement, I was returning to the top of the function while still in the function. This repeated for as long as I held the button. The reason the red button flashes the correct amount of times when I release the button is because the last loop function will flow down the if statement that doesn't call loop and the cycle breaks. When that happens, the last loop function is satisfied and the remainder of the else statement is completed. Then that loop function is satisfied and the previous iteration of the else statement is completed. This repeats for as many times as the else statement is allowed to run.

Again, thanks for the responses!