RGB Led strip - break and loop flash/fade functions

Hello,
I write a program to control a RGB LED strip using Ir remote. My purpose is to have similar possibilties as original IR controller, because my one is damaged.
Here is my code.

#include <IRremote.h>
#include <IRremoteInt.h>

const unsigned long FadeInterval = 10;

const int RECV_PIN = 7;
const int R_PIN = 5;
const int G_PIN = 9;
const int B_PIN = 3;

#define	BRIGHTNESS_UP   0xF700FF	
#define	BRIGHTNESS_DOWN 0xF7807F  
#define	OFF 	        0xF740BF	 
#define	ON 	        0xF7C03F	 

#define	RED 	  0xF720DF	
#define	GREEN 	  0xF7A05F	
#define	BLUE 	  0xF7609F	
#define	WHITE 	  0xF7E01F	

#define	ORANGE	          0xF710EF	
#define	YELLOW_DARK	  0xF730CF	
#define	YELLOW_MEDIUM	  0xF708F7	
#define	YELLOW_LIGHT      0xF728D7	 

#define	GREEN_LIGHT	  0xF7906F	
#define	GREEN_BLUE1	  0xF7B04F	 
#define	GREEN_BLUE2	  0xF78877	
#define	GREEN_BLUE3	  0xF7A857	

#define	BLUE_RED	  0xF750AF	
#define	PURPLE_DARK	  0xF7708F	
#define	PURPLE_LIGHT	  0xF748B7	
#define	PINK	          0xF76897	

#define FLASH             0xF7D02F
#define STROBE            0xF7F007
#define FADE              0xF7C837
#define SMOOTH            0xF7E817

#define INCREMENTO 10

unsigned long rgb = 0;
byte r,g,b;

byte CurrentR,CurrentG,CurrentB;
byte NextR, NextG, NextB;

IRrecv irrecv(RECV_PIN);
decode_results results;


void setup()
{
  irrecv.enableIRIn(); // Inicializamos el receptor
  Serial.begin(9600);

  // Start wit everything off
  CurrentR = NextR = 0;
  digitalWrite(R_PIN, LOW);
  pinMode(R_PIN, OUTPUT);   
  CurrentG = NextG = 0;
  digitalWrite(G_PIN, LOW);
  pinMode(G_PIN, OUTPUT);   
  CurrentB = NextB = 0;
  digitalWrite(B_PIN, LOW);
  pinMode(B_PIN, OUTPUT);
  
  
}

void variar (byte* color, int valor) {
  if (valor > 0) {
    if ( *color + valor <= 255) {
      *color += valor;
    } 
    else {
      *color = 255;
    }
  } 
  else { 
    if (*color + valor >= 0) {
      *color += valor;
    } 
    else {
      *color = 0;
    }
  }
}

void RGB(unsigned long valor) {
  NextR = valor >> 16; 
  NextG = (valor >> 8) & 0xFF; 
  NextB = valor & 0xFF; 
}

void setColor(int red, int green, int blue)
{
    analogWrite(R_PIN, red);
    analogWrite(G_PIN, green);
    analogWrite(B_PIN, blue);
}

void flash()
{
   
    setColor(250, 105, 0);   // Yellow
    delay(1000);

    setColor(250, 40, 0);    // Orange
    delay(1000);

    setColor(255, 0, 0);     // Red
    delay(1000);

    setColor(10, 10, 255);   // Blue
    delay(1000);

    setColor(255, 0, 100);   // Pink
    delay(1000);

    setColor(200, 0, 255);   // Purple
    delay(1000);

    setColor(0, 255, 0);     // Green
    delay(1000);

    setColor(255, 255, 255); // White
    delay(1000);
  
}


void fade()
{
     unsigned int rgbColour[3];

  // Start off with red.
  rgbColour[0] = 255;
  rgbColour[1] = 0;
  rgbColour[2] = 0;  

  // Choose the colours to increment and decrement.
  for (int decColour = 0; decColour < 3; decColour += 1) {
    int incColour = decColour == 2 ? 0 : decColour + 1;

    // cross-fade the two colours.
    for(int i = 0; i < 255; i += 1) {
      rgbColour[decColour] -= 1;
      rgbColour[incColour] += 1;
      
      setColor(rgbColour[0], rgbColour[1], rgbColour[2]);
      delay(25);
    }
  }
  
}

