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:
And this is the code that determines if it's time to update the LEDs, and does it:
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:
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: