How to turn off Loop program with bluetooth

Hi,
I am making program where I want to be able to control the RGB Led with bluetooth. When I press ‘on’ on my phone the Led lights up and keeps changing to random colors. This works fine But I cant make it to stop when I press ‘off’

Instead of exit(0), I tried turning all three digitalpins(9,10,11) to off but also does not work.

Turning on and off without the randomColor() function works, but i want the led to keep working till turned off.
Any ideas please. I am very new to this.

int ledDigitalOne[] = {9, 10, 11};

const boolean ON = LOW;     
const boolean OFF = HIGH;  

//Predefined Colors
const boolean CYAN[] = {ON, OFF, OFF}; 
.
.
.
const boolean RED[] = {OFF, ON, ON};    


char data = 0; 

const boolean* COLORS[] = {CYAN, RED, WHITE, BLUE, YELLOW, GREEN,  MAGENTA};

void setup(){
   Serial.begin(9600); 
   for(int i = 0; i < 3; i++){
   pinMode(ledDigitalOne[i], OUTPUT);   //Set the three LED pins as outputs
  }
}
          
void loop()
{
   if(Serial.available() > 0)      
   {
      data = Serial.read();       
      Serial.print(data);         
      Serial.print("\n");        
      if(data == 'a') {            
            
          randomColor();   
             
      }
     
      else if(data == 'b')  {      
         exit(0);
      }
   }
}



void randomColor(){
 for(int i = 0; i <= 1000; i++){
     int rand = random(0, sizeof(COLORS) / 2);  //without for loop only 1 color comes & i want blinking 
     setColor(ledDigitalOne, COLORS[rand]);  
     delay(500);
   } 
}

void setColor(int* led, boolean* color){
 for(int i = 0; i < 3; i++){
   digitalWrite(led[i], color[i]);
 }
}

You need to hold the received character in a variable when new data is available from the serial port and that is all. Then next in the loop look at that variable and decide what to do depending on that variables value. Do not use exit. Remember the loop function keeps on being repeatedly run.

As you have it at the moment you only ever do stuff when a new serial data value is received.

Thanks Mike for the answer.

I did not understand it all but when you say to hold the received character in a variable, I figured

char data = 0;

was doing that. I a relatively new and much of my code is copied pasted from various sources.

I tried moving out

if(Serial.available() > 0)      
   {
      data = Serial.read();       
      Serial.print(data);         
      Serial.print("\n");

from the void loop() so the loop keeps working on data='a' (for on) but I got error that "expected unqualified-id before 'if' "

I looked it up and it seems that I should not put code outside void loop().

Please can you add a bit more details to where I should make the changes.

Thanks

Another problem that you will have is that you have to wait 50 seconds before an 'off' command will be honoured.

And I don't think exit is useful; it will forever stop your sketch and you will have to reset the board

You put the

char data = 0;

Outside any function as that makes it a global variable. That means it will hold its value when the loop is finished and then starts again.
Otherwise you get the same effect by using

static char data = 0;

Inside the loop.

It is called the loop function NOT the void loop, void is just a word that means the function does not return a variable.

You will need to change randomColor(). As said, it currently causes a long wait.

loop() is called in an endless loop by the 'hidden' main() function. So loop() basically already loops forever. In loop(), you call randomColor(). Each time randomColor() finishes, the code goes back to loop(), loop() goes back to main() and main() calls loop() again which in turn calls randomColor() again.

Because loop() calls randomColor() again, you can use a different principle for randomColor(). Keep a counter that indicates each step; it will replace your 'i' variable.

int counter;
void randomColor()
{
  ...
  ...
}

Now instead of using a for loop, each time that randomColor is called, you do one step and next increment the counter.

int counter;
void randomColor()
{
  int rand = random(0, sizeof(COLORS) / 2);  //without for loop only 1 color comes & i want blinking
  setColor(ledDigitalOne, COLORS[rand]);
  delay(500);

  // increment the counter
  cnt++;

  // if it's 1000, reset to zero
  if (cnt == 1000)
  {
    cnt = 0;
  }
}

Now your waiting is basically over (500ms). You can get rid of those 500ms as well if you use a millis() based approach instead of using delay().

If you simplify loop(), you will see that it works

void loop()
{
  randomColor();
}

Next you can concentrate on loop(). If no serial data is available, you will never call your randomColor(). So the call of randomColor() is in the wrong place.

void loop()
{
  if (Serial.available() > 0)
  {
    data = Serial.read();
  }

  randomColor();

Now if data is received, you can check what it is

void loop()
{
  if (Serial.available() > 0)
  {
    data = Serial.read();
  }

  if(data == 'a')
  {
    randomColor();
  }
  else
  {

  }
}

So now, as long as data is 'a', randomColor() will be called and if it's no longer 'a' (anything else) randomColor() will no longer be called.

If 'b' needs to stop the displaying of a random color, you will need to keep a flag.

bool runRandom = false;
void loop()
{
  if (Serial.available() > 0)
  {
    data = Serial.read();
  }

  if(data == 'a')
  {
    runRandom = true;
  }
  else if (data == 'b')
  {
    runRandon = false;
  }
}

You can now test the runRandom flag in loop() and call randomColor() if it's set

void loop()
{
  if (Serial.available() > 0)
  {
    data = Serial.read();
  }

  if (data == 'a')
  {
    runRandom = true;
  }
  else if (data == 'b')
  {
    runRandon = false;
  }
  else
  {
    // other key, do not change anything
  }

  if (runRandom == true)
  {
    randomColor();
  }
}

That should be it; not compiled (because you did not post complete code) and not tested.

Thank you sterretje, Its working perfectly.

Thanks also for the detailed explanation along with the code. I was using ‘for’ loop only to make the led blink continuously. But with the changes in the code, i didn’t need the ‘for’ loop and could also do away with the counter and still the led blinked continuously with random colors till it was turned off.

With this part

else if (data == 'b')
  {
    runRandom = false;
    
  }

if I turned off the led from bluetooth, the led used to stop blinking but would still stay on with the color that was on it last, so I added

 {
    runRandom = false;
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(11, LOW);
}

to turn it off.

Thanks again

Grumpy_Mike:
As you have it at the moment you only ever do stuff when a new serial data value is received.

It took me some time but I finally got what you meant :slight_smile:

I separated both the if loops here

if(Serial.available() > 0)      
   {
      data = Serial.read();       
          
      if(data == 'a') 
    {    
                        
        randomColor();     
      }
[code]
to 

[code]
if(Serial.available() > 0)      
   {
      data = Serial.read();       
   }//this is the change
    
      if(data == 'a') 
    {    
                        
        randomColor();     
      }
[code]
and it worked with no other changes.(except for removing the exit())

Thanks a lot.