Go Down

Topic: Trouble getting rid of the delay [SOLVED] (Read 319 times) previous topic - next topic

surveyranger

Sep 23, 2019, 04:52 am Last Edit: Sep 24, 2019, 12:07 am by surveyranger
Trying to get a lightning type effect on a single WS2812b on its own breakout board (SMD resistor & capacitor) using an Uno clone.  I found an effect I liked, and it works...albeit using delays.  

I tried to adjust the code to get rid of the delays, but it turned it into a rapidly firing pixel rather than having brief "off" moments between flashes.  Read the pinned posts on getting rid of delays, but fell short in the execution.

Any ideas on where I went wrong ditching the delays?

Code with delay():
Code: [Select]

// source:  http://projects.mytestbox.org/?p=49

//Load NeoPixel library
#include <Adafruit_NeoPixel.h>

//Digital output pin and number of LEDs on string
#define PIN 6
#define NUMPIXELS 1    // default = 12
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_RGB + NEO_KHZ800);

// Initialize values used.
//  int brightVal;  // brightVal is how long LEDs are on.
//  int darkVal;    // darkVal is how long before next lightning effect
//  int delayVal;   // delayVal is the delay between lightning effect blinks
//  byte lightVal;  // lightVal is how bright each of the flashes are
//  int flashVal;   // flashVal is how many time the lightning effect flashes
//  int blinkTimes; // blinkTimes is how many times the lightning effect flashes
//  byte r = 0;          // r, g, b are used to set the RGB value of the LED
//  byte g = 0;
//  byte b = 0;
// r, g, b is assigned the value generated from the lightVal variable.
// If you want different RGB values, assign different values to r, g, b.

void setup() {
  pinMode(PIN, OUTPUT);       // set data pin as output
  pixels.begin();             // initialize pixels
  pixels.setBrightness(127);  // set pixels to 50% brightness to conserve battery
  pixels.show();              // set pixels to off
}

void loop() {
  // array to store number of pixels (max 255) used for brightVal and to turn pixels off
  byte pixelNum[NUMPIXELS];  
  
  // LEDs remain dark between 1000ms and 10000ms
  int darkVal = random(300, 500);  // changed to 300-500ms for shorter off times
  
  // LEDs will flash between 2 and 21 times
  int flashVal = random(2, 21);

  // LEDs will be a RGB value of 0 to 255 to vary brightness
  for (int blinkTimes = 0; blinkTimes <= flashVal; blinkTimes++)
  {
    byte lightVal = random(0, 255); // lightVal set to r, g, b. Can be changed to individual values for other colors
    byte r = lightVal;
    byte g = lightVal;
    byte b = lightVal;
    
    // LEDs will remain on between 20ms and 200ms
    int brightVal = random(20, 200);
    
    // Flashes will be delayed between 20ms and 500ms
    int delayVal = random(20, 500);      
    
    // turn pixels on
    for (int i = 0; i < NUMPIXELS; i++)
    {
      pixels.setPixelColor(pixelNum[i], pixels.Color(r, g, b));
      pixels.show();
    }
    
    delay(brightVal);  // may have to put delay inside FOR loop
    
    // turn pixels off
    for (int i = 0; i < NUMPIXELS; i++)
    {
      pixels.setPixelColor(pixelNum[i], pixels.Color(0, 0, 0));
      pixels.show();
    }
    
    delay(delayVal);  // may have to put delay inside FOR loop
  }
  delay(darkVal);
}


Code without delay():
Code: [Select]

#include <Adafruit_NeoPixel.h>
#define PIN 6
#define NUMPIXELS 1    // default = 12
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_RGB + NEO_KHZ800);

void setup() {
  pinMode(PIN, OUTPUT);       // set data pin as output
  pixels.begin();             // initialize pixels
  pixels.setBrightness(127);  // set pixels to 50% brightness to conserve battery
  pixels.show();              // set pixels to off
}

