Help exiting loop upon serial input, return to main loop

Hi all,
Need a bit of help. I have an infinite loop (rainbowCycle) that’s called upon when my main loop receives a certain serial command defined in the main loop. The rainbowCycle loop works as expected, but it’s then unable to process subsequent serial inputs, it just loops forever. I’ve tired adding line in the loop to break if Serial.available() > 0 , but it doesn’t take action on the serial inputs. I’m thinking it needs to exit to the main loop with the serial data in tow , but I can’t figure out how.

Thanks in advance :slight_smile:

// EEPROM - Version: Latest 
#include <EEPROM.h>
#include "Adafruit_TLC5947.h"

#define NUM_TLC5974 1

#define data   4
#define clock   5
#define latch   6
#define oe  -1  // set to -1 to not use the enable pin (its optional)
Adafruit_TLC5947 tlc = Adafruit_TLC5947(NUM_TLC5974, clock, data, latch);

void setup() {  
  Serial.begin(9600);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  tlc.begin(); 
  int r;
  int g;
  int b;
  EEPROM.get(0, r);
  EEPROM.get(2, g);
  EEPROM.get(4, b);

    for(int i=0; i<8*NUM_TLC5974; i++)
    tlc.setLED(i, r, g, b);   //sets all 24 outputs.
    tlc.write(); 
  
}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint32_t i, j;
while(1){
  for(j=0; j<4096; j++) { // 1 cycle of all colors on wheel
    for(i=0; i< 8*NUM_TLC5974; i++) {
      //Wheel(i, ((i * 4096 / (8*NUM_TLC5974)) + j) & 4095); //multicolor
       Wheel(i, j);  // all the same color
    }
    tlc.write();
    delay(wait);
    
  }
}
}

// Input a value 0 to 4095 to get a color value.
// The colours are a transition r - g - b - back to r.
void Wheel(uint8_t ledn, uint16_t WheelPos) {
  if(WheelPos < 1365) {
    tlc.setLED(ledn, 3*WheelPos, 4095 - 3*WheelPos, 0);
  } else if(WheelPos < 2731) {
    WheelPos -= 1365;
    tlc.setLED(ledn, 4095 - 3*WheelPos, 0, 3*WheelPos);
  } else {
    WheelPos -= 2731;
    tlc.setLED(ledn, 0, 3*WheelPos, 4095 - 3*WheelPos);
  }
}

void loop() {
 
  // If information is available in the serial port we will use it:
  while (Serial.available() > 0) {
    
    //int red = 0, green = 0, blue = 0;
    int red, green, blue, effect;
    int r;
    int g;
    int b;
    // search for the next valid chain of whole numbers and 
    // assign the value converted to a whole number to the corresponding variable
    red = Serial.parseInt();
    // search again.
    green = Serial.parseInt();
    // search again:
    blue = Serial.parseInt();
    // search again:
    effect = Serial.parseInt();
 
    // search for the end of line character. Tell the program that the entering of data has been finished.
    // If you use the Arduino IDE or another IDE that allows the format to be included
    // of the new line on sending data via the serial monitor, delete the comment
    // from line 33 and comment on line 34.
    
   // if (Serial.read() == '\n'){
    if (Serial.read() == '*'){
 
      // Using constrain, we make sure that the value is within the PWM range
      // For common anode LEDS use, for example, for red: red = 255 - constrain(red, 0, 255);
      red = constrain(red, 0, 4095);
      green = constrain(green, 0, 4095);
      blue = constrain(blue, 0, 4095);
      effect = constrain(effect, 0, 9);
 
      // print the three numbers in one string as hexadecimal:
      //Serial.print(red, HEX);
      //Serial.print(green, HEX);
      //Serial.println(blue, HEX);
 
     r = red;
     g = green;
     b = blue;
    for(int i=0; i<8*NUM_TLC5974; i++)
    tlc.setLED(i, r, g, b);   //sets all 24 outputs.
    tlc.write(); 
    
    EEPROM.put(0, r);
    EEPROM.put(2, g);
    EEPROM.put(4, b);
    
    if (effect > 0) 
      rainbowCycle(1);
    else 
      //something
      break;
    
        
    }
  }
}

1 - please format your code. ctrl-T in the IDE
2 - when would you expect that while(1){} loop to complete?

Hi,

  1. I'm using the web based IDE, it's not pasting in as nicely as it's actually formatted. sorry.

  2. I used while(1) as a generic way to get the loop to loop continuously. maybe there's a better way to do this. what I actually intend is Loop continuously , until serial data is received. Upon receiving serial data, read the data and take actions as defined in the main loop for the serial data.

The loop() function loops continuously. Use that.

The serial input basics tutorial has robust and non-blocking methods for receiving serial data.

Your code is missing a setup() function.

Solved by having the main loop check a value saved in EEPROM.

Rather than forcing rainbowcycle() to loop itself and attempt breaking upon serial events, I went back to using rainbowcycle as a onetime function and instead:

  1. I took the serial input that queues the function and saved it to EEPROM as “fx”
  2. when the main loop starts, I check the “fx” value to either re-queue the desired function or proceed with the rest of the loop.
// EEPROM - Version: Latest 
#include <EEPROM.h>
#include "Adafruit_TLC5947.h"

#define NUM_TLC5974 1

#define data   4
#define clock   5
#define latch   6
#define oe  -1  // set to -1 to not use the enable pin (its optional)
Adafruit_TLC5947 tlc = Adafruit_TLC5947(NUM_TLC5974, clock, data, latch);

void setup() {  

  Serial.begin(9600);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  tlc.begin(); 
  int r;
  int g;
  int b;
  int fx;
  EEPROM.get(0, r);
  EEPROM.get(2, g);
  EEPROM.get(4, b);
  EEPROM.get(6, fx);
    for(int i=0; i<8*NUM_TLC5974; i++)
    tlc.setLED(i, r, g, b);   //sets all 24 outputs.
    tlc.write(); 

}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  //Serial.print("starting rainbowcycle");
  uint32_t i, j;
  for(j=0; j<4096; j++) { // 1 cycle of all colors on wheel
    for(i=0; i< 8*NUM_TLC5974; i++) {
      //Wheel(i, ((i * 4096 / (8*NUM_TLC5974)) + j) & 4095); //multicolor
       Wheel(i, j);  // all the same color
    }
    tlc.write();
    delay(wait);

}
//Serial.print("ending rainbowcycle");
}

// Input a value 0 to 4095 to get a color value.
// The colours are a transition r - g - b - back to r.
void Wheel(uint8_t ledn, uint16_t WheelPos) {
  if(WheelPos < 1365) {
    tlc.setLED(ledn, 3*WheelPos, 4095 - 3*WheelPos, 0);
  } else if(WheelPos < 2731) {
    WheelPos -= 1365;
    tlc.setLED(ledn, 4095 - 3*WheelPos, 0, 3*WheelPos);
  } else {
    WheelPos -= 2731;
    tlc.setLED(ledn, 0, 3*WheelPos, 4095 - 3*WheelPos);
  }
}

void loop() {
    int fx;
    EEPROM.get(6, fx);
    if (fx > 0)
      rainbowCycle(1);
    else 
  //Serial.print("starting loop");
  // If information is available in the serial port we will use it:
  while (Serial.available() > 0) {
    
    //int red = 0, green = 0, blue = 0;
    int red, green, blue, effect;
    int r, g, b, fx;
    // search for the next valid chain of whole numbers and 
    // assign the value converted to a whole number to the corresponding variable
    red = Serial.parseInt();
    // search again.
    green = Serial.parseInt();
    // search again:
    blue = Serial.parseInt();
    // search again:
    effect = Serial.parseInt();
 
    // search for the end of line character. Tell the program that the entering of data has been finished.
    // If you use the Arduino IDE or another IDE that allows the format to be included
    // of the new line on sending data via the serial monitor, delete the comment
    // from line 33 and comment on line 34.
    
   // if (Serial.read() == '\n'){
    if (Serial.read() == '*'){
 
      // Using constrain, we make sure that the value is within the PWM range
      // For common anode LEDS use, for example, for red: red = 255 - constrain(red, 0, 255);
      red = constrain(red, 0, 4095);
      green = constrain(green, 0, 4095);
      blue = constrain(blue, 0, 4095);
      effect = constrain(effect, 0, 9);
 
      // print the three numbers in one string as hexadecimal:
      //Serial.print(red, HEX);
      //Serial.print(green, HEX);
      //Serial.println(blue, HEX);
 
     r = red;
     g = green;
     b = blue;
     fx = effect;
    for(int i=0; i<8*NUM_TLC5974; i++)
    tlc.setLED(i, r, g, b);   //sets all 24 outputs.
    tlc.write(); 
    
    EEPROM.put(0, r);
    EEPROM.put(2, g);
    EEPROM.put(4, b);
    EEPROM.put(6, fx);
    
    
    
        
    }
  }
}

Actually , I found that the more appropriate way to handle this is to not place the serial actions in the main loop, but instead use serialEvent(). https://www.arduino.cc/en/Tutorial/SerialEvent

Using serialEvent() will allow your loop to do whatever your loop does, while a serial entry will then be executed by whatever is in your serialEvent(). After the actions taken in the serialEvent, your loop will continue on.

craig24x: Actually , I found that the more appropriate way to handle this is to not place the serial actions in the main loop, but instead use serialEvent().

This is a misunderstanding. The function serialEvent() is called immediately after every iteration of loop(). The code in my Serial Input Basics Tutorial calls an equivalent function directly from within loop(). The overall effect is the same except that writing your own function puts you in control - for example you may not need to check for serial input on every iteration of loop()

...R