Cycle trough LED effect with a button

Hi, I am working on my first coding project and adapted the code from Adafruit Examples and want to add a new RAINBOW effect. Che code should eliminate all the delays to make the button responsive all the time. But my effect runs way to fast (LEDs are practically just blinking instead of changing colors slowly). Yes, it is responsive on button press as it should. If I add a delay of 500 at the end of "void RainbowUpdate()" if works just fine but I cant move on to another effect with the button anymore until the full cycle is completed.

I added my new rainbow effect in the exact same way as the RAINBOW_CYCLE is done and this effect runs slowly and is responsive to a button press. I don't quite understand why my new effect isn't working.

How do I need to change the code to run the RAINBOW effect in slow speed and be able to move on to the next effect with a press of the button?

#include <Adafruit_NeoPixel.h>
// Pattern types supported:
enum pattern { NONE, RAINBOW_CYCLE, RAINBOW, COLOR_WIPE };
// Patern directions supported:
enum  direction { FORWARD, REVERSE };

class NeoPatterns : public Adafruit_NeoPixel
{
  public:

    //Member variables:
    pattern ActivePattern; // which pattern is running
    direction Direction;     // direction to run the pattern

    unsigned long Interval;  // milliseconds between updates
    unsigned long lastUpdate; // last update of position

    uint32_t Color1, Color2;  // What colors are in use
    uint16_t TotalSteps;  // total number of steps in the pattern
    uint16_t Index;  // current step within the pattern

    void (*OnComplete)();

    // Constructor - calls base-class constructor to initialize strip
    NeoPatterns(uint16_t pixels, uint8_t pin, uint8_t type)
      : Adafruit_NeoPixel(pixels, pin, type)
    {}
    void Update()
    {
      if ((millis() - lastUpdate) > Interval) // time to update
      {
        lastUpdate = millis();
        switch (ActivePattern)
        {
          case COLOR_WIPE:
            ColorWipeUpdate();
            break;
          case RAINBOW_CYCLE:
            RainbowCycleUpdate();
            break;
          case RAINBOW:
            RainbowUpdate();
            break;
          
          default:
            break;
        }
      }
    }
    // Increment the Index and reset at the end
    void Increment()
    {
      if (Direction == FORWARD)
      {
        Index++;
        if (Index >= TotalSteps)
        {
          Index = 0;
          if (OnComplete != NULL)
          {
            OnComplete(); // call the comlpetion callback
          }
        }
      }
      else // Direction == REVERSE
      {
        --Index;
        if (Index <= 0)
        {
          Index = TotalSteps - 1;
          if (OnComplete != NULL)
          {
            OnComplete(); // call the comlpetion callback
          }
        }
      }
    }


    void Rainbow(uint8_t interval, direction dir = FORWARD)
    {
      ActivePattern = RAINBOW;
      Interval = interval;
      TotalSteps = 255;
      Index = 0;
      Direction = dir;
    }

    void RainbowUpdate() {
      
 
            
      uint16_t i, j;

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

      }
    }


    void RainbowCycle(uint8_t interval, direction dir = FORWARD)
    {
      ActivePattern = RAINBOW_CYCLE;
      Interval = interval;
      TotalSteps = 255;
      Index = 0;
      Direction = dir;
    }


    void RainbowCycleUpdate()
    {
      for (int i = 0; i < numPixels(); i++)
      {
        setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index) & 255));
      }
      show();
      Increment();
    }

    void ColorWipe(uint32_t color, uint8_t interval, direction dir = FORWARD)
    {
      ActivePattern = COLOR_WIPE;
      Interval = interval;
      TotalSteps = numPixels();
      Color1 = color;
      Index = 0;
      Direction = dir;
    }
    // Update the Color Wipe Pattern

    void ColorWipeUpdate()
    {
      setPixelColor(Index, Color1);
      show();
      Increment();
    }
    // 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)
    {
      WheelPos = 255 - WheelPos;
      if (WheelPos < 85)
      {
        return Color(255 - WheelPos * 3, 0, WheelPos * 3);
      }
      else if (WheelPos < 170)
      {
        WheelPos -= 85;
        return Color(0, WheelPos * 3, 255 - WheelPos * 3);
      }
      else
      {
        WheelPos -= 170;
        return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
      }
    }
};

#define BUTTON_PIN   2
#define PIXEL_PIN    5
#define PIXEL_COUNT  6

NeoPatterns Strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);

bool oldState = HIGH;
int showType = 0;

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  Strip.begin();
  
  Strip.ActivePattern = RAINBOW_CYCLE; //set start LED mode/color
  Strip.Index = 0;
  Strip.Interval = 100;
  Strip.TotalSteps = 255;
  Strip.setBrightness(50);
  Strip.show();
  Strip.Update();

  Serial.begin(9600);
}

void loop() {

  bool newState = digitalRead(BUTTON_PIN);
  if (newState == LOW && oldState == HIGH) {
    delay(20);
    newState = digitalRead(BUTTON_PIN);
    if (newState == LOW) {
      showType++;
      if (showType > 8)
        showType = 1;
      startShow(showType);
    }
  }
  oldState = newState;
  Strip.Update();
}
void startShow(int i) {
  switch (i) {
    case 0: Strip.ActivePattern = COLOR_WIPE;
      Strip.Index = 0;
      Strip.Color1 = Strip.Color(0, 0, 0); //off
      Strip.Interval = 30;
      Strip.Update();
      Serial.println(showType);
      Serial.println(Strip.ActivePattern);
      break;
    case 1: Strip.ActivePattern = COLOR_WIPE;
      Strip.Index = 0;
      Strip.Color1 = Strip.Color(255, 0, 255); //pink
      Strip.Interval = 30;
      Strip.Update();
      Serial.println(showType);
      break;
    case 2: Strip.ActivePattern = COLOR_WIPE;
      Strip.Index = 0;
      Strip.Color1 = Strip.Color(200, 255, 0); //Green
      Strip.Interval = 30;
      Strip.Update();
      Serial.println(showType);
      break;
    case 3: Strip.ActivePattern = COLOR_WIPE;
      Strip.Index = 0;
      Strip.Color1 = Strip.Color(0, 250, 255); //türkis
      Strip.Interval = 20;
      Strip.Update();
      Serial.println(showType);
      break;
    case 4: Strip.ActivePattern = COLOR_WIPE;
      Strip.Index = 0;
      Strip.Color1 = Strip.Color(255, 150, 0); //orange
      Strip.Interval = 20;
      Strip.Update();
      Serial.println(showType);
      break;
    case 5: Strip.ActivePattern = COLOR_WIPE;
      Strip.Index = 0;
      Strip.Color1 = Strip.Color(125, 0, 255); //lila
      Strip.Interval = 20;
      Strip.Update();
      Serial.println(showType);
      break;
    case 6: Strip.ActivePattern = COLOR_WIPE;
      Strip.Index = 0;
      Strip.Color1 = Strip.Color(255, 255, 255); //weiss
      Strip.Interval = 20;
      Strip.Update();
      Serial.println(showType);
      break;
    case 7: Strip.ActivePattern = RAINBOW_CYCLE;
      Strip.Index = 0;
      Strip.Interval = 100;
      Strip.TotalSteps = 255;
      Strip.Update();
      Serial.println(showType);
      break;
    case 8: Strip.ActivePattern = RAINBOW;
      Strip.Index = 0;
      Strip.Interval = 100;
      Strip.TotalSteps = 255;
      Strip.Update();
      Serial.println(showType);
      break;
  }
}

test_led1.ino (6.45 KB)

Try setting Strip.Interval to a higher value for your pattern to slow it down:

    case 8: Strip.ActivePattern = RAINBOW;
      Strip.Index = 0;
      Strip.Interval = 100;

Thanks pert, that was actually the first place i've looked at. By increasing the interval in that line actually makes the LEDs light red and blink white in with a larger interval. But the colorcycling is not working at all.
It is only working if I add a delay here. But the the button only reacts if the complete cycle is finished.

    void RainbowUpdate() {
      uint16_t i, j;

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

But in theory if the other modes are working without a delay, this one should too, right?

I think the problem is you are staying in a loop for 255 * numPixels() on each update. The outside loop can be eliminated by using the Index property, reducing the time the code spends inside update on each pass. The Interval property ensures the delay time between each update while still being responsive.

void RainbowUpdate() {

      uint16_t i;

      for (i = 0; i < numPixels(); i++)
      {
        setPixelColor(i, Wheel((i + Index) & 255));
      }
      show();

      Increment();
    }

Thanks, that was it. Here ist my final code:

#include <Adafruit_NeoPixel.h>
// Pattern types supported:
enum pattern { 
  NONE, RAINBOW_CYCLE, RAINBOW, COLOR_WIPE };
// Patern directions supported:
enum  direction { 
  FORWARD, REVERSE };

class NeoPatterns : 
public Adafruit_NeoPixel
{
public:

  //Member variables:
  pattern ActivePattern; // which pattern is running
  direction Direction;     // direction to run the pattern

    unsigned long Interval;  // milliseconds between updates
  unsigned long lastUpdate; // last update of position

  uint32_t Color1, Color2;  // What colors are in use
  uint16_t TotalSteps;  // total number of steps in the pattern
  uint16_t Index;  // current step within the pattern

  void (*OnComplete)();

  // Constructor - calls base-class constructor to initialize strip
  NeoPatterns(uint16_t pixels, uint8_t pin, uint8_t type)
: 
    Adafruit_NeoPixel(pixels, pin, type)
    {
    }
  void Update()
  {
    if ((millis() - lastUpdate) > Interval) // time to update
    {
      lastUpdate = millis();
      switch (ActivePattern)
      {
      case COLOR_WIPE:
        ColorWipeUpdate();
        break;
      case RAINBOW_CYCLE:
        RainbowCycleUpdate();
        break;
      case RAINBOW:
        RainbowUpdate();
        break;          
      default:
        break;
      }
    }
  }
  // Increment the Index and reset at the end
  void Increment()
  {
    if (Direction == FORWARD)
    {
      Index++;
      if (Index >= TotalSteps)
      {
        Index = 0;
        if (OnComplete != NULL)
        {
          OnComplete(); // call the comlpetion callback
        }
      }
    }
    else // Direction == REVERSE
    {
      --Index;
      if (Index <= 0)
      {
        Index = TotalSteps - 1;
        if (OnComplete != NULL)
        {
          OnComplete(); // call the comlpetion callback
        }
      }
    }
  }


  void Rainbow(uint8_t interval, direction dir = FORWARD)
  {
    ActivePattern = RAINBOW;
    Interval = interval;
    TotalSteps = 255;
    Index = 0;
    Direction = dir;
  }

  void RainbowUpdate() {
    uint16_t i;

    for (i = 0; i < numPixels(); i++)
    {
      setPixelColor(i, Wheel((i+Index) & 255));
    }
    show(); 
    Increment();  
  }


  void RainbowCycle(uint8_t interval, direction dir = FORWARD)
  {
    ActivePattern = RAINBOW_CYCLE;
    Interval = interval;
    TotalSteps = 255;
    Index = 0;
    Direction = dir;
  }


  void RainbowCycleUpdate()
  {
    for (int i = 0; i < numPixels(); i++)
    {
      setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index) & 255));
    }
    show();
    Increment();
  }

  void ColorWipe(uint32_t color, uint8_t interval, direction dir = FORWARD)
  {
    ActivePattern = COLOR_WIPE;
    Interval = interval;
    TotalSteps = numPixels();
    Color1 = color;
    Index = 0;
    Direction = dir;
  }
  // Update the Color Wipe Pattern

  void ColorWipeUpdate()
  {
    setPixelColor(Index, Color1);
    show();
    Increment();
  }
  // 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)
  {
    WheelPos = 255 - WheelPos;
    if (WheelPos < 85)
    {
      return Color(255 - WheelPos * 3, 0, WheelPos * 3);
    }
    else if (WheelPos < 170)
    {
      WheelPos -= 85;
      return Color(0, WheelPos * 3, 255 - WheelPos * 3);
    }
    else
    {
      WheelPos -= 170;
      return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
    }
  }
};

#define BUTTON_PIN   2
#define PIXEL_PIN    5
#define PIXEL_COUNT  12

NeoPatterns Strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);

bool oldState = HIGH;
int showType = 0;

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  Strip.begin();

  Strip.ActivePattern = RAINBOW_CYCLE; //set start LED mode/color
  Strip.Index = 0;
  Strip.Interval = 100;
  Strip.TotalSteps = 255;
  Strip.setBrightness(100);
  Strip.show();

  Serial.begin(9600);
}

void loop() {

  bool newState = digitalRead(BUTTON_PIN);
  if (newState == LOW && oldState == HIGH) {
    delay(20);
    newState = digitalRead(BUTTON_PIN);
    if (newState == LOW) {
      showType++;
      if (showType > 8)
        showType = 1;
      startShow(showType);
    }
  }
  oldState = newState;
  Strip.Update();
}
void startShow(int i) {
  switch (i) {
  case 0: 
    Strip.ActivePattern = COLOR_WIPE;
    Strip.Index = 0;
    Strip.Color1 = Strip.Color(0, 0, 0); //off
    Strip.Interval = 30;
    Strip.Update();
    Serial.println(showType);
    Serial.println(Strip.ActivePattern);
    break;
  case 1: 
    Strip.ActivePattern = COLOR_WIPE;
    Strip.Index = 0;
    Strip.Color1 = Strip.Color(255, 0, 255); //pink
    Strip.Interval = 30;
    Strip.Update();
    Serial.println(showType);
    break;
  case 2: 
    Strip.ActivePattern = COLOR_WIPE;
    Strip.Index = 0;
    Strip.Color1 = Strip.Color(200, 255, 0); //Green
    Strip.Interval = 30;
    Strip.Update();
    Serial.println(showType);
    break;
  case 3: 
    Strip.ActivePattern = COLOR_WIPE;
    Strip.Index = 0;
    Strip.Color1 = Strip.Color(0, 250, 255); //türkis
    Strip.Interval = 20;
    Strip.Update();
    Serial.println(showType);
    break;
  case 4: 
    Strip.ActivePattern = COLOR_WIPE;
    Strip.Index = 0;
    Strip.Color1 = Strip.Color(255, 150, 0); //orange
    Strip.Interval = 20;
    Strip.Update();
    Serial.println(showType);
    break;
  case 5: 
    Strip.ActivePattern = COLOR_WIPE;
    Strip.Index = 0;
    Strip.Color1 = Strip.Color(125, 0, 255); //lila
    Strip.Interval = 20;
    Strip.Update();
    Serial.println(showType);
    break;
  case 6: 
    Strip.ActivePattern = COLOR_WIPE;
    Strip.Index = 0;
    Strip.Color1 = Strip.Color(255, 255, 255); //weiss
    Strip.Interval = 20;
    Strip.Update();
    Serial.println(showType);
    break;
  case 7: 
    Strip.ActivePattern = RAINBOW_CYCLE;
    Strip.Index = 0;
    Strip.Interval = 100;
    Strip.TotalSteps = 255;
    Strip.Update();
    Serial.println(showType);
    break;
  case 8: 
    Strip.ActivePattern = RAINBOW;
    Strip.Index = 0;
    Strip.Interval = 300;
    Strip.TotalSteps = 255;
    Strip.Update();
    Serial.println(showType);
    break;
  }
}