How to exit a loop based on momentary input?

Hello everyone!
I am just starting my journey with Arduino and this is one little project I’m doing where i have got myself stuck. I am using momentary push buttons to switch an RGD LED between Off, Red, Green, Blue, and a color changing loop. The problem is i can’t figure out how to break out of the color changing loop and return to the if statements when one of the other inputs is pressed. Any help is greatly appreciated!

/*Will set an RGB LED to either OFF, Red, Blue, Green, or Alternating between colors when buttons A through E are pressed
*/
//define pins
#define RED 2
#define GREEN 3
#define BLUE 4
int buttonApin = 8;
int buttonBpin = 9;
int buttonCpin = 10;
int buttonDpin = 11;
int buttonEpin = 12;


void setup() {
pinMode(RED, OUTPUT);
pinMode(GREEN, OUTPUT);
pinMode(BLUE, OUTPUT);
pinMode(buttonApin, INPUT_PULLUP);
pinMode(buttonBpin, INPUT_PULLUP);
pinMode(buttonCpin, INPUT_PULLUP);
pinMode(buttonDpin, INPUT_PULLUP);
pinMode(buttonEpin, INPUT_PULLUP);
digitalWrite(RED, HIGH);
digitalWrite(GREEN, LOW);
digitalWrite(BLUE, LOW);
}

//define variables
int redValue;
int greenValue;
int blueValue;
#define delayTime 10

// Main Loop
void loop() {  
  if (digitalRead(buttonEpin) == LOW)
    {
      redValue = 0;
      greenValue = 0;
      blueValue = 0;
      digitalWrite(RED, redValue);
      digitalWrite(GREEN, greenValue);
      digitalWrite(BLUE, blueValue);
    }
  if (digitalRead(buttonApin) == LOW)
    {
      redValue = 255;
      greenValue = 0;
      blueValue = 0;
      digitalWrite(RED, redValue);
      digitalWrite(GREEN, greenValue);
      digitalWrite(BLUE, blueValue);
    }
  if (digitalRead(buttonBpin) == LOW)
    {
      redValue = 0;
      greenValue = 255;
      blueValue = 0;
      digitalWrite(RED, redValue);
      digitalWrite(GREEN, greenValue);
      digitalWrite(BLUE, blueValue);
    }
      if (digitalRead(buttonCpin) == LOW)
    {
      redValue = 0;
      greenValue = 0;
      blueValue = 255;
      digitalWrite(RED, redValue);
      digitalWrite(GREEN, greenValue);
      digitalWrite(BLUE, blueValue);
    }
   if (digitalRead(buttonDpin) == LOW)
    {
      loop();
      redValue = 255; // choose a value between 1 and 255 to change the color.
      greenValue = 0;
      blueValue = 0;
      for(int i = 0; i < 255; i += 1) // fades out red bring green full when i=255
      {
      redValue -= 1;
      greenValue += 1;
      analogWrite(RED, redValue);
      analogWrite(GREEN, greenValue);
      delay(delayTime);
      }
      redValue = 0;
      greenValue = 255;
      blueValue = 0;      
      for(int i = 0; i < 255; i += 1) // fades out green bring blue full when i=255
      {
      greenValue -= 1;
      blueValue += 1;
      analogWrite(GREEN, greenValue);
      analogWrite(BLUE, blueValue);
      delay(delayTime);
      }
      redValue = 0;
      greenValue = 0;
      blueValue = 255;   
      for(int i = 0; i < 255; i += 1) // fades out blue bring red full when i=255
      {
      blueValue -= 1;
      redValue += 1;
      analogWrite(BLUE, blueValue);
      analogWrite(RED, redValue);
      delay(delayTime);
      }
         
    }
}

Those for loops are blocking. The way you have it now that whole for loop has to complete before you wrap back around to reading buttons. You can either rewrite the code so that instead of running straight all the way through the for loop it just takes one step at a time in an if.

Or you could read the button inside the for and use break but that might get ugly if the code grows much more.

I have the for statements looped to repeat the fade in and out. That was one problem i found earlier is the fade would only happen once until i looped it. I could exit it then once the for statements completed, but now that i have looped them i can't exit back up the main loop to the if statements for the buttons.

Yeah. I told you what to do. Take all of that code out and write a simple sketch that just fades in and out with no for loops. Let the loop function do the looping.

War_Junky_91:

   if (digitalRead(buttonDpin) == LOW)

{
      loop();

In addition to what Delta_G said, you need to get rid of that call to loop(). You should never call loop().

Oh wow. How did I miss that one. Yeah, that's a really bad idea.

Either way, the progression will be:

  1. Figure out how to fade an LED on and off with no for loops. No other code, just a simple sketch that does that alone.

  2. Modify the sketch in 1 so that it doesn't use delay either

  3. Start adding back the other parts.

It appears you have not looked at or understand how to do basic programming.
Please look at the the examples that came with the IDE.

.

pert:
In addition to what Delta_G said, you need to get rid of that call to loop(). You should never call loop().

Why should i never call a loop? The reason i put in the loop was because it would only cycle through the colors once and then stop. What would be a better way to do it?

Delta_G:
Either way, the progression will be:

  1. Figure out how to fade an LED on and off with no for loops. No other code, just a simple sketch that does that alone.

  2. Modify the sketch in 1 so that it doesn’t use delay either

  3. Start adding back the other parts.

This sketch:https://www.arduino.cc/en/Tutorial/ColorCrossfader from the Ardunio site itself is doing the color changing LED similarly but it still uses a for, not looping quite like how my code is, but you are saying i shouldn’t use a for at all? Why should i not use a delay?

larryd:
It appears you have not looked at or understand how to do basic programming.
Please look at the the examples that came with the IDE.

.

Good catch, i’m brand new at this and trying to learn. The color changing part of the sketch comes straight from an example sketch that i got with my starter kit, i just added the loop and nested it under an if statement.

Why should i never call a loop?
The way things work are as follows.
setup() runs once at restart
loop() runs automatically after setup() then at the end of loop() executions goes back to the start of loop(), ad infinitum.

The reason i put in the loop was because it would only cycle through the colors once and then stop. What would be a better way to do it?
You can write functions that are 'called' based on certain conditions.
One of those conditions can be a flag.
As long as the flag is true the function can be called.
At some point the flag is made false which prevents the function from being called again.

if( myFlag == true && x == 10)
{
myFunction(); // calling the function myFunction()
}
. . .
myFlag = false; // happens somewhere else in the sketch

Why should i not use a delay.
delay() freezes all program execution until the delay time is over, this is very bad :wink:
The BWD example in the IDE explains how to not use delay()

/* Blink without Delay

 Turns on and off a light emitting diode (LED) connected to a digital
 pin, without using the delay() function.  This means that other code
 can run at the same time without being interrupted by the LED code.

 The circuit:
 * LED attached from pin 13 to ground.
 * Note: on most Arduinos, there is already an LED on the board
 that's attached to pin 13, so no hardware is needed for this example.

 created 2005
 by David A. Mellis
 modified 8 Feb 2010
 by Paul Stoffregen
 modified 11 Nov 2013
 by Scott Fitzgerald


 This example code is in the public domain.

 http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
 */

// constants won't change. Used here to set a pin number :
const int ledPin =  13;      // the number of the LED pin

// Variables will change :
int ledState = LOW;             // ledState used to set the LED

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change :
const long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the
  // difference between the current time and last time you blinked
  // the LED is bigger than the interval at which you want to
  // blink the LED.
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

.

Maybe have a look at the demo Several Things at a Time which illustrates repetition without using FOR or WHILE.

And this is a more extensive example Planning and Implementing a Program

...R