Interrupting a loop?

Please can someone help me. I have a sketch running a series of loops to PWM an RGB LED from one colour to the next. How do I set it so that when a button is pressed it leaves the loop and does something else instead without having code inside every loop to detect a button press? I am guessign I could use interrupts but have not had much success getting them to work.

There is no single best implementation, how you do it depends on the application. There is nothing wrong with repeating code in your loops.

Here is one approach:

  for (int i = 0; i < 10; i++) {
     // do something here;
     if( digitalRead(switchPin) == LOW)
       break;  // terminate the loop if switch pressed
     delay(100);  
  }

If your loops call delay and you need to terminate the delay when the switch is pressed you could so something like this:

// a function to delay the given value unless a switch is pressed 
// returns true if switch pressed, else returns false
// switch state is checked every millisecond
boolean myDelay( int value ){
     while(value--){
         if( digitalRead(switchPin) == LOW){
             return true; // return true if switch pressed      
         }
         delay(1);
     } 
}


 for (int i = 0; i < 10; i++) {
     // do something here;
     if( myDelay(100) == true ) {
       // here when switch is pressed  
       break;  
     }
  }

There is nothing wrong with repeating code in your loops.

Do be careful about the code you repeat. Copied code is one of the most common ways to introduce bugs and make understanding and maintaining the program more difficult than necessary.

If you find that you are repeating code consider pulling that code into a function, or, if you can't afford the overhead of a function call, use a define to put the code inline.

Later if it is necessary to change the code you'll be less likely to miss something or change something that should not have been changed. It's usually also easier to read the code if you've chosen an appropriate name.

It seems like a trivial or silly thing to do in simple sketches, but like other aspects of learning to code, it is something you should practice in simple situations so you know what works best when you need it.

Dave, I think the OP was looking for some single global way to terminate loops when a button was pressed.
I completely agree about problems with cut and paste, but not sure how you expect the OP to use the advice in this context.

Are you suggesting replacing the example above

 for (int i = 0; i < 10; i++) {
     // do something here;
     if( digitalRead(switchPin) == LOW)
       break;  // terminate the loop if switch pressed
     delay(100);  
  }

With

  for (int i = 0; i < 10; i++) {
     // do something here;
     if( checkSwitch(switchPin))
       break;  // terminate the loop if switch pressed
     delay(100);  
  } 
  
boolean checkSwitch(int switchPin){
// return true if the given switch is pressed  
   return  digitalRead(switchPin) == LOW;
}

Without knowing more about the code the OP is using or considering I can't say specifically how he might apply that advice.

In your example rather than checkSwitch() I might use a userInputAvailable() function which can check a variety of user inputs without necessarily implying anything about the nature of those inputs or when they had been checked. Information about these inputs might be stored in global vars that could be updated either by a routine that polls the inputs at the time of the call, or they could be updated by an ISR (thus capturing the input immediately via the ISR and then doing the more time-consuming processing at convenient times in the main loop).

