How to break a for() loop when a button is pressed?

I want the for() loop to continue until the button is pressed/the counter becomes even... However, it is clear that once the for() loop begins, the void loop() no longer runs, so no input is read, meaning a simple break if(button is pressed) won't work...
Even after realizing this, I have no idea how to solve this problem and any help would be greatly appreciated! :pray:

Code:

const int BUTTON = A1;
const int RLED = 10;
const int GLED = 9;
const int BLED = 8;
const unsigned long debouncePeriod = 20;
unsigned long startMillis;
unsigned long currentMillis;
unsigned long debounceStartMillis;
byte previousButtonState;
byte currentButtonState;
int count = 0;
bool debouncing = false;


void setup()
{
	Serial.begin(115200);
	pinMode(BUTTON, INPUT_PULLUP);
	pinMode(RLED, OUTPUT);
	pinMode(GLED, OUTPUT);
	pinMode(BLED, OUTPUT);
	startMillis = millis();

}

void ledMode(byte mode)
{
	switch (mode)
	{
	case 1:
		digitalWrite(RLED, HIGH);	//RED
		digitalWrite(GLED, LOW);
		digitalWrite(BLED, LOW);
		delay(1000);
		break;
	case 2:
		digitalWrite(RLED, LOW);	//GREEN
		digitalWrite(GLED, HIGH);
		digitalWrite(BLED, LOW);
		delay(1000);
		break;
	case 3:
		digitalWrite(RLED, LOW);	//BLUE
		digitalWrite(GLED, LOW);
		digitalWrite(BLED, HIGH);
		delay(1000);
		break;
	case 4:
		digitalWrite(RLED, HIGH);	//Yellow
		digitalWrite(GLED, HIGH);
		digitalWrite(BLED, LOW);
		delay(1000);
		break;
	case 5:
		digitalWrite(RLED, LOW);	//TEAL
		digitalWrite(GLED, HIGH);
		digitalWrite(BLED, HIGH);
		delay(1000);
		break;
	case 6:
		digitalWrite(RLED, HIGH);	//PURPLE
		digitalWrite(GLED, LOW);
		digitalWrite(BLED, HIGH);	
		delay(1000);
		break;
	case 7:
		digitalWrite(RLED, HIGH);	//WHITE
		digitalWrite(GLED, HIGH);
		digitalWrite(BLED, HIGH);
		delay(1000);
		break;
	}
}

int RGBloop() 
{
	for (byte x = 1; x < 9; x++)
	{
		if (x == 8)
		{
			x = 1;
		}
		else if(count % 2 ==  0)
		{
			Serial.println("Button pressed.");
			break;
		}
		ledMode(x);
	}
}

int RGBoff()
{
	Serial.println("Turning off.");
	digitalWrite(RLED, LOW);
	digitalWrite(BLED, LOW);
	digitalWrite(GLED, LOW);
}


void loop()
{
	currentMillis = millis();
	previousButtonState = currentButtonState;
	currentButtonState = digitalRead(BUTTON);
	if (currentButtonState != previousButtonState)
	{
		debouncing = true;
		debounceStartMillis = currentMillis;
	}
	if (currentMillis - debounceStartMillis >= debouncePeriod)
	{
		if(debouncing == true)
		{
			if (currentButtonState == LOW)
			{
				debouncing = false;
				count++;
				Serial.println(count);
				if (count % 2 == 0)
				{
					Serial.println("Turning off.");
					RGBoff();
				}
				else if (count % 2==1)
				{
					Serial.println("Running loop function.");
					RGBloop();
					
				}
			}
		}
	}
}

Please google "arduino break from for loop"

You should know that folks here appreciate it when posters with questions have at least spent some effort to find the answer before posting. The folks here answer questions because we like to help others. When someone doesn't at least spent some time researching before posting a question it doesn't sit will with us spending our time to do what you could easily do your self.

You can also look at this to learn how to break your code up into smaller chunks. You don't have to do it all in one pass through loop()

several things at the same time

		if (x == 8)
		{
			x = 1;
		}

Read up on for loops. The above in your for loop means for never does its job.