void loop() {
  static unsigned long lastFadeTime = 0;
  if (millis() - lastFadeTime > FadeInterval)
  {
    lastFadeTime = millis();
    if (NextR > CurrentR)
      CurrentR++;
    if (NextR < CurrentR)
      CurrentR--;
    if (NextG > CurrentG)
      CurrentG++;
    if (NextG < CurrentG)
      CurrentG--;
    if (NextB > CurrentB)
      CurrentB++;
    if (NextB < CurrentB)
      CurrentB--;
    analogWrite(R_PIN,CurrentR);
    analogWrite(G_PIN,CurrentG);
    analogWrite(B_PIN,CurrentB);
  }

  if (irrecv.decode(&results)) {
    if ( results.value != 0xFFFFFFFF) {
      switch (results.value) {
        
      case BRIGHTNESS_UP : 
        variar (&NextR, INCREMENTO);
        variar (&NextG, INCREMENTO);
        variar (&NextB, INCREMENTO);
        break; 
      case BRIGHTNESS_DOWN : 
        variar (&NextR, -INCREMENTO);
        variar (&NextG, -INCREMENTO);
        variar (&NextB, -INCREMENTO);
        break; 
        
      case ON:          digitalWrite(7,HIGH);   break;
      case OFF: RGB(0); digitalWrite(7,LOW);    break; 
      
      case RED           : RGB(0x00FF0000); break;
      case GREEN         : RGB(0x0000FF00); break;
      case BLUE          : RGB(0x000000FF); break;
      case WHITE         : RGB(0x00FFFFFF); break;
      case ORANGE        : RGB(0x00FF7F00); break;
      
      case YELLOW_DARK   : RGB(0x00FFAA00); break;
      case YELLOW_MEDIUM : RGB(0x00FFD400); break;
      case YELLOW_LIGHT  : RGB(0x00FFFF00); break;
      case GREEN_LIGHT   : RGB(0x0000FFAA); break;
      case GREEN_BLUE1   : RGB(0x0000FFFF); break;
      case GREEN_BLUE2   : RGB(0x0000AAFF); break;
      case GREEN_BLUE3   : RGB(0x000055FF); break;
      case BLUE_RED      : RGB(0x00000080); break;
      case PURPLE_DARK   : RGB(0x003F0080); break;
      case PURPLE_LIGHT  : RGB(0x007A00BF); break;
      case PINK          : RGB(0x00FF00FF); break;
      
      default:RGB(0); digitalWrite(7,LOW);    break; 
   
      }
          
      if (results.value==FLASH) flash(); 
      if (results.value==FADE)  fade();
  
  
      
      Serial.println(results.value, HEX);
      Serial.print(" ");
      Serial.print(NextR,DEC);
      Serial.print(" ");
      Serial.print(NextG, DEC);
      Serial.print(" ");
      Serial.println(NextB, DEC);

    }
    irrecv.resume(); // Receive the next value
  }
}

I can change color with fading effect. Moreover I have (thanks forum) functions to fade and flash colors.
But my question is:

1)how to make loop flash/fade functions? (when one circulation will end, back to first color and again through whole palette)

2)how to stop flash/fade effect when I press any button on remote again? I mean: (for example) - leds are flashing, I press red color and change is happen immediately, without waiting until every color in function will display.

Any help will be appriciated.

Does anybody can give me few tips?
Simplyfing → I would like to figure out how to break fade loop (by pressing of the colors). Codes below.

Function body:

void fade()
{
     unsigned int rgbColour[3];

  // Start off with red.
  rgbColour[0] = 255;
  rgbColour[1] = 0;
  rgbColour[2] = 0;  

  // Choose the colours to increment and decrement.
  for (int decColour = 0; decColour < 3; decColour += 1) {
    int incColour = decColour == 2 ? 0 : decColour + 1;

    // cross-fade the two colours.
    for(int i = 0; i < 255; i += 1) {
      rgbColour[decColour] -= 1;
      rgbColour[incColour] += 1;
      
      setColor(rgbColour[0], rgbColour[1], rgbColour[2]);
      delay(25);
    }
  }
  
}

And call this function:

if (irrecv.decode(&results)) {
    if ( results.value != 0xFFFFFFFF) {
      switch (results.value) {
      
      case RED           : RGB(0x00FF0000); break;
      case GREEN         : RGB(0x0000FF00); break;
   
      }
          
      if (results.value==FADE)  fade(); //how to break this function when color become pressed?
 
    }
    irrecv.resume(); // Receive the next value
}

Hi,

You must remove all those delay() functions. The IR receive library cannot work with them. While delay() is happening, whole ir signals will be missed or parts of signals will be missed, which means they cannot be received.

You have two ways to approach this, I think.

  1. Remove all delay() completely. This means you must restructure your code completely, and use millis() function to time periods between changes. You will also need to make the code keep track of where it is in a sequence of changes using a variable for that purpose. This is what people are referring to when they say "Finite State Machine", which is a grandiose title for something that is actually pretty simple.

  2. You may be able to replace each use of delay() with your own function. You could call it myDelay() for example. This function would wait for a given time to pass using millis() but it would also monitor for incoming ir signals. Some other changes would also be needed to your code, so that if an ir command was received, the current flashing/fading function could be ended immediately, so that the ir command could be actioned.

Paul

search or google for: Blink without delay

Hi.
I used things which PaulRB and DiSrUpTeR wrote about. I deleted all delays from code and add milis function. My code now looks that (only flash function):

const int R_PIN = 5;
const int G_PIN = 9;
const int B_PIN = 3;

long previousMillis = 0;      
long interval = 1000;  

void setup() 
{ 
  //
}

void setColor(int red, int green, int blue)
{
    analogWrite(R_PIN, red);
    analogWrite(G_PIN, green);
    analogWrite(B_PIN, blue);
}

void flash()
{
  unsigned long currentMillis = millis();
  unsigned long elapsed = currentMillis - previousMillis;  
  
  switch (elapsed){
    case 0:                                        
    setColor(255, 0, 0);
    break;
    
    case 1000:                                     
    setColor(0, 255, 0);
    break;
    
    case 2000:                                    
    setColor(0, 0, 255);  
    break;
    
    case 3000:                                     
    setColor(255, 127, 0);  
    break;
    
    case 4000:                                    
    previousMillis = currentMillis;
    break;
    
  }
  
}
void loop()
{
  
  flash();
  
}

I read that using switch is not elegant but I don't know how to make this in another way. Can anyone show me how to make this code work using "if" instructions?
Moreover, I still want to be able to stop flash function when something appear - let's say (analogRead(A0)>=1000). How to do that?

That is elegant. However, what happens if elapsed is 1001? 3001? Then you miss it.
Try adding Serial.println (elapsed); and see if the number is always right on the whole thousand mark.

You want to Not call flash() with the analogRead?
if (analogRead(A0) >= 1000){
// do whatever
}
else {
flash();
}

I add Serial.print(elapsed) to observe numbers - and, yes, it is always right on the whole thousand mark. By naming this solution unelegant, I mean that I can’t control what happens when elapsed is 1001, 2001 etc. But it works and I hope it will still :slight_smile:

(analogRead(A0) >= 1000) is only example - let’s disregard and forget it.
My real purpose is to have possibilty to enable flash by pressing button on remote control and to stop sequence before end by pressing another button.

Now, I don’t know why I can’t start flash function and how to stop it and break from loop and display chose color.

#include <IRremote.h>
#include <IRremoteInt.h>

#define FLASH     0xF7D02F
#define	RED 	  0xF720DF
#define	BLUE 	  0xF7609F

const int R_PIN = 5;
const int G_PIN = 9;
const int B_PIN = 3;

const int RECV_PIN = 7;
IRrecv irrecv(RECV_PIN);
decode_results results;

long previousMillis = 0;      
long interval = 1000;  

void setup() 
{ 
  irrecv.enableIRIn();
  Serial.begin(9600);
}

void setColor(int red, int green, int blue)
{
    analogWrite(R_PIN, red);
    analogWrite(G_PIN, green);
    analogWrite(B_PIN, blue);
}

void flash()
{
  unsigned long currentMillis = millis();
  unsigned long elapsed = currentMillis - previousMillis;  
  
  switch (elapsed){
    case 0:                                        
    setColor(255, 0, 0);    //1-RED
    Serial.println(elapsed);
    break;
    
    case 1000:                                     
    setColor(0, 255, 0);    //2-GREEN
    Serial.println(elapsed);
    break;
    
    case 2000:                                    
    setColor(0, 0, 255);    //3-BLUE
    Serial.println(elapsed);
    break;
    
    case 3000:                                     
    setColor(240, 255, 0);   //4-YELLOW  
    Serial.println(elapsed);
    break;
    
    case 4000:                                    
    previousMillis = currentMillis;
    Serial.println(elapsed);
    break; 
  }
}

void loop()
{
  if (irrecv.decode(&results)) 
  {
    if ( results.value != 0xFFFFFFFF) 
    {
      switch (results.value) 
      {
        case RED           : setColor(255, 0, 0); break;
        case BLUE          : setColor(0, 0, 255); break;
        case FLASH         : flash();             break;
      }
    
    }
    irrecv.resume();
  }
}

The flash function only passes through the code once per press from the IR. And the first time it goes through it case 0 will be called. Then the function ends, as the currentmillis and the elapsed variables are defined and initialized each time the function is called it will never do anything else.

Basically you haven't grasped the fundamentals of a state machine.

See my
http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html
Or Robin2's several things at once

To fix up your bodged code then you could try this:-

#include <IRremote.h>
#include <IRremoteInt.h>

#define FLASH     0xF7D02F
#define  RED     0xF720DF
#define BLUE    0xF7609F

const int R_PIN = 5;
const int G_PIN = 9;
const int B_PIN = 3;

const int RECV_PIN = 7;
IRrecv irrecv(RECV_PIN);
decode_results results;

long previousMillis = 0;     
long interval = 1000; 
boolean flashing = false;

void setup()
{
  irrecv.enableIRIn();
  Serial.begin(9600);
}

void setColor(int red, int green, int blue)
{
    analogWrite(R_PIN, red);
    analogWrite(G_PIN, green);
    analogWrite(B_PIN, blue);
}

void flash()
{
  static unsigned long elapsed; 
  elapsed = millis() - previousMillis; 
 
  switch (elapsed){
    case 0:                                       
    setColor(255, 0, 0);    //1-RED
    Serial.println(elapsed);
    break;
   
    case 1000:                                     
    setColor(0, 255, 0);    //2-GREEN
    Serial.println(elapsed);
    break;
   
    case 2000:                                   
    setColor(0, 0, 255);    //3-BLUE
    Serial.println(elapsed);
    break;
   
    case 3000:                                     
    setColor(240, 255, 0);   //4-YELLOW 
    Serial.println(elapsed);
    break;
   
    case 4000:                                   
    previousMillis = currentMillis;
    Serial.println(elapsed);
    break;
  }
}

void loop(){
  if(flashing) flash();
  
  if (irrecv.decode(&results))
  {
    if ( results.value != 0xFFFFFFFF)
    {
      switch (results.value)
      {
        case RED           :  flashing = false; setColor(255, 0, 0); break;
        case BLUE          :  flashing = false; setColor(0, 0, 255); break;
        case FLASH        :  flashing = true;                                break;
      }
   
    }
    irrecv.resume();
  }
}

So I know this thread is super old but since it came up high in my searches (as it probably will for others) and I have just finished the exact same project (for the same reason, with the same remote) and my code is working quite nicely without the delay() function, I’ll just post it here.

LEDRemote.ino (10.6 KB)

PanickedPickle Best written working code i have found yet. Thanks a bundle