Structuring the routine to check for a more abstract idea (user input available) rather than a specific condition (pin x low) allows one to more easily change the implementation details of how user input is acquired(perhaps in a later iteration of the design input can also come from the serial port), while reducing the impact of the change on other areas of the application and while (hopefully) expressing the intention of the code more precisely (that is, it isn't the state of the pin that is important, but that there is user input to process).

This is of course an ideal and the sort of thing that is very much open to personal preference. The details of how one structures one's code is as much art as it is science, IMO, and so quite open to individual interpretation.

The program is simply to control two RGB LED's for a lamp. It transitions the two LED's from one random colour to another (different colours per LED).

Whilst it is doing that, I want it to look out for button presses or a potentiometer input so that I can adjust the time of the transition and delay inbetween transitions.

Why not post the code so we can have a look

I can post the code for the RGB lamp but I have't added any button code yet. Will post the code tonight when I get home.

This is the code I am using to control the LED's :-

float RGB1[3];
float RGB2[3];
float RGB3[3];
float RGB4[3];
float INC1[3];
float INC2[3];

int red1, green1, blue1;
int red2, green2, blue2;

int RedPin1 = 10;
int GreenPin1 = 11;
int BluePin1 = 9;

int RedPin2 = 3;
int GreenPin2 = 5;
int BluePin2 = 6;

int ledPin = 13; // choose the pin for the LED
 
void setup() 
{ 
  Serial.begin(9600);
  randomSeed(analogRead(0));
  
  RGB1[0] = 0;
  RGB1[1] = 0;
  RGB1[2] = 0;
  
  RGB2[0] = random(256);
  RGB2[1] = random(256);
  RGB2[2] = random(256);  
  
  RGB3[0] = 0;
  RGB3[1] = 0;
  RGB3[2] = 0;
  
  RGB4[0] = random(256);
  RGB4[1] = random(256);
  RGB4[2] = random(256);  

} 
 
void loop() 
{ 
  randomSeed(analogRead(0));
  
  for (int x=0; x<3; x++) {
    INC1[x] = (RGB1[x] - RGB2[x]) / 256;
    INC2[x] = (RGB3[x] - RGB4[x]) / 256; } 
  
  for (int x=0; x<256; x++) {
    
    red1 = int(RGB1[0]);
    green1 = int(RGB1[1]);
    blue1 = int(RGB1[2]);
    
    red2 = int(RGB3[0]);
    green2 = int(RGB3[1]);
    blue2 = int(RGB3[2]);

    analogWrite (RedPin1, red1);  
    analogWrite (GreenPin1, green1);   
    analogWrite (BluePin1, blue1);     
    
    analogWrite (RedPin2, red2);  
    analogWrite (GreenPin2, green2);   
    analogWrite (BluePin2, blue2);     
    delay(150);  
    
    RGB1[0] -= INC1[0];
    RGB1[1] -= INC1[1];    
    RGB1[2] -= INC1[2];   
   
    RGB3[0] -= INC2[0];
    RGB3[1] -= INC2[1];    
    RGB3[2] -= INC2[2];    
    

  }
  
  for (int x=0; x<3; x++) {
  RGB2[x] = random(556)-300;
  RGB2[x] = constrain(RGB2[x], 0, 255); 
  
  RGB4[x] = random(556)-300;
  RGB4[x] = constrain(RGB4[x], 0, 255); 
  delay(10000);
 }
}

..and I want to add in a part to increase or decrease the speed of the colour change and also the delay inbetween the transitions depending on either a button press or the value from a potentiometer.

I have added some functionality to the delay example code posted in reply#2 and put it into your sketch to give you an idea of how you can do what you want. You will need to tweek the range of delay values and how fast they are changed by the button.
You may also want to change the code so it doesn't immediately terminate the delay (and this could need debouncing) , but I hope this gives you an idea of how to proceed.

Good luck!

float RGB1[3];
float RGB2[3];
float RGB3[3];
float RGB4[3];
float INC1[3];
float INC2[3];

int red1, green1, blue1;
int red2, green2, blue2;

int RedPin1 = 10;
int GreenPin1 = 11;
int BluePin1 = 9;

int RedPin2 = 3;
int GreenPin2 = 5;
int BluePin2 = 6;

int ledPin = 13; // choose the pin for the LED
int changeIncBtn = 2; // pin for change button
int changeDecBtn = 3; // pin for change button
int transitIncBtn = 4; // pin for transit button
int transitDecBtn = 5; // pin for transit button

int changeDelay = 150; // color change delay
int transitDelay = 10000; // delay between transition

void setup()
{
  Serial.begin(9600);
  randomSeed(analogRead(0));

  RGB1[0] = 0;
  RGB1[1] = 0;
  RGB1[2] = 0;

  RGB2[0] = random(256);
  RGB2[1] = random(256);
  RGB2[2] = random(256);

  RGB3[0] = 0;
  RGB3[1] = 0;
  RGB3[2] = 0;

  RGB4[0] = random(256);
  RGB4[1] = random(256);
  RGB4[2] = random(256);

}

void loop()
{
  randomSeed(analogRead(0));

  for (int x=0; x<3; x++) {
    INC1[x] = (RGB1[x] - RGB2[x]) / 256;
    INC2[x] = (RGB3[x] - RGB4[x]) / 256; 
  }

  for (int x=0; x<256; x++) {

    red1 = int(RGB1[0]);
    green1 = int(RGB1[1]);
    blue1 = int(RGB1[2]);

    red2 = int(RGB3[0]);
    green2 = int(RGB3[1]);
    blue2 = int(RGB3[2]);

    analogWrite (RedPin1, red1);
    analogWrite (GreenPin1, green1);
    analogWrite (BluePin1, blue1);

    analogWrite (RedPin2, red2);
    analogWrite (GreenPin2, green2);
    analogWrite (BluePin2, blue2);
    delay(changeDelay);

    RGB1[0] -= INC1[0];
    RGB1[1] -= INC1[1];
    RGB1[2] -= INC1[2];

    RGB3[0] -= INC2[0];
    RGB3[1] -= INC2[1];
    RGB3[2] -= INC2[2];


  }

  for (int x=0; x<3; x++) {
    RGB2[x] = random(556)-300;
    RGB2[x] = constrain(RGB2[x], 0, 255);

    RGB4[x] = random(556)-300;
    RGB4[x] = constrain(RGB4[x], 0, 255);
    delay(transitDelay);
  }
}

// a function to delay the given value unless a switch is pressed
// returns true if a switch is pressed, else returns false
// switch state is checked every millisecond
boolean myDelay( int value ){
  while(value--){
    if( digitalRead(changeIncBtn) == LOW){
      if(++changeDelay > 1000)
        changeDelay = 1000; // limit max time for color change
    }
    if( digitalRead(changeDecBtn) == LOW){
      if(--changeDelay < 10)
        changeDelay = 10; // limit min time for color change      
      return true; // return true if switch pressed
    }
    if( digitalRead(transitIncBtn) == LOW){
      if(++transitDelay > 30000)
        transitDelay = 30000; // limit max time for color change
    }    
    if( digitalRead(transitDecBtn) == LOW){
      if(--transitDelay < 10)
        transitDelay = 10; // limit min time for color change      
      return true; // return true if switch pressed
    }
    delay(1);
  }
}

That's great. Thanks for that. I will give that a try this weekend.