how to exit a sequence if variable changes

I'm hitting a brick wall and was hoping someone might be able to shed some light on my situation.

Essentially I'm programming an LED playback controller on an Uno that plays an effect sequence back depending on a DIP switch state. The sketch has ended up quite long, but in essence the parts are:

void loop() {
-read input pins from dip switch states, returns two values, x10 value and x1 value-
if (x10 == 0) {
-runs effect sequence 0, x1 value controls delay for fade timing control-
}
if (x10 == 1) {
-runs effect sequence 1, x1 value controls delay for fade timing control-
}
etc etc.
}

My issue is that if I change the x10 value on the dip switches while an effect sequence is mid-run, it does not start running the 'new' sequence selected until after the current one finishes and returns to its first 'for' step, then runs the 'new' sequence.

Each sequence is a grouping of 'for' actions to fade an LED channel in or out in sequence.

I tried inserting

if (x10 != 'current sequence number) {
break;
}

but this didn't seem to work.

Currently my sketch is all in one void loop(), if I break it out in to separate void x()'s referenced by the main void loop() would the break command kick it out to the new sequence?? As in:

void loop() {
-read input pins from dip switch states, returns two values, x10 and x1-
if (x10 == 0) {
seq0();
}
if (x10 == 1) {
seq1();
}
etc etc.
}

void seq0() {
-runs effect sequence 0, x1 value controls delay for fade timing control-
}

void seq1() {
-runs effect sequence 1, x1 value controls delay for fade timing control-
}
etc etc

Or is there a better way to be doing this? It's late now where I am so I am stepping away for the night without trying to break it down in to separate voids. I also saw 'while' might be something to try instead of 'if'.

Any advice is greatly appreciated, thank you.

Code tags, please.

How long do your defined sequences go for?
Can you provide an example of one?

I would use your second suggestion,placing the sequences within methods() but have checks within the methods which allows early exit of the method if the dip switches change.

We can only guess at you problem because you have not posted all your code and you have not posted it correctly so read the how to use this forum sticky post.

My guess is you are using delays or some other blocking code and you need youse the technique in the link without delay example. This is known as a state machine.

I was trying to avoid throwing the whole code up as it has become longer than I thought anyone would care to read but I'll throw up my void loop() (or as much as I can fit)

