RGBW Not cycling properly

Hello! I am somewhat new to Arduino so please excuse how messy this may appear but I am trying to get a button when pressed once to make the RGBW strip white then once pressed again it will cycle through a nice RGBW rainbow cycle - if the button is pressed again then it will return to the white then pressed again rainbow cycle again etc... However the cycle does not loop until I press the button to go to white and stops at a certain point.

I've tried putting rainbowCycle() with and without fullWhite() in the void loop section but that breaks the button function - is there a way to keep the rainbow cycle going forever until I press the button to go to white?

Thank you for reading, here's the code:

#include <Adafruit_NeoPixel.h>

#ifdef __AVR__
#include <avr/power.h>
#endif

#define BUTTON_PIN   2

#define PIN 6

#define NUM_LEDS 25

#define BRIGHTNESS 200

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRBW + NEO_KHZ800);

bool oldState = HIGH;
int showType = 0;
void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  strip.setBrightness(BRIGHTNESS);
  strip.begin();
  strip.show();
}

void loop() {
  // Get current button state
  bool newState = digitalRead(BUTTON_PIN);


  // Check if state changed from high to low (button press)
  if (newState == LOW && oldState == HIGH) {
    // Short delay to debounce button.
    delay(20);
    // Check if button is still low after debounce
    newState = digitalRead(BUTTON_PIN);
    if (newState == LOW) {
      showType++;
      if (showType > 1)
        showType = 0;
      startShow(showType);


    }
  }



  // Set the last button state to the old state.
  oldState = newState;
}

void startShow(int i) {
  switch (i) {
    case 0: rainbowCycle();
      break;
    case 1: fullWhite();
      break;
    case 2: rainbowCycle();
      loop;
    case 3: fullWhite();
      break;
  }
}

void fullWhite() {                      //WHITE
  int fadeVal = 25, fadeMax = 100;

  for (uint16_t i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, strip.Color(0, 0, 0, 255 ) );
  }
  strip.show();
  if (digitalRead(BUTTON_PIN) == LOW && oldState == HIGH)return;

}


void rainbowCycle() {                   //RGBW CYCLE
  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();
    
  }
}

// Values 0 to 255 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);
  }
}

Also, here's what is visually happening (it may explain this better):

OK, now note that rainbowCycle(), once initiated, will run to completion and only after that will it be able to do anything else, including reading the button.

That is just how it is written. If you want faster response from the button, you have to deconstruct the rainbowCycle() code into smaller pieces so that you can check the button more regularly.

In case you are distracted by the thought, interrupts cannot be used to abort the code - but could be used to "remember" that you had actually pressed the button so that you could switch cycles once rainbowCycle() completes. (Someone will probably offer that an interrupt could be used to execute a reset of the whole program FWIW. :roll_eyes: )

Hello literallyHYDRA,
Welcome to the forum.

It drives people nuts on here when newbies don't post code properly. For posting your code correctly on your first post ++Karma.