Stop Sketch before the end of a function.

Hello friends.

I started a few days to study programming and electronics in Arduino, so far I think that has progressed enough. :smiley:
I’m working on a tape addressable digital Led by using the library “Adafruit_NeoPixel” which helps a lot in effect for a digital tape and controlling it with app on mobile via Bluetooth.

However I am having trouble making the switch effect, where only changes after the end total effect running cycle.

Example: I send the command to “effect 1”, then begins execution of “effect 1”, however if I send the command to “effect 2”, it only starts after finishing the cycle “effect 1”.

I wish I could stop the “effect 1”, so I send the request to “effect 2”, and not have to wait the whole cycle over.

I’ve tried to use, while, break, digitalWrite (to turn off the pin 2), millis, attachInterrupt, Blink Without Delay, and I could not, I do not know if I made the wrong way or if these options do not really fit for my needs. :confused:

Someone would have some idea or solution ?

I use Arduino Uno R3
Pin 0 = TX of HC-06 Bluetooth module
Pin 1 = RX of HC-06 Bluetooth module
Pin 2 = Digital Led Strip

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

#define PIN 2


char buf;


// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(30, PIN, NEO_GRB + NEO_KHZ800);

// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel.  Avoid connecting
// on a live circuit...if you must, connect GND first.

void setup() {

  strip.begin();
  strip.show(); // Initialize all pixels to 'off'

  Serial.begin(9600);
  
}

void loop() {

  while(Serial.available() > 0)
  {
    buf = Serial.read();
    if (buf == '1')
    {
      rainbow(50);
      Serial.println("Rainbow !");
    }
    if (buf == '2')
    {
      rainbowCycle(20);
      Serial.println("Rainbow Cycle !");
    }
    if (buf == '3')
    {
      colorWipe(strip.Color(255, 0, 0), 50);
      Serial.println("Full Color Red !");
    }

  }
}



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

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


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

  for(j=0; j<256*2; 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);
  }
}


void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    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) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
delay(wait);

This, combined with the nested for loops is the cause of your problem. Until the 2 loops are complete nothing else can happen. This is exacerbated by the use of the delay() function during which nothing else can happen.

So, what to do ?
One clumsy way would be to read an input inside the 2 for loops and act on it.

Better would be to ditch the for loops and delay() function and use millis() for timing the effects. Save the millis() start time that a LED colour is shown then each time through loop() check whether it is time to change colour and/or LED by comparing the current millis() with the start millis(). If it is time then move to the next colour and/or LED. If not go round again and read inputs each time through loop() to keep the system responsive.

Have a look at Several things at the same time for some ideas.

Read and understand the "blink without delay" demo.

Hi UKHeliBob and PaulMurrayCbr

I changed all the delays the code to use millis, however one of the delays if I shot the effect is very fast not to see the colors passing, is so fast that all LEDs flash instead of the desired effect.
The issue of controlling the mobile app, removed to facilitate the tests (get off the Bluetooth all the time to pass the code is very bad), put for change / transition effects for Button.

   #include <Adafruit_NeoPixel.h>
   #define PIN 2
   Adafruit_NeoPixel strip = Adafruit_NeoPixel(10, PIN, NEO_GRB + NEO_KHZ800);
   const int buttonPin = 7;
       
   // Variables will change:
   int buttonState;
   int lastButtonState = LOW;
   long lastDebounceTime = 0;
   long debounceDelay = 50;
   long previousMillis;
   
   int neoPixel_j = 0;
   
   int nPatterns = 4;
   int lightPattern = 1;
   
//----------------------------------------------------------------------------------------------

   void setup() {
   strip.begin();
   strip.show();                // initialize all pixels to 'off'  
   pinMode(buttonPin, INPUT);
   
}

//=============================================================================================

 void loop() {
 
 int reading = digitalRead(buttonPin);
 if (reading != lastButtonState) {
   lastDebounceTime = millis();
 } 
 
 if ((millis() - lastDebounceTime) > debounceDelay) {
   if (reading != buttonState) {
     buttonState = reading;
     if (buttonState == HIGH) {        
       lightPattern = (lightPattern + 1) % (nPatterns + 1); //include numOfPrograms + 1, since there is an off state
     }
   }
 }

 lastButtonState = reading;
 
//======================================

 switch(lightPattern) {
   case 1:
     softBlink(strip.Color(50,0,0), 1);
     break;
   case 2:
     softBlink(strip.Color(0,50,0), 1);
     break;
   case 3:
     rainbowCycle(10);
     break;
   case 4:
     softBlink(strip.Color(0,0,50), 1);
     break;
 }
}

//======================================
// Fill all the dots with one color
void allColor(uint32_t c) {
 for(uint16_t i=0; i<strip.numPixels(); i++) {
     strip.setPixelColor(i, c);
     strip.show();
 }
}

//======================================
//fades in, then shuts off
void softBlink(uint32_t c, uint8_t wait) {
 
 unsigned long currentMillis = millis();

 if(currentMillis - previousMillis > wait) {
 
   //set the color of all pixels
   allColor(c);
   
   // save the last time you changed a NeoPixel 
   previousMillis = currentMillis; 
   
   uint16_t i;
   int b = neoPixel_j;
   strip.show(); 
   neoPixel_j = (neoPixel_j + 1);
 }
}

//======================================

void rainbowCycle(uint8_t wait) {

  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > wait) {
    previousMillis = currentMillis; 

  uint16_t i, j;
  for(j=0; j<256; j++) {
        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) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

In the code above view that there is only one delay “delay (wait);” if I remove this effect “rainbowCycle” is too fast, which reaches not give to see colors, just flash in white. And I could not in any way use the millis to override this delay. :confused:

I found this video that demonstrates the effect “rainbowCycle” above;

I thank you your attention.