Switching Arduino Loops on input

Hi there, I need a bit of help with breaking mid-loop in my code.
I’m trying to write a program that has an RGB strip just gently scan through the colours when there is no input, and when there is an input (from A0 pin) it flashes with the level of the music. I have the script for both aspects, and this is what I currently have to select the colour scan loop;

// rest of void loop with script for audio flash
if (soundLevel < 50 ) {
// colour scan loop script
}

It does a complete loop through the colour scan (which is about 20 seconds) before testing to see if the variable is true, but I need it to break the loop instantly if there is any input (when soundLevel > 50) rather than just testing at the start of every loop.

Any help would be much appreciated, as I’m an amateur at this!
Thanks,
Simon

Four lines of code, huh? (two of them comments)

http://snippets-r-us.com/

I'm going to guess that

// colour scan loop script

is blocking code, returning only when it is done.

You'll need to COMPLETELY rewrite your code, using the blink without delay philosophy (to determine when a change is needed) and a state machine methodology (to keep track of what the next change should be and when it should happen).

Then, when an external event (input happens) occurs, you can instantly change the state.

Hi again,

I’m gonna firstly point out that this obviously isn’t all of my code, I just decided to show the bits that I thought mattered, but if you want to see the lot it’s posted below. Sorry if it was a bit confusing, I just thought it was easier to show just the bit that was causing me problems! Thanks PaulS- do you think you could show me a simple example please? (sorry again I’m a newbie I’m not 100% sure what you mean thoughout that!) Basically what I’m after is a sound meter, low is green mid is blue and high is red, and colour scanning when theres no input.

Thanks,
Simon

int ledR = 9;
int ledG = 10;
int ledB = 11;
int soundLevel;
int ledDelay = 48;

void setColourRgb(unsigned int red, unsigned int green, unsigned int blue) {
  analogWrite(ledR, red);
  analogWrite(ledG, green);
  analogWrite(ledB, blue);
 }

void setup()
{
  Serial.begin(9600);
  pinMode(ledR, OUTPUT);
  pinMode(ledG, OUTPUT);
  pinMode(ledB, OUTPUT);
}

void loop() 
{
  soundLevel = analogRead(A0);

  Serial.print("Sound level: ");
  Serial.println(soundLevel, DEC);
  
  if ( soundLevel > 50 ) {
    digitalWrite(ledG, HIGH);   
    delay(ledDelay);
  }
  if ( soundLevel > 75 ) {
    digitalWrite(ledB, HIGH);
    digitalWrite(ledG, LOW);
    delay(ledDelay);
  }
  if ( soundLevel > 125 ) {
    digitalWrite(ledR, HIGH);
    digitalWrite(ledG, LOW);
    digitalWrite(ledB, LOW);
    delay(ledDelay);
  }
  if (soundLevel < 50 ) { 
    unsigned int rgbColour[3];

  rgbColour[0] = 255;
  rgbColour[1] = 0;
  rgbColour[2] = 0;  

  for (int decColour = 0; decColour < 3; decColour += 1) {
    int incColour = decColour == 2 ? 0 : decColour + 1;

    for(int i = 0; i < 255; i += 1) {
      rgbColour[decColour] -= 1;
      rgbColour[incColour] += 1;
      
      setColourRgb(rgbColour[0], rgbColour[1], rgbColour[2]);
      delay(5);
    }
  }
}
  if ( soundLevel < 75 ) {
    digitalWrite(ledB, LOW);
  }
  
  
  if ( soundLevel < 125 ) {
    digitalWrite(ledR, LOW);
  }
}

like paul said you have written blocking code with no way out. Try to avoid using "for" and "delay" in your code if you want it to be react when something changes. during the 20 seconds the "for" loops are running the arduino is not looking at the analog input pin.

Okay sweet as, thank you! How would you suggest I write it without the for expressions? (I'm not 100% sure how the scan bit of code works, it wasn't written by me!)

The simple thing in your case seems to me to be to test more frequently. In particular, here:

    for (int decColour = 0; decColour < 3; decColour += 1) {
      int incColour = decColour == 2 ? 0 : decColour + 1;
      for (int i = 0; i < 255; i += 1) {
        rgbColour[decColour] -= 1;
        rgbColour[incColour] += 1;
        setColourRgb(rgbColour[0], rgbColour[1], rgbColour[2]);
        delay(5);
        if (analogRead(A0) >= 50)   // <---------- add this
          return;    // <--------- and this
      }
    }

Now this tests inside your rather lengthy nested loops. If it detects a high sound level, it immediately returns from the loop function, which is re-called again, and then does its new bidding.

The demo several things at a time illustrates the use of millis() for timing and non-blocking functions. Also planning and implementing a program.

...R

Brilliant Thank you!! I've tested it out with your added testing, Nick, and that works well!