void loop() {
  unsigned long currentMillis = millis();
  unsigned long darkValMillis, brightValMillis, delayValMillis;
  
  // array to store number of pixels (max 255) used for brightVal and to turn pixels off
  byte pixelNum[NUMPIXELS];  
  
  // LEDs remain dark between 1000ms and 10000ms
  int darkVal = random(300, 500);  // changed to 300-500ms for shorter off times
  
  // LEDs will flash between 2 and 21 times
  int flashVal = random(2, 21);

  if(currentMillis - darkValMillis >= darkVal)
  {
    darkValMillis = currentMillis;
    
    // LEDs will be a RGB value of 0 to 255 to vary brightness
    for (int blinkTimes = 0; blinkTimes <= flashVal; blinkTimes++)
    {
      byte lightVal = random(0, 255); // lightVal set to r, g, b. Can be changed to individual values for other colors
      byte r = lightVal;
      byte g = lightVal;
      byte b = lightVal;
      
      // LEDs will remain on between 20ms and 200ms
      int brightVal = random(20, 200);
      
      // Flashes will be delayed between 20ms and 500ms
      int delayVal = random(20, 500);      

      if (currentMillis - brightValMillis >= brightVal)
      {
        brightValMillis = currentMillis;  // reset brightValMillis
        
        // turn pixels on
        for (int i = 0; i < NUMPIXELS; i++)
        {
          pixels.setPixelColor(pixelNum[i], pixels.Color(r, g, b));
          pixels.show();
        }
      }

      if (currentMillis - delayValMillis >= delayVal)
      {
        delayValMillis = currentMillis; // reset delayValMillis
        // turn pixels off
        for (int i = 0; i < NUMPIXELS; i++)
        {
          pixels.setPixelColor(pixelNum[i], pixels.Color(0, 0, 0));
          pixels.show();
        }
      }
    }
  }
}

marco_c

#1
Sep 23, 2019, 06:01 am Last Edit: Sep 23, 2019, 09:14 pm by marco_c
You basically need to turn the original code into a Finite State Machine style of program. I expect that you will need states for initialise, led_on and led_off.

Read this and see if it helps you get the concepts https://arduinoplusplus.wordpress.com/2019/07/06/finite-state-machine-programming-basics-part-1/
Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com

noiasca

not bad at all.

three things:

a) you also have to remember if you are in "on" state or in "off" state and react in your if (currentMillis ... accordingly ... a first step of a state machine.
b) don't call pixels.show(); after each pixels.setPixelColor, just call it once after you have set all pixels.
c) add Serial.println in each "if" so that you can see, what your code is doing.

DE: Wie man Fragen postet:
1. was hat man (Sketch und Hardware)
2. was SOLL es machen
3. was macht es: IST (Fehlverhalten, Fehlermeldungen, Serial.Output ...)
4. Eine Frage stellen bzw. erklären was man erwartet

surveyranger

#3
Sep 23, 2019, 09:57 pm Last Edit: Sep 23, 2019, 11:13 pm by surveyranger
You basically need to turn the original code into a Finite State Machine style of program. I expect that you will need states for initialise, led_on and led_off.
Thanks for the link.  Tweaked the code to incorporate the Finite State Machine (FSM) as I understood the concept.  I also added Serial.print as suggested by noiasca for debugging.  It appears that the switch/case does not advance to case 1 after case 0 even though I added the "state = 1;" line in case 0.  The serial monitor shows that it generates the random values, moves through the if/for/switch statements to case 0, and then back to the beginning.

The WS2812b blinked as desired after I created the "flashLightning" function and changed the "delay(darkVal)" to an IF statement.  It doesn't blink at all after adding the switch/case because it doesn't advance to case 1.

Adjusted code using FSM:
Code: [Select]

#include <Adafruit_NeoPixel.h>
#define PIN 6
#define NUMPIXELS 1    // default = 12
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_RGB + NEO_KHZ800);

void setup() {
  Serial.begin(9600);         // Initialize serial monitor for debugging
  pinMode(PIN, OUTPUT);       // set data pin as output
  pixels.begin();             // initialize pixels
  pixels.setBrightness(127);  // set pixels to 50% brightness to conserve battery
  pixels.show();              // set pixels to off
}

void loop() {
  flashLightning();
}

void flashLightning() {
  unsigned long darkValMillis = 0;
  byte state = 0;
 
  // array to store number of pixels (max 255) used for brightVal and to turn pixels off
  byte pixelNum[NUMPIXELS]; 
 
  // LEDs remain dark between 1000ms and 10000ms
  int darkVal = random(300, 500);  // changed to 300-500ms for shorter off times
  Serial.print("darkVal = ");
  Serial.println(darkVal);
 
  // LEDs will flash between 2 and 21 times
  int flashVal = random(2, 21);
  Serial.print("flashVal = ");
  Serial.println(flashVal);

  if(millis() - darkValMillis >= darkVal)
  {
    // LEDs will be a RGB value of 0 to 255 to vary brightness
    for (int blinkTimes = 0; blinkTimes <= flashVal; blinkTimes++)
    {
      switch(state)
      {
        case 0:   // generate random values
          Serial.println("Case 0:  Generate Random Values");
          byte lightVal = random(0, 255); // lightVal set to r, g, b. Can be changed to individual values for other colors
          Serial.print("lightVal = ");
          Serial.println(lightVal);
          byte r = lightVal;
          byte g = lightVal;
          byte b = lightVal;
          int brightVal = random(20, 200); // LEDs will remain on between 20ms and 200ms
          Serial.print("brightVal = ");
          Serial.println(brightVal);
          int delayVal = random(20, 500);  // Flashes will be delayed between 20ms and 500ms     
          Serial.print("delayVal = ");
          Serial.println(delayVal);
          state = 1;
          break;
        case 1:   // turn pixels ON
          Serial.println("Case 1:  Turn Pixels ON");
          Serial.print("state = ");
          Serial.println(state);
          for (int i = 0; i < NUMPIXELS; i++)
          {
            pixels.setPixelColor(pixelNum[i], pixels.Color(r, g, b));
            pixels.show();
          }
          state = 2;
          break;
        case 2:   // delay for brightVal ms
          delay(brightVal);
          state = 3;
          break;
        case 3:   // turn pixels off
          for (int i = 0; i < NUMPIXELS; i++)
          {
            pixels.setPixelColor(pixelNum[i], pixels.Color(0, 0, 0));
            pixels.show();
          }
          state = 4;
          break;
        case 4:   // delay for delayVal ms
          delay(delayVal);
          state = 0;
          break;
      }
    }
    darkValMillis = millis();
  }
}

noiasca

I made some variables static - otherwise you will set them to 0 each time you jump into your flashLigthning().
and I moved some variables declarations higher from the case 0.

now serial output jumps between 1,2,3,4,0

still don't know what your sketch should do - but it does something ;-)

The sketch produces still some warnings - I guess you can solve it by your own...
Code: [Select]

/*
   https://forum.arduino.cc/index.php?topic=637292.msg
*/
#include <Adafruit_NeoPixel.h>
#define PIN 6
#define NUMPIXELS 1    // default = 12
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_RGB + NEO_KHZ800);

void setup() {
  Serial.begin(115200);       // Initialize serial monitor for debugging
  pinMode(PIN, OUTPUT);       // set data pin as output
  pixels.begin();             // initialize pixels
  pixels.setBrightness(127);  // set pixels to 50% brightness to conserve battery
  pixels.show();              // set pixels to off
}

void loop() {
  flashLightning();
}

void flashLightning() {
  static unsigned long darkValMillis = 0;  // noiasca --> static
  static byte state = 0;                   // noiasca --> static

  // array to store number of pixels (max 255) used for brightVal and to turn pixels off
  byte pixelNum[NUMPIXELS];

  // LEDs remain dark between 1000ms and 10000ms
  uint16_t darkVal = random(300, 500);  // changed to 300-500ms for shorter off times  // noiasca changed type
  //Serial.print("darkVal = ");
  //Serial.println(darkVal);

  // LEDs will flash between 2 and 21 times
  uint16_t flashVal = random(2, 21);  // noiasca changed type
  //Serial.print("flashVal = ");
  //Serial.println(flashVal);


  // brought to higher scope
  byte lightVal;
  byte r, g, b;
  int brightVal;
  int delayVal = 0;

  if (millis() - darkValMillis >= darkVal)
  {
    // LEDs will be a RGB value of 0 to 255 to vary brightness
    for (int blinkTimes = 0; blinkTimes <= flashVal; blinkTimes++)
    {
      switch (state)
      {
        case 0:   // generate random values
          Serial.println("Case 0:  Generate Random Values");
          lightVal = random(0, 255); // lightVal set to r, g, b. Can be changed to individual values for other colors
          Serial.print("lightVal = ");
          Serial.println(lightVal);
          r = lightVal;
          g = lightVal;
          b = lightVal;
          brightVal = random(20, 200); // LEDs will remain on between 20ms and 200ms
          Serial.print("brightVal = ");
          Serial.println(brightVal);
          delayVal = random(20, 500);  // Flashes will be delayed between 20ms and 500ms
          Serial.print("delayVal = ");
          Serial.println(delayVal);
          state = 1;
          break;
        case 1:   // turn pixels ON
          Serial.println("Case 1:  Turn Pixels ON");
          Serial.print("state = ");
          Serial.println(state);
          for (int i = 0; i < NUMPIXELS; i++)
          {
            pixels.setPixelColor(pixelNum[i], pixels.Color(r, g, b));
          }
          pixels.show(); // noiasca as told already
          state = 2;
          break;
        case 2:   // delay for brightVal ms
          Serial.println("Case 2:  delay for brightVal ms");  // noiasca
          delay(brightVal);
          state = 3;
          break;
        case 3:   // turn pixels off
          Serial.println("Case 3:  turn pixels off");  // noiasca
          for (int i = 0; i < NUMPIXELS; i++)
          {
            pixels.setPixelColor(pixelNum[i], pixels.Color(0, 0, 0));
          }
          pixels.show(); // noiasca... as already told ... AFTER the for
          state = 4;
          break;
        case 4:   // delay for delayVal ms
          Serial.println("Case 4:  delay");  // noiasca
          delay(delayVal); // why this dirty delay???
          state = 0;
          break;
      }
    }
    darkValMillis = millis();
  }
}

DE: Wie man Fragen postet:
1. was hat man (Sketch und Hardware)
2. was SOLL es machen
3. was macht es: IST (Fehlverhalten, Fehlermeldungen, Serial.Output ...)
4. Eine Frage stellen bzw. erklären was man erwartet

surveyranger

#5
Sep 23, 2019, 11:43 pm Last Edit: Sep 23, 2019, 11:45 pm by surveyranger
I made some variables static - otherwise you will set them to 0 each time you jump into your flashLigthtning().
and I moved some variables declarations higher from the case 0.

now serial output jumps between 1,2,3,4,0
Thank you for the help!  Or rather I should say:  Vielen Dank fuer die Hilfe!  I made the changes, and it flashes like the original code now.  I guess I should not declare variables in the switch/case.  Next I will get rid of the other two delays.


still don't know what your sketch should do - but it does something ;-)
I have a single pixel connected, and I want to make it look like lightning.  Also, I want to use other patterns.  Eventually, I will connect it to an ATTiny85 and mount it on a pendant.  Hopefully, the coding is the hardest part :-D

surveyranger

Final code to generate "lightning" on a single pixel, but it can be used for multiple pixels:

Code: [Select]

// source:  http://projects.mytestbox.org/?p=49

//Load NeoPixel library
#include <Adafruit_NeoPixel.h>

//Digital output pin and number of LEDs on string
#define PIN 6
#define NUMPIXELS 1    // default = 12
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_RGB + NEO_KHZ800);

// Initialize values used.
//  int brightVal;  // brightVal is how long LEDs are on.
//  int darkVal;    // darkVal is how long before next lightning effect
//  int delayVal;   // delayVal is the delay between lightning effect blinks
//  byte lightVal;  // lightVal is how bright each of the flashes are
//  int flashVal;   // flashVal is how many time the lightning effect flashes
//  int blinkTimes; // blinkTimes is how many times the lightning effect flashes
//  byte r = 0;          // r, g, b are used to set the RGB value of the LED
//  byte g = 0;
//  byte b = 0;
// r, g, b is assigned the value generated from the lightVal variable.
// If you want different RGB values, assign different values to r, g, b.

void setup() {
  //Serial.begin(9600);         // Initialize serial monitor for debugging
  pinMode(PIN, OUTPUT);       // set data pin as output
  pixels.begin();             // initialize pixels
  pixels.setBrightness(127);  // set pixels to 50% brightness to conserve battery
  pixels.show();              // set pixels to off

}

void loop() {
  flashLightning();
}

void flashLightning() {
  static unsigned long darkValMillis = 0;
  static unsigned long brightValMillis = 0;
  static unsigned long delayValMillis = 0;
  static byte state = 0;
 
  // array to store number of pixels (max 255) used for brightVal and to turn pixels off
  byte pixelNum[NUMPIXELS]; 
 
  // LEDs remain dark between 1000ms and 10000ms
  uint16_t darkVal = random(300, 500);  // changed to 300-500ms for shorter off times
  //Serial.println();
  //Serial.print("darkVal = ");
  //Serial.println(darkVal);
 
  // LEDs will flash between 2 and 21 times
  uint16_t flashVal = random(2, 21);
  //Serial.print("flashVal = ");
  //Serial.println(flashVal);

  byte lightVal, r, g, b;
  int brightVal;
  int delayVal = 0;
 
  if(millis() - darkValMillis >= darkVal)
  {
    // LEDs will be a RGB value of 0 to 255 to vary brightness
    for (int blinkTimes = 0; blinkTimes <= flashVal; blinkTimes++)
    {
      switch(state)
      {
        case 0:   // generate random values
          //Serial.println("Generate Random Values");
          //Serial.print("state = ");
          //Serial.println(state);
          lightVal = random(0, 255); // lightVal set to r, g, b. Can be changed to individual values for other colors
          //Serial.print("lightVal = ");
          //Serial.println(lightVal);
          r = lightVal;
          g = lightVal;
          b = lightVal;
          brightVal = random(20, 200); // LEDs will remain on between 20ms and 200ms
          //Serial.print("brightVal = ");
          //Serial.println(brightVal);
          delayVal = random(20, 500);  // Flashes will be delayed between 20ms and 500ms     
          //Serial.print("delayVal = ");
          //Serial.println(delayVal);
          state = 1;
          break;
         
        case 1:   // turn pixels ON
          //Serial.println("Turn Pixels ON");
          //Serial.print("state = ");
          //Serial.println(state);
          for (int i = 0; i < NUMPIXELS; i++)
          {
            pixels.setPixelColor(pixelNum[i], pixels.Color(r, g, b));
          }
          pixels.show();
          state = 2;
          break;
       
        case 2:   // delay for brightVal ms
          //Serial.println("Delay for brightVal ms");
          //Serial.print("state = ");
          //Serial.println(state);
          // delay(brightVal);   // changed to IF statement
          if (millis() - brightValMillis >= brightVal)
          {
          state = 3;
          brightValMillis = millis();   // reset brightValMillis for next time
          }
          break;
       
        case 3:   // turn pixels off
          //Serial.println("Turn Pixels OFF");
          //Serial.print("state = ");
          //Serial.println(state);
          for (int i = 0; i < NUMPIXELS; i++)
          {
            pixels.setPixelColor(pixelNum[i], pixels.Color(0, 0, 0));           
          }
          pixels.show();
          state = 4;
          break;
       
        case 4:   // delay for delayVal ms
          //Serial.println("Delay for delayVal ms");
          //Serial.print("state = ");
          //Serial.println(state);
          // delay(delayVal);    // changed to IF statement
          if (millis() - delayValMillis >= delayVal)
          {
          state = 0;
          delayValMillis = millis();  // reset delayValMillis
          }
          //Serial.println("Cycle Complete");
          break;
      }
    }
    darkValMillis = millis();
  }
}

noiasca

#7
Sep 24, 2019, 01:30 am Last Edit: Sep 24, 2019, 01:32 am by noiasca
I doubt if case 1 and 3 are doing what you really want.

the compiler still gives this warning
Code: [Select]

C:\Daten\myrepository\Arduino\forum\sketch_sep23a\sketch_sep23a.ino:97:33: warning: 'pixelNum$' may be used uninitialized in this function [-Wmaybe-uninitialized]

             pixels.setPixelColor(pixelNum[i], pixels.Color(r, g, b));


you never set your pixelNum  array. So currently I guess only pixel 0 is effected by these rows.

by the way
warnings: check signed vs. unsigned variables, and initialize variables when needed (activate all warnings in your IDE!)
Press CTRL-T in the IDE and see the magic ...


DE: Wie man Fragen postet:
1. was hat man (Sketch und Hardware)
2. was SOLL es machen
3. was macht es: IST (Fehlverhalten, Fehlermeldungen, Serial.Output ...)
4. Eine Frage stellen bzw. erklären was man erwartet

Go Up