void loop() {
  currentTime = millis();
  lastPacket = DMXSerial.noDataSince();

  // SET/UPDATE ADDRESS AND X VALUES
  if (currentTime >= (loopTimeAdd + 250))    //  CHECKS FOR NEW ADDRESS/X VALUES EVERY .25 SECOND
  {
    -TRUNCATED TO LIMIT CHARACTERS - THIS PART WORKING AS INTENDED -
  }

  // DMX MODE
  if (X100 <= 5)
  {
    if(lastPacket <= LOSSTIMER)
    {
        -TRUNCATED TO LIMIT CHARACTERS - THIS PART WORKING AS INTENDED -
  }

  //  600 SERIES - STATIC COLOUR - X10 SELECTS COLOUR - X1 SELECTS INTENSITY
  if (X100 == 6)
  {
    //  SET BRIGHTNESS
    if (X1 == 0)
    {
      BRIGHT = 10;
    }
    else if (X1 > 0)
    {
      BRIGHT = X1;
    }

    //    SET COLOUR
    if (X10 == 1)    // RED
    {
           -TRUNCATED TO LIMIT CHARACTERS - THIS PART WORKING AS INTENDED -
    }
  }

  // 700 SERIES - EFFECTS - X10 SELECTS SEQUENCE - X1 SELECTS SPEED
  if (X100 == 7)
  {
    // RAINBOW FADE FORWARD
    if (X10 == 0)
    {
      if (X1 == 0)
      {
        DELAY = 10;
      }
      else if (X1 > 0)
      {
        DELAY = X1;
      }
      for (G = 0; G < 255; G++) {      // add green, GREEN (AMBER)
        analogWrite (GRN, G);
        delay ((DELAY * 500) / 26);
      }
      if (R == 255)
      {
        for (R = 255; R > 0; R--) {    // (minus red, GREEN)
          analogWrite (RED, R);
          delay ((DELAY * 500) / 26);
        }
      }
      for (B = 0; B < 255; B++) {      // add blue, BLUE AND GREEN
        analogWrite (BLU, B);
        delay ((DELAY * 500) / 26);
      }
      for (G = 255; G > 0; G--) {      // minus green, BLUE
        analogWrite (GRN, G);
        delay ((DELAY * 500) / 26);
      }
      for (R = 0; R < 255; R++) {      // add red, BLUE AND RED
        analogWrite (RED, R);
        delay ((DELAY * 500) / 26);
      }
      for (B = 255; B > 0; B--) {      // minus blue, RED
        analogWrite (BLU, B);
        delay ((DELAY * 500) / 26);
      }
    }

    // RAINBOW STEP FORWARD
    if (X10 == 1)
    {
      if (X1 == 0)
      {
        DELAY = 10;
      }
      else if (X1 > 0)
      {
        DELAY = X1;
      }
      if (currentTime >= (loopTime + ((DELAY)*1000)))
      {
        C += 1;
        if (C > 6) {
          C = 1;
        }
        COLOUR = C;
        loopTime = currentTime;
      }
      if (COLOUR == 1)
      {
        analogWrite (RED, 0);    // GREEN
        analogWrite (GRN, 255);
        analogWrite (BLU, 0);
      }
      if (COLOUR == 2)
      {
        analogWrite (RED, 0);    // CYAN
        analogWrite (GRN, 255);
        analogWrite (BLU, 255);
      }
      if (COLOUR == 3)
      {
        analogWrite (RED, 0);    // BLUE
        analogWrite (GRN, 0);
        analogWrite (BLU, 255);
      }
      if (COLOUR == 4)
      {
        analogWrite (RED, 255);    // MAGENTA
        analogWrite (GRN, 0);
        analogWrite (BLU, 255);
      }
      if (COLOUR == 5)
      {
        analogWrite (RED, 255);    // RED
        analogWrite (GRN, 0);
        analogWrite (BLU, 0);
      }
      if (COLOUR == 6)
      {
        analogWrite (RED, 255);    // AMBER
        analogWrite (GRN, 255);
        analogWrite (BLU, 0);
      }
    }

    // RAINBOW FADE REVERSE
    if (X10 == 2)
    {
      if (X1 == 0)
      {
        DELAY = 10;
      }
      else if (X1 > 0)
      {
        DELAY = X1;
      }
      for (R = 0; R < 255; R++) {        // add red, RED
        analogWrite (RED, R);
        delay ((DELAY * 500) / 26);
      }
      if (G == 255)
      {
        for (G = 255; G > 0; G--) {      // (minus GREEN, RED)
          analogWrite (GRN, G);
          delay ((DELAY * 500) / 26);
        }
      }
      for (B = 0; B < 255; B++) {       // add blue, BLUE AND RED
        analogWrite (BLU, B);
        delay ((DELAY * 500) / 26);
      }
      for (R = 255; R > 0; R--) {       // minus red, BLUE
        analogWrite (RED, R);
        delay ((DELAY * 500) / 26);
      }
      for (G = 0; G < 255; G++) {      // add green, BLUE AND GREEN
        analogWrite (GRN, G);
        delay ((DELAY * 500) / 26);
      }
      for (B = 255; B > 0; B--) {      // minus blue, GREEN
        analogWrite (BLU, B);
        delay ((DELAY * 500) / 26);
      }
    }

    // RAINBOW STEP REVERSE
//etc etc

}

It's in the X100=7 section that I'm tripping up. As it runs an X10=? sequence it won't register the change in address until after the current one completes, which can be quite a long time if the X1 value has been set high (X1 acting as a time control), so I need some way for the code to continue to check if the X10 value is still set as it's running each piece.

I'm going to do a save as and try breaking it down in to separate voids with break; ifs and see if that works.

Are you doing shading around the HSL circle? Looks like you are with that code. Or at least part of it. It's hard to tell.

Those delays in the sequence are what's killing you. You'll need to massively restructure your code in order to deal with that. Work on splitting it into subroutines for each sequence, then we can start restructuring.

BTW, I have a sketch that does HSL shading of the backlight of an RGB LCD screen in a non-blocking way. I'll post it here so you can see what I did and possibly get inspiration. It's far from the best I could have done, but I can help you out understanding it if you need.

/*
  LiquidCrystal Library - Hello World
 
 Demonstrates the use a 16x2 LCD display.  The LiquidCrystal
 library works with all LCD displays that are compatible with the 
 Hitachi HD44780 driver. There are many of them out there, and you
 can usually tell them by the 16-pin interface.
 
 This sketch prints "Hello World!" to the LCD
 and shows the time.
 
  The circuit:
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 5
 * LCD D5 pin to digital pin 4
 * LCD D6 pin to digital pin 3
 * LCD D7 pin to digital pin 2
 * LCD R/W pin to ground
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)
 
 Library originally added 18 Apr 2008
 by David A. Mellis
 library modified 5 Jul 2009
 by Limor Fried (http://www.ladyada.net)
 example added 9 Jul 2009
 by Tom Igoe
 modified 22 Nov 2010
 by Tom Igoe
 
 This example code is in the public domain.

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

// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

char hex_str[3];
char bar[16];

byte line_char[8] = {
  B00000,
  B00000,
  B11111,
  B11111,
  B11111,
  B11111,
  B00000,
  B00000
};

void setup() {
  // set up the LCD's number of columns and rows: 
  lcd.begin(20, 4);
  // Print a message to the LCD.
  lcd.print("RGB Backlight");
  lcd.setCursor( 0, 1 );
  lcd.print( "R: 0x" );
  lcd.setCursor( 0, 2 );
  lcd.print( "G: 0x" );
  lcd.setCursor( 0, 3 );
  lcd.print( "B: 0x" );
  lcd.createChar( 0, line_char );
  pinMode(13,OUTPUT);
}

void loop() {
  
  long time = millis()/25;
  time = time%360;
  int time_index = time / 60;
  
  lcd.setCursor( 18, 0 );
  lcd.print( time_index );
  
  //lcd.setCursor(0,2);
  //lcd.print(time_index);
  
  byte red;
  byte gre;
  byte blu;
  
  switch(time_index)
  {
    case 0:
      red = 0x00;
      gre = map( time, 0, 60, 0xFF, 0x00 );
      blu = 0xFF;
      break;
    case 1:
      red = map( time, 60, 120, 0x00, 0xFF );
      gre = 0x00;
      blu = 0xFF;
      break;
    case 2:
      red = 0xFF;
      gre = 0x00;
      blu = map( time, 120, 180, 0xFF, 0x00 );
      break;
    case 3:
      red = 0xFF;
      gre = map( time, 180, 240, 0x00, 0xFF );
      blu = 0x00;
      break;
    case 4:
      red = map( time, 240, 300, 0xFF, 0x00 );
      gre = 0xFF;
      blu = 0x00;
      break;
    case 5:
      red = 0x00;
      gre = 0xFF;
      blu = map( time, 300, 360, 0x00, 0xFF );
      break;
  }
  
  lcd.setCursor(5, 1);
  sprintf( hex_str, "%.2X", 0xFF-red );
  lcd.print( hex_str );
  lcd.setCursor(5, 2);
  sprintf( hex_str, "%.2X", 0xFF-gre );
  lcd.print( hex_str );
  lcd.setCursor(5, 3);
  sprintf( hex_str, "%.2X", 0xFF-blu );
  lcd.print( hex_str );
  
  lcd.setCursor( 10, 1 );
  for( int i=0; i<10; i++ )
  {
    if( i<map( red, 0xFF, 0x00, 0, 10 ) )
    {
      byte ii = 0;
      lcd.write( ii );
    }
    else
    {
      lcd.print( " " );
    }
  }
  
  lcd.setCursor( 10, 2 );
  for( int i=0; i<10; i++ )
  {
    if( i<map( gre, 0xFF, 0x00, 0, 10 ) )
    {
      byte ii = 0;
      lcd.write( ii );
    }
    else
    {
      lcd.print( " " );
    }
  }
  
  lcd.setCursor( 10, 3 );
  for( int i=0; i<10; i++ )
  {
    if( i<map( blu, 0xFF, 0x00, 0, 10 ) )
    {
      byte ii = 0;
      lcd.write( ii );
    }
    else
    {
      lcd.print( " " );
    }
  }
  
  analogWrite( 6, red );
  analogWrite( 9, gre );
  analogWrite( 10, blu );
}

void hexify(byte num, char* str)
{
  str[1] = '0' + (num & 0x0F);
  str[0] = '0' + ((num>>4) & 0x0F);
}

I don't have anything currently that works on a Hue/Sat system, the main interface is actually a control signal from another device (DMX-512). The sequences I'm having issues with are standalone programs to run when not connected to a control device.

I've tried breaking each sequence out to its own void

//  X10 = 0
void RainFadeF()
{
  if (X1 == 0)
  {
    DELAY = 10;
  }
  else if (X1 > 0)
  {
    DELAY = X1;
  }
  for (G = 0; G < 255; G++) {      // add green, GREEN (AMBER)
    if (X10 != 0)
    {
      break;
    }
    analogWrite (GRN, G);
    delay ((DELAY * 500) / 26);
  }
  if (R == 255)
  {
    for (R = 255; R > 0; R--) {    // (minus red, GREEN)
      if (X10 != 0)
      {
        break;
      }
      analogWrite (RED, R);
      delay ((DELAY * 500) / 26);
    }
  }
  for (B = 0; B < 255; B++) {      // add blue, BLUE AND GREEN
    if (X10 != 0)
    {
      break;
    }
    analogWrite (BLU, B);
    delay ((DELAY * 500) / 26);
  }
  for (G = 255; G > 0; G--) {      // minus green, BLUE
    if (X10 != 0)
    {
      break;
    }
    analogWrite (GRN, G);
    delay ((DELAY * 500) / 26);
  }
  for (R = 0; R < 255; R++) {      // add red, BLUE AND RED
    if (X10 != 0)
    {
      break;
    }
    analogWrite (RED, R);
    delay ((DELAY * 500) / 26);
  }
  for (B = 255; B > 0; B--) {      // minus blue, RED
    if (X10 != 0)
    {
      break;
    }
    analogWrite (BLU, B);
    delay ((DELAY * 500) / 26);
  }
}

referenced by the main loop

void loop()
{
 //ADDRESS CHECK REMOVED FOR SPACE

  // DMX MODE
  if (X100 <= 5)
  {
    DMX();
  }

  //  600 SERIES - STATIC COLOUR - X10 SELECTS COLOUR - X1 SELECTS INTENSITY
  if (X100 == 6)
  {
    Static();
  }

  // 700 SERIES - EFFECTS - X10 SELECTS SEQUENCE - X1 SELECTS SPEED
  if (X100 == 7)
  {
    // RAINBOW FADE FORWARD
    if (X10 == 0)
    {
      RainFadeF();
    }

    // RAINBOW STEP FORWARD
    if (X10 == 1)
    {
      RainStepF();
    }

    // RAINBOW FADE REVERSE
    if (X10 == 2)
    {
      RainFadeR();
    }

    // RAINBOW STEP REVERSE
    if (X10 == 3)
    {
      RainStepR();
    }

    //  RED/BLUE FADE
    if (X10 == 4)
    {
      RedBlu();
    }

    //  RED/GREEN FADE
    if (X10 == 5)
    {
      RedGrn();
    }

    //  BLUE/GREEN FADE
    if (X10 == 6)
    {
      BluGrn();
    }

    //  BLANK EFFECT
    if (X10 == 7)
    {
      Blank();
    }

    //  BLANK EFFECT
    if (X10 == 8)
    {
      Blank();
    }

    //  BLANK EFFECT
    if (X10 == 9)
    {
      Blank();
    }
  }

  //  BLANK MODE
  if (X100 == 8)
  {
    Blank();
  }

  //  BLANK MODE
  if (X100 == 9)
  {
    Blank();
  }
}

But it still won't kick out mid-sequence with the breaks. Have I placed the break appropriately?

I guess I don't really understand how the arduino runs through its code. I assumed it ran through the code and if it hit a for, did one action on it then moved on until coming back around again and doing the next action. It looks like the arduino hits a for and sits there until the for is complete, is this more correct?

Aristobulous:
It looks like the arduino hits a for and sits there until the for is complete, is this more correct?

Yes, that is the correct behavior of a for loop for all C++ programs.

BTW, that's not how break works either. You need to restructure your code following the Blink Without Delay example.

Post your full sketch, and we can work through it function by function.

If you use the concept in the Blink Without Delay example your fade routines will do a single step of the fade for each iteration of loop() rather than do the whole sequence.

Because the code returns to loop after each small step it is easy to have another function that tests for a change of instructions.

By the way, the correct name for the things you are calling "voids" is "functions". Void just tells the compiler that the function doesn't return a result.

I wrote this example using the Blink Without Delay concept to control a few LEDS at the same time and check a button. It may help to illustrate the concept. Demonstration code for several things at the same time - Project Guidance - Arduino Forum

...R

I'm on my iPad right now and don't have access to my sketch.

I had decided to leave the delays in the for loops as my longest possible delay would be 200ms approx on each step, and deemed that acceptable for waiting for updates, but if the use of delay is getting in the way of interrupting the fors I could switch over to the millis counter method.

I was in the middle of typing this when your reply came through Robin2. So if I switch over to a milli counter if statement, I would have to manually recreate the functioning of a for loop by having it increment by one each time through? Or you're saying it would run a for loop one step at a time as it runs the main loop function?

How is a break; implemented correctly then in a for?

The Arduino reference just gives the following as a guide

for (x = 0; x < 255; x ++)
{
    digitalWrite(PWMpin, x);
    sens = analogRead(sensorPin);  
    if (sens > threshold){      // bail out on sensor detect
       x = 0;
       break;
    }  
    delay(50);
}

How would I properly structure a break in the for loops I have above?

My issue may simply be that because the program is stuck on the for loop, my if function for the break; needs to read the dip pins directly as the program is not going back to the beginning to run my address sequence to reaffirm address until after running the entire set of fors. Again not being at my comp I have not yet confirmed if that fixes things, had that thought after shutting down the comp for the night and the more I think about it, and after being affirmed that the program holds at the for until its complete, the more I believe that may be my issue.

I've tried breaking each sequence out to its own void

I don't understand how anyone can be writing such complicated code and still refer to functions as voids. If you saw this function

int square(int a)
{
    return a * a;
}

would you refer to it as an int ?

Break only gets you out of the block you are currently in, that is defined by braces. In my opinion is is a very poor thing to use and if you write your code correctly you never need to use it.
The point is it can not break out of multiple levels of program structure only the one you are in.
If you are in a function you can break out of that using the return statement.

Aristobulous:
So if I switch over to a milli counter if statement, I would have to manually recreate the functioning of a for loop by having it increment by one each time through? Or you're saying it would run a for loop one step at a time as it runs the main loop function?

I'm not quite sure what you are asking. Let me know if I am not answering the right question. Using millis() to manage the time of things happening means you don't need a for loop. You do things whenever the next time interval elapses (think of it like turning the bacon on your grill every few minutes) and when you get to where you want to be (255, I think in your case) you know that that piece is complete. I hope it is easier to follow in the code that I gave you the link for.

...R

Have a look at this:-
http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html

I have resolved my main issue.

//  X10 = 0
void RainFadeF()
{
  B = 0;  // ENSURE BLUE IS OUT AT BEGINNING
  analogWrite (BLU, B);
  
  for (G = 0; G < 255; G++) {      // add green, GREEN (AMBER)
    ADDRESSUPDATE();
    if (X100 !=7 || X10 != 0)
    {
      return;
    }
    analogWrite (GRN, G);
    if (X1 == 0)
    {
      DELAY = 10;
    }
    else if (X1 > 0)
    {
      DELAY = X1;
    }
    delay ((DELAY * 500) / 26);
  }
  if (R == 255)
  {
    for (R = 255; R > 0; R--) {    // (minus red, GREEN)
      ADDRESSUPDATE();
      if (X100 !=7 || X10 != 0)
      {
        return;
      }
      analogWrite (RED, R);
      if (X1 == 0)
      {
        DELAY = 10;
      }
      else if (X1 > 0)
      {
        DELAY = X1;
      }
      delay ((DELAY * 500) / 26);
    }
  }
  for (B = 0; B < 255; B++) {      // add blue, BLUE AND GREEN
    ADDRESSUPDATE();
    if (X100 !=7 || X10 != 0)
    {
      return;
    }
    analogWrite (BLU, B);
    if (X1 == 0)
    {
      DELAY = 10;
    }
    else if (X1 > 0)
    {
      DELAY = X1;
    }
    delay ((DELAY * 500) / 26);
  }
  for (G = 255; G > 0; G--) {      // minus green, BLUE
    ADDRESSUPDATE();
    if (X100 !=7 || X10 != 0)
    {
      return;
    }
    analogWrite (GRN, G);
    if (X1 == 0)
    {
      DELAY = 10;
    }
    else if (X1 > 0)
    {
      DELAY = X1;
    }
    delay ((DELAY * 500) / 26);
  }
  for (R = 0; R < 255; R++) {      // add red, BLUE AND RED
    ADDRESSUPDATE();
    if (X100 !=7 || X10 != 0)
    {
      return;
    }
    analogWrite (RED, R);
    if (X1 == 0)
    {
      DELAY = 10;
    }
    else if (X1 > 0)
    {
      DELAY = X1;
    }
    delay ((DELAY * 500) / 26);
  }
  for (B = 255; B > 0; B--) {      // minus blue, RED
    ADDRESSUPDATE();
    if (X100 !=7 || X10 != 0)
    {
      return;
    }
    analogWrite (BLU, B);
    if (X1 == 0)
    {
      DELAY = 10;
    }
    else if (X1 > 0)
    {
      DELAY = X1;
    }
    delay ((DELAY * 500) / 26);
  }
}

Each for loop in each of my functions now double checks the dip state status every time it runs through. Because this wasn't happening my X10 value was not changing until the for loop was done, thus the if statement controlling the break (now I'm using return) was never coming true. So my issue is resolved, my sketch is running as intended. I am using milli loop counters elsewhere but have decided to leave the delays in the for loops as the largest delay time does not hinder performance.

Thank you very much for all the replies and help.