Neopixel strip not turning off when indicated

Hello, I am working on a project with an Infrared Controller and neopixels on an arduino Uno board. The goal of the project (for now) is to be able to choose between red, blue and green and a rainbow effect. The 3 first colors work well, no problem there. The rainbow effect: it does work normally, but the led strip doesnt turn off when i press on the button. It seems like i need to wait for the rainbow animation to stop ( yeah, i also want to fix that, so that it works till i click on another button) before any of the other buttons have any effect on the arduino. The do get ‘seen’ by the arduino thanks to a led on the arduino that turns on when the it receives a signal, but there isnt any other action. Once the effect is finished, the program works again normally.

For more info, just answer to this post, I will try answering back ASAP.


#include <IRremote.h> //include IR reciever library
#include <Adafruit_NeoPixel.h> // include Neopixel library


const int RECV_PIN = 7; // set the IR receiver to pin 7


IRrecv irrecv(RECV_PIN); // stuff from the IR library
decode_results results;  // stuff from the IR library


#define PIN      8 // set the Neopixel to pin 8
#define N_LEDS 30  // set the Neopixel amount of leds

Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_LEDS, PIN, NEO_GRB + NEO_KHZ800); //call the Neopixel strip

uint32_t red = strip.Color(255, 0, 0); // these are just some colors i want to have for buttons on the controller
uint32_t green = strip.Color(0, 255, 0); // these are just some colors i want to have for buttons on the controller
uint32_t blue = strip.Color(0, 0, 255); // these are just some colors i want to have for buttons on the controller

int rep = 0; // the variable I thought of using to tell the Arduino when to stop the Rainbow effect

void setup(){
  irrecv.enableIRIn(); // some IR stuff again
  irrecv.blink13(true); // some IR stuff again
  strip.begin(); //resetting the Neopixels to off at the beginnig of the program
  strip.show();  // strip.show to update the strip
  
}

/**
 * This rainbow effect wasnt programmed by me because I had been struggling for 2 weeks on making one
 * I did force myself to understand the whole of it  
 * even though it isnt fully clear to me 
 * I hope it will for you guys 
 */


void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) { //this is used to give the 'rolling colors' effect (i think)
      strip.setPixelColor(i, Wheel((i*1+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}



void loop(){
    
    
    /*For the buttons 1, 2, 3 and PWR , 'switch and 'case' are only for the IR receiver
     * 1) strip.clear to make sure ther isnt any color left from before
     * 2) strip.fill(red) to fill the strip in the predefined color
     * 3) rep = 1 to make sure the rainbow effect is off (i put the rainbow in a if statement (if rep = 0 then do rainbow effect)
     * 4) strip.show to update the strip
    */
    
    
    if (irrecv.decode(&results)){

        switch(results.value){
          case 0xFF30CF: //Keypad button "1"
              strip.clear();
              strip.fill(red);
              rep = 1 ;
              strip.show();
          }

        switch(results.value){
          case 0xFF18E7: //Keypad button "2"
            strip.clear();
            strip.fill(green);
            rep = 1;
            strip.show();

          }    

        switch(results.value){
          case 0xFF7A85: //Keypad button "3"
            strip.clear();
            strip.fill(blue);
            rep = 1;
            strip.show();
            
        }
        switch(results.value){
          case 0xFFA25D: //Keypad button "PWR"
          strip.clear();
          rep = 1;
          strip.show();
          
          }
        
        switch(results.value){
          case 0xFF9867: //Keypad button "Random"
          strip.clear(); // clear the strip of any ongoing colors
          rep = 0;
          if(rep == 0) { // if statement to control the rainbow effect (see also the other buttons to know what is the value of rep)
          rainbow(30); // the rainbow effect command line
          strip.show(); // updating the strip
          }
          else {
          strip.clear(); // 'turning' the strip 'off'
          strip.show(); // updating the strip
          }
        }
        
        irrecv.resume(); // more IR reciever code
      }
}

// this last part is only programm to choose a color.
// I dont think it has to do anyting with my problem. I someone could give a short explanation in the comments, 
// i woulndt mind it though

uint32_t Wheel(byte WheelPos) {
  if(WheelPos < 85) {
    return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } 
  else if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } 
  else {
    WheelPos -= 170;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

It seems like i need to wait for the rainbow animation to stop

We get this problem every week.
You have written blocking code, so yes you have to wait until the animation to finish before you can look at any control.

The normal solution is to write none blocks code like the blink without delay example in the IDE, but this is not beginners stuff, but intermediate level stuff.

However you want to use IR remote so when you finally write none blocking code then because the neopixels driver turn off the interrupts when sending data you have problems detecting the IR pulses.

this is your problem

delay(wait);

instead of freezing your program you need the program to run as fast as possible and go through the loop as many times as possible per second.

So instead of waiting, you should write the program so that IF it is time to change the led colors in the rainbow, the rainbow program runs, ELSE, you want to skip that part of the program.

const int ledPin =  13;
int ledState = LOW;
unsigned long previousMillis = 0;
unsigned long interval = 1000;
 
void setup() {
  pinMode(ledPin, OUTPUT);
} 
 
void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
    digitalWrite(ledPin, ledState);
  }
}

and

const int ledPin =  13;
int ledState = LOW;
int wait = 1000;
 
void setup() {
  pinMode(ledPin, OUTPUT);
} 
 
void loop() {
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
    digitalWrite(ledPin, ledState);
    delay(wait);
}

Blink the led just as often, but the difference in code is running many times per second in the first example, but only once per second in the second example. Which is why you have to wait for the animation to end in your program.

Thanks alot for both the answers, I will try each one of them in the code.

I will post if it works.