And nothing in the loop will change count, so this

      if(count % 2 ==  0) {

never enters into changing the flow.

Use

int RGBloop() 
{
  for (byte x = 1; x < 9; x++) {
      ledMode(x);
  }
}

It still has some problems, play with it here:

The button is ignored until the sequence is finished and all LEDs are on.

Then +1 @blh64 several things at the same time

There may be some things in your code that can be salvaged.

a7

I don't mean to cause any hardship, and I already did search on google...
I'm already well aware of break;. The issue is when I want to break the loop if the button is pressed, I don't see anyway of doing so given that the computer is set to loop the different RGB modes within the for() loop.

I added the below code so that it would loop and reset to mode 1.

if (x == 8)
		{
			x = 1;
		}

I suppose another way of explaining my problem is that I essentially want to run two loops simultaneously, but I'm unaware as to how to do so...

The void loop() to check for a button state change, and then the RGB loop to start once it is pressed. But also have it stop once the button is pressed again, which would require the void loop()to continue running....

Could you not put an if statement in your loop:

if (GPIOx == 1) break;

1 Like

That's what I originally tried, but it doesn't recognize if (GPIOx == 1), because it is stuck in switching LED modes. The main loop, which checks if (GPIOx == 1), does not run while it does switch LED modes.

Which is why I was hoping there was a way to have both loops run at once...

I did look at several things at the same time , but I can't open the link within the post. I will have to study it more in depth when I get the chance, I just thought there was simpler solution, such as changing the for() loop's position.

Add another if statement in the LED modes loop.

To do several things at "the same time" is really simple.

There is a millis() function that counts milliseconds. You simply use the millis() in your main loop to determine what gets run next.
See Arduino reference.

the basics are:

in setup:
variableoldmillis = millis()

on loop:
if (variableoldmillis => millis + howmanymillisbeforeyouwantsomecodetorun){
    then run code#1
}

if (variableoldmillis => millis + howmanymillisbeforeyouwantanother codeun){
    then run code#2
}


just before end of loop
variableoldmillis = millis()
1 Like

Thank you very much for your help! I will study this more deeply tmrw morning...

Sorry again for any trouble, as beginner I'm just starting to adapt to the forum, so forgive me for any disrespect I may have accidentally presented.

I have nothing but respect for all of you, it's impressive enough that you guys can code so well, not to mention teaching others. :pray: :slightly_smiling_face:

The simplest way would be to read the button in the for-loop and react on that. The better way would be not to use for-loops or while-loops. As mentioned earlier, break your for-loop in small pieces.

int RGBloop()
{
    // loop counter
    static byte x = 1;
    
    if (x == 8)
    {
      x = 1;
    }

    ledMode(x);
    x++;
  }
}

The static keyword indicates that the variable will be remembered between calls (it makes x act as a global variable but x will only be known inside RGBloop()).

The above code needs to be called repeatedly from loop() and with the exception of the reacting on the button will do the same as your original.

void loop()
{
    RGBloop();
}

You can also make x a global variable which might make life easier if you always want to start from 1 after an interruption; in that case I suggest that you rename x to e.g. loopCounter.


byte loopCounter = 1;
...
...

void setup()
{
...
...
}

void loop()
{
    RGBloop();
}

int RGBloop()
{
    if (loopCounter == 8)
    {
      loopCounter = 1;
    }

    ledMode(loopCounter);
    loopCounter++;
  }
}

In loop(), you can now detect button presses and react on them. Below would be a slight modification of your original loop().

void loop()
{
  currentMillis = millis();
  previousButtonState = currentButtonState;
  currentButtonState = digitalRead(BUTTON);
  if (currentButtonState != previousButtonState)
  {
    debouncing = true;
    debounceStartMillis = currentMillis;
  }
  if (currentMillis - debounceStartMillis >= debouncePeriod)
  {
    if (debouncing == true)
    {
      if (currentButtonState == LOW)
      {
        debouncing = false;
        count++;
        Serial.println(count);
        if (count % 2 == 0)
        {
          Serial.println("Turning off.");
          RGBoff();
          
          // optional, reset loopCounter if you want RGBloop to start from 1 again if count equals 1
          loopCounter = 1;
        }
        else if (count % 2 == 1)
        {
          Serial.println("Running loop function.");
          RGBloop();

        }
      }
    }
  }
}

Note:
Codes not tested nor compiled; just to give you the idea.

1 Like

Thank you so much! This solution makes much more sense and completely avoids the issue of needing two loops to run simultaneously.

I had completely forgotten that you could use the increment operation without a for/while() loop! :sweat_smile: