Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 5 of 5

Thread: Trying to make LEDs light up at random intervals

  1. #1

    Trying to make LEDs light up at random intervals

    Hey.
    I have a setup with 5 LEDs. I want these to light up at random intervals, and then fade out.
    My approach is to have an array (NextBlink_LEDi[5]). It has one value for each LED, indicating the next time it should light up.
    I have a loop that compares the current time with the value in the array to determine if the LED should light up or not.


    First I set initial values:
    Code:
    void Blink()
        {
          ActivePattern = BLINK;
          for (int i = 0; i < 5; i++) {
            Index_LEDi[i] = 0;
            NextBlink_LEDi[i] = millis()+(random16()%5000);
          }
          TotalSteps = 255;
        }
    And this is the code that determines if it's time to update the LEDs, and does it:
    Code:
    void BlinkUpdate()
        {
          //Runs through each LED
          for (int i = 0; i < 5; i++)
          {
            //Checks if time now is greater or eaqual to next blink time
            if (millis() >= NextBlink_LEDi[i])
            {
              
              leds[i] = ColorFromPalette( heatcolorPalette, Index_LEDi[i]);   //Sets the color of the LED to a value in a previously generated palette
              Index_LEDi[i]++;                                                //Increases index so that the next color in the palette will be selected on the next round
    
              //Checks if we have run through the entire color palette
              if (Index_LEDi[i] > TotalSteps)
              {
                Index_LEDi[i] = 0;                                            //Resets the index to 0
                NextBlink_LEDi[i] = millis()+(random16()%50000);              //Generates a new time for the next blink
              }
            }
          }
          FastLED.show();  
        }
    The initial values seem to be working, because the LEDs power on in a new random order every time I reset power.
    But then after a LED has run through the color palette it just starts on a new round immediately. It seems like generating a new time for the nest blink doesn't work.

    I recorded a short video so you can better understand:
    https://youtu.be/unGTJ6aRRFQ



    Here is all my code so you can try to run it yourself:
    Code:
    #include "FastLED.h"
    
    /////////// BLINK PARAMETERS \\\\\\\\\\\\\
    
    
    
    /////////// CANDLE PARAMETERS \\\\\\\\\\
    
    // The data-in pin of the NeoPixel
    // #define WICK_PIN                6
    // Any unconnected pin, to try to generate a random seed
    #define UNCONNECTED_PIN         23
    
    // The LED can be in only one of these states at any given time
    #define BRIGHT                  0
    #define UP                      1
    #define DOWN                    2
    #define DIM                     3
    #define BRIGHT_HOLD             4
    #define DIM_HOLD                5
    
    // Percent chance the LED will suddenly fall to minimum brightness
    #define INDEX_BOTTOM_PERCENT    10
    // Absolute minimum red value (green value is a function of red's value)
    #define INDEX_BOTTOM            128
    // Minimum red value during "normal" flickering (not a dramatic change)
    #define INDEX_MIN               192
    // Maximum red value
    #define INDEX_MAX               255
    
    // Decreasing brightness will take place over a number of milliseconds in this range
    #define DOWN_MIN_MSECS          20
    #define DOWN_MAX_MSECS          250
    // Increasing brightness will take place over a number of milliseconds in this range
    #define UP_MIN_MSECS            20
    #define UP_MAX_MSECS            250
    // Percent chance the color will hold unchanged after brightening
    #define BRIGHT_HOLD_PERCENT     20
    // When holding after brightening, hold for a number of milliseconds in this range
    #define BRIGHT_HOLD_MIN_MSECS   0
    #define BRIGHT_HOLD_MAX_MSECS   100
    // Percent chance the color will hold unchanged after dimming
    #define DIM_HOLD_PERCENT        5
    // When holding after dimming, hold for a number of milliseconds in this range
    #define DIM_HOLD_MIN_MSECS      0
    #define DIM_HOLD_MAX_MSECS      50
    
    #define MINVAL(A,B)             (((A) < (B)) ? (A) : (B))
    #define MAXVAL(A,B)             (((A) > (B)) ? (A) : (B))
    
    byte state;
    unsigned long flicker_msecs;
    unsigned long flicker_start;
    byte index_start;
    byte index_end;
    unsigned long current_time;
    
    ///////////////////      \\\\\\\\\\\\\\\\\\\\\\\
    
    #define NUM_LEDS 5
    #define LED_PIN 6
    #define BUTTON 0
    uint8_t sat = 255;
    uint8_t val = 255;
    enum pattern { NONE, RAINBOW_CYCLE, CANDLE, HEAT_COLOR, LOVE, BLINK};
    uint8_t patternID;
    int buttonState;
    int lastButtonState;
    
    DEFINE_GRADIENT_PALETTE( love_gp ) {
      0,    255,  255,  255,    //White
      127,  255,  0,    255,    //Pink
      255,  128,  0,    128};   //Purple
    
    DEFINE_GRADIENT_PALETTE( heatmap_gp ) {
      0,     0,  0,  0,   //black
    128,   255,  0,  0,   //red
    224,   255,255,  0,   //bright yellow
    255,   255,255,255 }; //full white
    
    CRGB leds[NUM_LEDS];
    
    class LedsMultitask
    {
      public:
    
        pattern ActivePattern;
    
        unsigned long Interval;
        unsigned long LastUpdate;
    
        uint16_t TotalSteps;
        int16_t Index;
    
        uint8_t Hue1;
        uint8_t Value1;
        uint8_t Saturation1;
        uint8_t ColorDistance;
    
        uint8_t Index_LEDi[5];
        uint16_t NextBlink_LEDi[5];
        
        CRGBPalette16 heatcolorPalette = heatmap_gp;
        CRGBPalette16 lovePalette = love_gp;
    
            
        LedsMultitask() {};
    
        void Update()
        {
          if((millis() - LastUpdate) > Interval) // time to update
          {
            LastUpdate = millis();
            switch (ActivePattern)
            {
              case RAINBOW_CYCLE:
                 RainbowCycleUpdate();
                 break;
              case CANDLE:
                 CandleCycleUpdate();
                 break;
              case HEAT_COLOR:
                  HeatcolorUpdate();
                  break;
              case LOVE:
                  LoveUpdate();
                  break;
              case BLINK:
                  BlinkUpdate();
                  break;
              default:
                break;
            }
          }
        }
    
        void Blink()
        {
          ActivePattern = BLINK;
          for (int i = 0; i < 5; i++) {
            Index_LEDi[i] = 0;
            NextBlink_LEDi[i] = millis()+(random16()%5000);
          }
          TotalSteps = 255;
        }
    
        // Update the Blink pattern
        void BlinkUpdate()
        {
          //Runs through each LED
          for (int i = 0; i < 5; i++)
          {
            //Checks if time now is greater or eaqual to next blink time
            if (millis() >= NextBlink_LEDi[i])
            {
              
              leds[i] = ColorFromPalette( heatcolorPalette, Index_LEDi[i]);   //Sets the color of the LED to a value in a previously generated palette
              Index_LEDi[i]++;                                                //Increases index so that the next color in the palette will be selected on the next round
    
              //Checks if we have run through the entire color palette
              if (Index_LEDi[i] > TotalSteps)
              {
                Index_LEDi[i] = 0;                                            //Resets the index to 0
                NextBlink_LEDi[i] = millis()+(random16()%50000);              //Generates a new time for the next blink
              }
            }
          }
          FastLED.show();  
        }
        
        void RainbowCycle()
        {
          ActivePattern = RAINBOW_CYCLE;
          Interval = 100;
          TotalSteps = 255;
          Index = 0;
          Value1 = 255;
          Saturation1 = 255;
          ColorDistance = 100;
        }
    
        // Update the Rainbow Cycle Pattern
        void RainbowCycleUpdate()
        {
          for (int i = 0; i < NUM_LEDS; i++)
          {
            uint8_t hue = (Index+(i*ColorDistance));
            leds[i] = CHSV(hue, Saturation1, Value1);
          }
          FastLED.show();
          Increment();    
         }
    
    
         // CANDLE
         void CandleCycle()
        {
          ActivePattern = CANDLE;
          Interval = 0;
          TotalSteps = 255;
          Index = 0;
          set_color(255);
          index_start = 255;
          index_end = 255;
          state = BRIGHT;
        }
    
        void CandleCycleUpdate()
        {
          current_time = millis();
        
          switch (state)
            {
            case BRIGHT:
              flicker_msecs = random(DOWN_MAX_MSECS - DOWN_MIN_MSECS) + DOWN_MIN_MSECS;
              flicker_start = current_time;
              index_start = index_end;
              if ((index_start > INDEX_BOTTOM) &&
                  (random(100) < INDEX_BOTTOM_PERCENT))
                index_end = random(index_start - INDEX_BOTTOM) + INDEX_BOTTOM;
              else
                index_end = random(index_start - INDEX_MIN) + INDEX_MIN;
        
              state = DOWN;
              break;
            case DIM:
              flicker_msecs = random(UP_MAX_MSECS - UP_MIN_MSECS) + UP_MIN_MSECS;
              flicker_start = current_time;
              index_start = index_end;
              index_end = random(INDEX_MAX - index_start) + INDEX_MIN;
              state = UP;
              break;
            case BRIGHT_HOLD:
            case DIM_HOLD:
              if (current_time >= (flicker_start + flicker_msecs))
                state = (state == BRIGHT_HOLD) ? BRIGHT : DIM;
        
              break;
            case UP:
            case DOWN:
              if (current_time < (flicker_start + flicker_msecs))
                set_color(index_start + ((index_end - index_start) * (((current_time - flicker_start) * 1.0) / flicker_msecs)));
              else
                {
                set_color(index_end);
        
                if (state == DOWN)
                  {
                  if (random(100) < DIM_HOLD_PERCENT)
                    {
                    flicker_start = current_time;
                    flicker_msecs = random(DIM_HOLD_MAX_MSECS - DIM_HOLD_MIN_MSECS) + DIM_HOLD_MIN_MSECS;
                    state = DIM_HOLD;
                    }
                  else
                    state = DIM;
                  }
                else
                  {
                  if (random(100) < BRIGHT_HOLD_PERCENT)
                    {
                    flicker_start = current_time;
                    flicker_msecs = random(BRIGHT_HOLD_MAX_MSECS - BRIGHT_HOLD_MIN_MSECS) + BRIGHT_HOLD_MIN_MSECS;
                    state = BRIGHT_HOLD;
                    }
                  else
                    state = BRIGHT;
                  }
                }
        
              break;
            }
        }
    
        void set_color(byte index)
        {
          index = MAXVAL(MINVAL(index, INDEX_MAX), INDEX_BOTTOM);
          if (index >= INDEX_MIN)
          {
            for (int i = 0; i < 5; i++) {
              leds[i] = CRGB(index, (index * 3) / 8, 0);
            }
          }
          else if (index < INDEX_MIN)
          {
            for (int i = 0; i < 5; i++) {
              leds[i] = CRGB(index, (index * 3.25) / 8, 0);
            }
          }
        
          FastLED.show();
        }
    
        void Heatcolor()
        {
          ActivePattern = HEAT_COLOR;
          Interval = 75;
          TotalSteps = 255;
          Index = 0;
          ColorDistance = 25;
        }
        
        void HeatcolorUpdate()
        {
          for (int i = 0; i < NUM_LEDS; i++)
          {
            uint8_t paletteindex = (Index+(i*ColorDistance));
            leds[i] = ColorFromPalette( heatcolorPalette, paletteindex);
          }
          FastLED.show();
          Increment();
        }
    
        void Love()
        {
          ActivePattern = LOVE;
          Interval = 75;
          TotalSteps = 255;
          Index = 0;
          ColorDistance = 25;
        }
        
        void LoveUpdate()
        {
          for (int i = 0; i < NUM_LEDS; i++)
          {
            uint8_t paletteindex = (Index+(i*ColorDistance));
            leds[i] = ColorFromPalette( lovePalette, paletteindex);
          }
          FastLED.show();
          Increment();
        }
    
    
        // Increment the Index and reset at the end
        void Increment()
        {
          Index++;
          if (Index >= TotalSteps)
          {
            Index = 0;
          }
        }
    
        void SetHue1(uint8_t hue) {
          Hue1 = hue;
        }
        void SetSaturation1(uint8_t sat) {
          Saturation1 = sat;
        }
        void SetValue1(uint8_t val) {
          Value1 = val;
        }
        void SetInterval(uint8_t inter) {
          Interval = inter;
        }
        void SetColorDistance(uint8_t dist) {
          ColorDistance = dist;
        }
    };
    
    LedsMultitask Bordlys;
    
    void setup() {
      FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, NUM_LEDS);
      randomSeed(analogRead(UNCONNECTED_PIN));
      random16_add_entropy( analogRead(UNCONNECTED_PIN) );
      patternID = 0;
      pinMode(BUTTON, INPUT_PULLUP);
      Bordlys.Blink();
      Serial.begin(9600);
    }
    
    void loop() {
    
      
      Bordlys.Update();
      random16_add_entropy( analogRead(UNCONNECTED_PIN) );
      
      
      buttonState = digitalRead(BUTTON);
      
      if (buttonState != lastButtonState)
      {
        if(buttonState == LOW)
        {
          NextPattern();
        }
      }
      delay(10);
      lastButtonState = buttonState;
    }
    
    void NextPattern()
    {
      patternID ++;
      if(patternID >= 11)
      {
        patternID = 0;
      }
    
      switch(patternID)
      {  
          // Candle light  
          case 0:
              Bordlys.CandleCycle();
              break;
          // Standard rainbow
          case 1:
              Bordlys.RainbowCycle();
              Bordlys.SetInterval(100);
              Bordlys.SetColorDistance(100);
              Bordlys.SetValue1(255);
              break;
          // fast rainbow   
          case 2:
              Bordlys.SetInterval(10);
              Bordlys.SetValue1(255);
              Bordlys.SetColorDistance(100);
              break;
          // Standard, dimmed rainbow
          case 3:
              Bordlys.SetInterval(100);
              Bordlys.SetValue1(175);
              Bordlys.SetColorDistance(100);
              break;
          // Fast, dimmed rainbow 
          case 4:
              Bordlys.SetInterval(10);
              Bordlys.SetValue1(175);
              Bordlys.SetColorDistance(100);
              break;
          // Low color distance rainbow
          case 5:
              Bordlys.SetInterval(100);
              Bordlys.SetValue1(255);
              Bordlys.SetColorDistance(25);
              break;
          // Low color distance rainbow, fast
          case 6:
              Bordlys.SetInterval(10);
              Bordlys.SetValue1(255);
              Bordlys.SetColorDistance(25);
              break;
           // Low color distance rainbow, dimmed
          case 7:
              Bordlys.SetInterval(100);
              Bordlys.SetValue1(175);
              Bordlys.SetColorDistance(25);
              break;
          // Low color distance rainbow,dimmed, fast
          case 8:
              Bordlys.SetInterval(10);
              Bordlys.SetValue1(175);
              Bordlys.SetColorDistance(25);
              break;
          // Heat colors
          case 9:
              Bordlys.Heatcolor();
              Bordlys.SetInterval(75);
              Bordlys.SetColorDistance(25);
              break;
          // Love
          case 10:
              Bordlys.Love();
              Bordlys.SetInterval(75);
              Bordlys.SetColorDistance(25);
              break;       
          default:
              break;
      }
    
      //Serial.println(patternID);
    }
    Last edited by harald25; 12-24-2016 at 11:48 AM. Reason: Forgot to post all my code

  2. #2
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,085
    I have not tried it yet, but first thing I would try would change the next blink LEDs array to uint32_t and see if it is simply issue of rolling over at 16 bits

  3. #3
    I tried changing it to both uint32_t and unsigned long, but that didn't change anything.
    I've managed to get som serial output, and I can see that the values of the array NextBlink_LEDi[] never changes, after it is set in Blink().

    I'll read some more on your comments in my other post and see if any of your tips from there might help.

  4. #4
    I figured it out! It was even more trivial than uint32_t vs uint16_t.
    This statement was never true:
    Code:
    if (Index_LEDi[i] > TotalSteps)
    Changing it to this fixed the problem:
    Code:
    if (Index_LEDi[i] >= TotalSteps)

    But... I think it's good that you brought up the 32-bit thing, because my NextBlink_LEDi-variable would be overflowed pretty fast as a 16 bit integer.

    Thank you a lot for input on Christmas eve
    And Merry Christmas to you!

  5. #5
    Senior Member Jp3141's Avatar
    Join Date
    Nov 2012
    Posts
    461
    what works really well is to run through the array, and with a probability p, change it from off to on. If you want 10 % of the LEDs on (on average), then p is 0.1 etc. This keeps the whole set of LEDs working randomly.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •