loop within switch case statement while continuing to read input

Hello,

I'm working towards code that reads multiple inputs and then changes the sequence in which 5 LEDs are lit up. Once a light sequence is initiated, I'd like for it to loop while also continuing to monitor for new input. I'm starting from the basics here, but would eventually like to use an IR reader, microphone and switches as the inputs to trigger sequences for around 100 LEDs.

My problem is that I'm not sure how to continue to read the sensor after a case is true. Using goto locks me into a loop but deleting it results in the input being read continuously but only running each case once.

As a noob, I'd also love any input if there is a better statement to use for this project instead of using switchcase.

Thanks in advance!!

int ledPins[] = { 
  5, 6, 9, 10, 11};      // an array of pin numbers to which LEDs are attached
int pinCount = 5;        // the number of pins (i.e. the length of the array)
// LINEAR ARPEGGIO
int timer = 100;         // length that bulb stays on
int incrementArpeggio = 60;      // fade increment / speed
int timerDelay = 2;      // time between bulbs
// RANDOM
int incrementRandom = 100;

void setup() {
  // initialize serial communication:
  Serial.begin(9600); 
  for(int thisPin = 0; thisPin < pinCount; thisPin++){
    pinMode(ledPins[thisPin], OUTPUT);
  }
}

void loop () {
  // SENSOR READINGS
  if (Serial.available() > 0) {
    int trigger = Serial.read();
    
  // TRIGGER SERIAL
    switch (trigger) {
    case 'a':
      linearArpeggio:
      // light array of pins going from 1-5
      { for (int thisPin = 0; thisPin < pinCount; thisPin++){
        // fade in
        for (int brightness = 0; brightness <= 255; brightness += incrementArpeggio){
          analogWrite(ledPins[thisPin], brightness);
          delay(timer);
        }
        // fade out
        for (int brightness = 255; brightness >= 0; brightness -= incrementArpeggio){
          analogWrite(ledPins[thisPin], brightness);
          delay(timerDelay);
        }
        analogWrite(ledPins[thisPin], 0);
      }
      // light array of pins going from highest to lowest pin
      for(int thisPin = pinCount -2; thisPin > 0; thisPin--){
        // fade out
        for (int brightness = 0; brightness <= 255; brightness += incrementArpeggio){
          analogWrite(ledPins[thisPin], brightness);
          delay(timer);
        }
        // fade out
        for (int brightness = 255; brightness >= 0; brightness -= incrementArpeggio){
          analogWrite(ledPins[thisPin], brightness);
          delay(2);
        }
        analogWrite(ledPins[thisPin], 0);
      }
      goto linearArpeggio;
      break;
      }
    
    case 'b':
      randomArray: 
    { int randomPin = random(6);
      // fade in
      for (int brightness = 0; brightness <= 255; brightness += incrementRandom){
        analogWrite(ledPins[randomPin], brightness);
        delay(timer);
      }
      // fade out
      for (int brightness = 255; brightness >= 0; brightness -= incrementRandom){
        analogWrite(ledPins[randomPin], brightness);
        delay(2);
      }
      analogWrite(ledPins[randomPin], 0);
      goto randomArray;
      break;
      }

    case 'c':
      //  OPEN DOOR = LIGHTS GO OFF
      // turn all the LEDs off:
      { digitalWrite(5, LOW);
      digitalWrite(6, LOW);
      digitalWrite(9, LOW);
      digitalWrite(10, LOW);
      digitalWrite(11, LOW);
      break;
      }
      
    default:
      // turn all the LEDs off:
      { digitalWrite(5, LOW);
      digitalWrite(6, LOW);
      digitalWrite(9, LOW);
      digitalWrite(10, LOW);
      digitalWrite(11, LOW);
      }
    }
  }
}

Once a light sequence is initiated, I'd like for it to loop while also continuing to monitor for new input.

Looping one part of the code and doing something else in another part of the code is not possible. The Arduino is fast enough, though, that it can appear to do things simultaneously.

          delay(timer);

This, though, absolutely has to go. Delete all this code. Start with the blink without delay example, and fundamentally rewrite all of your code.

The gotos need to go, too. There are things like while loops that accomplish the same thing in a much more readable fashion.

I'm a fan of switch/case. I find I use it often.

I'm not a fan of goto. I find I use it never. :wink:

Your question/problem is simple but the solution requires a bit of a re-write. You need to take an alternative approach to coding and do two things differently. One, you need to schedule things to happen with millis(). Second, you need to write non-blocking code.

A good starting point for scheduling things with millis() is the Blink Without Delay example PaulS refers to.

Non-blocking code means that you never spend a long time doing one thing. You need to do something small, then check for input, and do the next small thing as appropriate based on that input. If you do this quickly enough, the Arduino can seem to multitask. For your application, rather than step through each brightness in a 'for' loop, you'd have code that increments the brightness variable once, does one analogWrite, goes back to check for more input, then starts over.

instead of
goto randomArray;
to change the case, use
trigger = 'b';

instead of
goto linearArpeggio;
use
trigger = 'a';

I think part of the problem is this:

if (Serial.available() > 0) {
int trigger = Serial.read();
} <<< add a bracket here; trigger then changes when a new character comes in, and if not changed by the stuff in switch case, the same case will keep running.
Without this bracket the switch:case code only runs when serial data comes in.

If it is still a bit confusing...

Here is a pseudo algorithm for what you are trying to do. I also find it easier to break the code up in smaller utility functions instead of writing everything in one single giant loop() function.

So..
You will have to execute the lighting sequence in smaller incremental steps. For this you have to store the "state" details of each lighting sequence in some global variables. This will allow you to execute the next step from current state.

state variables about your lighting sequence 
loop()
{
	check for new input on serial

	if new input has changed your sequence then
		make that as the "current" sequence and initialize its state details

	execute next step of currently running sequence 
}

executeNextStepOfCurrentSequence()
{
	put your switch statement here to call the "current" sequence's next step
}

// You will have to write a utility function like this for each lighting sequence 
executeNextStepOfLinearAppreggio()
{
	// This is the non-blocking execution. Do a small task, if necessary, and return the control.

	Is it time to do the next step? Use millis() for this.
		then do the next step and update"state" details to reflect what you did
	else
		just return
}

Now, the above is all great if you want to write plain old c code. The whole code is way more elegant if you use C++ base class, derived class pattern. You don't need a switch statement at all! Also, you can store state information as members of each class and your code is easily extensible for more lighting sequences in future.
In fact this is one of the classic patterns (polymorphism) why C++ was invented on top of C.

tttt:
I also find it easier to break the code up in smaller utility functions ...
... For this you have to store the "state" details of each lighting sequence in some global variables.

Or make them static inside your utility function:

http://arduino.cc/en/Reference/Static

Thank you all so much for your help. Hopefully I can give your suggestions a shot in the next few days and will let you know how it goes! :fearful: