How to interupt rainbowCycle() and similar LED control functions

Hi,

I've been stuck experimenting with different code regarding time to replace the "delay(wait)" in rainbowCycle. My goal is to have an Arduino (teensy) drive a strip of 2811 LED but is controlled via IR remote. Most, if not all of the native LED controls have a "delay" function in them that I want the input from the IR to override/interrupt/break. I'm not a coder and I don't expect to get the answer from someone but a little direction would be appreciated. Here is the sketch:

#include <IRremote.h>

#include <Adafruit_NeoPixel.h>


int RECV_PIN = 10;

IRrecv irrecv(RECV_PIN);

decode_results results;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(27, 6, NEO_GRB + NEO_KHZ800);


void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  
   strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}

void loop() {
  if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    irrecv.resume(); // Receive the next value
    
    switch(results.value)
    {
      case 0xFF1AE5:
        colorWipe(strip.Color(255, 0, 0), 5); // Red
      break;
      
      case 0xFF9A65:
        colorWipe(strip.Color(0, 255, 0), 5); // Green
      break;
      
      case 0xFFA25D:
        colorWipe(strip.Color(0, 0, 255), 5); // Blue
      break;
      
      case 0xFF22DD:
        colorWipe(strip.Color(255, 255, 255), 5); // White
      break;
      
      case 0xFF827D:
        colorWipe(strip.Color(0, 0, 0), 5); // Off
      break;
      
      case 0xFF609F:
        rainbow(5); // Rainbow
      break;
      
      case 0xFFE01F:
        rainbowCycle(5); // Rainbow Cycle
      break;
      
      case 0xFFE02F:
        rainbowCycle(5); // Rainbow Cycle
      break;
      
       default:
      break; 
      
    }
    
  //  if(results.value  == 0xFF7887)
  //    colorWipe(strip.Color(255, 0, 0), 50); // Red
    
    
  }
}


// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=26; i<strip.numPixels(); i--) {
      strip.setPixelColor(i, c);
      strip.show();
      delay(wait);
  }
}

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

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
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);
  }
}

I tried finding rainbowCycle() in the libraries but couldn't, I tried using millis() instead of delay(), I'm thinking of having a hardware interupt that is triggered by the high/low of the IR, which might be tricky if the IR remote button is held down. Thanks for any help.

There is nothing you can at the top level you need to address what happens in the library calls.

I tried using millis() instead of delay(),

Essentially that is what you have to do. You could replace the delay call in the library with your own function say yourdealy() that uses millis() to delay but at the same time looks for an input and when you see one set a global flag and come out of yourdealy() immediately. Also yourdealy() will check this flag at the start and if set immediately return. That way you should be able to come out of the library when you need to.

I'm thinking of having a hardware interupt that is triggered by the high/low of the IR,

An interrupt only triggers an interrupt service routine, you can not manipulate the return address from this in C so it will simply return to the point in the code before the interruption.

yonespro:

Try:

...
unsigned long startTime;
uint16_t i=26;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  
   strip.begin();
   strip.show(); // Initialize all pixels to 'off'
   startTime = millis();
}

void loop() {
 ...
    }
    
 // Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
        if ((millis()-startTime) >= wait){
             //don't do anything if wait time not reached
           if (i>0){ 
      //?? does your LED strip end at 0 or 1?? If 1, change to (i>1).
              i--;
              strip.setPixelColor(i, c);
              strip.show();
              }
           else{
              i = 26; //begin again
              }
           startTime = millis(); //reset to NOW for next wait period.
           }
     }

This will allow you to receive the IR remote signal at any time during the sequence.

Thanks Grumpy_Mike, is there a sketch that you know of which I can use as reference, the logic eludes me. I attempted a go with the millis() but it effected functionality of rainbowCycle, I will get to my other computer with the code soon and post what I did.

Henry_Best, thanks so much for the code. I implemented it but did not get the normal functionality of colorWipe, it seems to give me per led control, waiting for my input for each led down the strip, one by one, which is really great functionality I could use but not what I was looking for. I'm hoping to have colorWipe, and rainbowCycle, interuptable. Hopefully the code I will post soon with the millis() I implemented on rainbowCycle will be of use.

Thanks again to both of you, never thought I would get a response for something so niche.
YOU GUYS ROCK!

Something like this:-

void myDelay(long duration){
boolean exit = false;
long time = millis();
while (exit == false){
if(millis()-time > duration) exit = true;
if(digitalRead(pin) == LOW) exit = true;  // assuming push button wired to give low on press
}
}

This will exit after the allotted time or whenever the button is pushed.
This needs to be substituted for all the delays INSIDE the library.

Thanks Grumpy_Mike, but I wasn't able to successfully implement this. Here is the code I've been working with:

/*
 * IRremote: IRrecvDemo - demonstrates receiving IR codes with IRrecv
 * An IR detector/demodulator must be connected to the input RECV_PIN.
 * Version 0.1 July, 2009
 * Copyright 2009 Ken Shirriff
 * http://arcfn.com
 */

#include <IRremote.h>

#include <Adafruit_NeoPixel.h>


int RECV_PIN = 10;

IRrecv irrecv(RECV_PIN);

decode_results results;

unsigned long startTime;

uint16_t i=27;

Adafruit_NeoPixel strip = Adafruit_NeoPixel(27, 6, NEO_GRB + NEO_KHZ800);


void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  
   strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}

void loop() {
  if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    irrecv.resume(); // Receive the next value
    
    switch(results.value)
    {
      case 0xFF1AE5:
        //colorWipe(strip.Color(255, 0, 0), 5); // Red
        colorChase(strip.Color(127,   0, 127), 25); // Violet
      break;
      
      case 0xFF9A65:
        //colorWipe(strip.Color(0, 255, 0), 5); // Green
        scanner(127,0,127, 15); // Violet
      break;
      
      case 0xFFA25D:
        //colorWipe(strip.Color(0, 0, 255), 5); // Blue
        //myCrap(strip.Color(127,0,127),10); //Violet
        wave(strip.Color(127,0,127), 2, 40); // Violet
      break;
      
      case 0xFF22DD:
        colorWipe(strip.Color(255, 255, 255), 5); // White
      break;
      
      case 0xFF02FD:
        colorWipe2(strip.Color(0, 0, 0), 5); // Off
      break;
      
      case 0xFF2AD5:
        colorWipe2(strip.Color(255, 0, 0), 5); // Red
      break;
      
      case 0xFFAA55:
        colorWipe2(strip.Color(0, 255, 0), 5); // Green
      break;
      
      case 0xFF926D:
        colorWipe2(strip.Color(0, 0, 255), 5); // Blue
      break;
      
      case 0xFF12ED:
        colorWipe2(strip.Color(255, 255, 255), 5); // White
      break;
      
      case 0xFF0AF5:
        colorWipe(strip.Color(255, 165, 0), 5); // Orange
      break;
      
      case 0xFF8A75:
        colorWipe(strip.Color(0, 255, 255), 5); // Teal
      break;
      
      case 0xFFB24D:
        colorWipe(strip.Color(160, 32, 240), 5); // Purple
      break;
      
      case 0xFF32CD:
        colorWipe(strip.Color(255, 20, 147), 5); // Pink
      break;
      
      
      case 0xFF38C7:
        colorWipe2(strip.Color(255, 165, 0), 5); // Orange
      break;
      
      case 0xFFB847:
        colorWipe2(strip.Color(0, 255, 255), 5); // Teal
      break;
      
      case 0xFF7887:
        colorWipe2(strip.Color(160, 32, 240), 5); // Purple
      break;
      
      case 0xFFF807:
        colorWipe2(strip.Color(255, 20, 147), 5); // Pink
      break;
      
      
      case 0xFF827D:
        colorWipe(strip.Color(0, 0, 0), 5); // Off
      break;
      
      case 0xFF30CF:
        rainbow(5); // Rainbow
      break;
      
      case 0xFF708F:
        rainbowCycle(10); // Rainbow Cycle
      break;
      
      case 0xFF10EF:
        rainbowCycle(0); // Rainbow Cycle
      break;
      
       case 0xFFB04F:
        rainbow2(5); // Rainbow
      break;
      
      case 0xFF906F:
        rainbowCycle2(10); // Rainbow Cycle
      break;
      
      case 0xFF50AF:
        rainbowCycle2(0); // Rainbow Cycle
      break;
      
      case 0xFF20DF:
        rainbowCycle3(10); // Rainbow Cycle
      break;
      
      case 0xFFA05F:
        rainbowCycle3(0); // Rainbow Cycle
      break;
      
       default:
      break; 
      
    }
    
  //  if(results.value  == 0xFF7887)
  //    colorWipe(strip.Color(255, 0, 0), 50); // Red
    
    
  }
}


// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=26; i<strip.numPixels(); i--) {
      strip.setPixelColor(i, c);
      strip.show();
      delay(wait);
  }
}

// Fill the dots one after the other with a color
void colorWipe2(uint32_t c, uint8_t wait) {
// Henry_Best-  for(uint16_t i=26; i<strip.numPixels(); i--) {
if ((millis()-startTime) >= wait) { // Henry_Best:don't do anything if wait time not reached
  if (i>0) { // Henry_Best:??does your LED strip end at 0 or 1?? If 1, change to (i>1).
  i--; // Henry_Best
  strip.setPixelColor(i, c);
      strip.show();
// Henry_Best-      delay(wait);
  }
  else {
    i = 27; // Henry_Best:begin again
  }
  startTime = millis(); // Henry_Best:reset to NOW for the next wait period.
 }
}




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

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}


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

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i*j/2) & 255));
    }
    strip.show();
    delay(wait);
  }
}


// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}



// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle2(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()/2) - j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle3(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel2(((i * 256 / strip.numPixels()/2) - j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
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);
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel2(byte WheelPos) {
  if(WheelPos < 85) {
   return strip.Color(WheelPos * 3, 25 - WheelPos * 3, 0);
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   return strip.Color(25 - WheelPos * 3, 0, 25 - WheelPos * 3);
  } else {
   WheelPos -= 170;
   return strip.Color(0, WheelPos * 3, 25 - WheelPos * 3);
  }
}
// Chase one dot down the full strip.
   void colorChase(uint32_t c, uint8_t wait) {
   int i;

  // Start by turning all pixels off:
    for(i=0; i<strip.numPixels(); i++) strip.setPixelColor(i, 0);

  // Then display one pixel at a time:
    for(i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c); // Set new pixel 'on'
    strip.show();              // Refresh LED states
    strip.setPixelColor(i, 0); // Erase pixel, but don't refresh!
    delay(wait);
  }

  strip.show(); // Refresh to turn off last pixel
}

// "Larson scanner" = Cylon/KITT bouncing light effect
void scanner(uint8_t r, uint8_t g, uint8_t b, uint8_t wait) {
  int i, j, pos, dir;

  pos = 0;
  dir = 1;

  for(i=0; i<((strip.numPixels()-1) * 8); i++) {
    // Draw 5 pixels centered on pos.  setPixelColor() will clip
    // any pixels off the ends of the strip, no worries there.
    // we'll make the colors dimmer at the edges for a nice pulse
    // look
    strip.setPixelColor(pos - 2, strip.Color(r/4, g/4, b/4));
    strip.setPixelColor(pos - 1, strip.Color(r/2, g/2, b/2));
    strip.setPixelColor(pos, strip.Color(r, g, b));
    strip.setPixelColor(pos + 1, strip.Color(r/2, g/2, b/2));
    strip.setPixelColor(pos + 2, strip.Color(r/4, g/4, b/4));

    strip.show();
    delay(wait);
    // If we wanted to be sneaky we could erase just the tail end
    // pixel, but it's much easier just to erase the whole thing
    // and draw a new one next time.
    for(j=-2; j<= 2; j++) 
        strip.setPixelColor(pos+j, strip.Color(0,0,0));
    // Bounce off ends of strip
    pos += dir;
    if(pos < 0) {
      pos = 1;
      dir = -dir;
    } else if(pos >= strip.numPixels()) {
      pos = strip.numPixels() - 2;
      dir = -dir;
    }
  }
}

void myCrap(uint32_t c, uint8_t wait) {
  for(uint16_t k=0; k<strip.numPixels(); k++) {
    
      strip.setPixelColor(2*k, c); 
      strip.show();
      delay(wait);    
    
  }
  
  
}

Any possibility of implementing myDelay here?

Any possibility of implementing myDelay here?

I don't see why not.
Replace all the delays with myDelay, what are you going to have as the trigger to get out of it?

yonespro:
Thanks Grumpy_Mike, but I wasn't able to successfully implement this. Here is the code I've been working with:

You left out a line in setup()
startTime = millis(); and you're still using delay() instead of millis() elsewhere in your code.

Grumpy_Mike,
I'm using IR remote to control the LEDs but not sure how to make IR input make a pin high (or low) and have the arduino see that change and see it as an interrupt, I think it would be cleaner for the interrupt be all in software though but if I can get myDelay to work I'll be happy.

Henry_Best,
I'll try millis() again with the startTime in setup().

I will post my progress. Thanks again

I'm using IR remote to control the LEDs but not sure how to make IR input make a pin high (or low)

What are you using as the IR receiver and how is it wired up.

Generally you have some receiving code that reads the pulse with of the input signal and produces a number for the IR code. You then use that in your code to trigger action using an 'if' statement or a 'switch' structure.

Any luck with interrupts on rainbowcycle? I read somewhere that with the ws28** series that it is not possible because of the timing issues with them specifically.