How to fade 5 LEDs in a defined time using FastLED

I'm using FastLED library, Arduino Nano and 5 addressable LEDs (WS2812B). I'd like to create the sequence in the image attached. (all in white color for example)

I know how to turn ON each LED every 0.2 sec and I know how to fade. I don't know how to make sure each LED goes from 0% brightness to 100% in 0.4 sec + start fading in the next LED after 0.2 sec.

Can anyone help me figure it out? enter image description here

Nice username.
What have you tried up to this point? Please post your code.
Is this homework? I'm curious where you got that graphic.

Thanks! Yours as well :slight_smile:
It's Homework.

void loop() {
  uint32_t cur_ms = millis();
    if (cur_ms - fade_ms > 200) {
        fade_ms = cur_ms;
        brightness += 5;
        leds[0] = CHSV(255, 0, brightness);
    }

FastLED.show();
// delay(10);

I'm trying to use if (cur_ms - x_ms > Y_MS) twice; one for incrementing the brightness and one for increasing the index to the next LED.
I also need a struct/array to create different brightness value for each LED

each LED behaves the same way if I understand correctly and could be depicted this way.

each LED has it's own ∆T0 and a current brightness. its position in the strip could match the position in an array of struct

struct {
  uint32_t deltaT0;
  uint8_t  brightness;
} myLeds[] {
  {0, 0}, {200, 0}, {400, 0}, {600, 0}, {800, 0}, 
};

it would not be to difficult to iterate over the myLeds array in the loop (once you get the START command to define T0) and compare for each LED at which state you should be and set it accordingly.

1 Like

Thanks, sounds right.
I'd appreciate if you could supply a snippet for loop().

Try it on your own first.
It's all the advise you should need to make an attempt.

nice try :slight_smile:
not if it's school work! propose something

Hint: I'd recommend to use the HSV() model to drive the LED color. it will make your life easier.

Things are getting very messy...
I don't know how to compare the delta for each LED (if that's what I should do at all) and how to start each LED work at the right time.

#include <Arduino.h>
#include <FastLED.h>

#define LED_PIN				    (4)
#define LED_COUNT			    (5)
#define LED_BRIGHTNESS		(20)
#define FADE_MS				    (2000)
#define STEP_MS				    (1000)

CRGB leds[LED_COUNT];

struct {
	CRGB color;
	uint8_t index;
	uint32_t step_ms;
	uint32_t fade_ms;
} effect;

struct {
	uint32_t delta_t;
	uint8_t  brightness;
} pixel[] {{0, 0}, {200, 0}, {400, 0}, {600, 0}, {800, 0}};

uint8_t brightness = 0;

void setup()
{
	Serial.begin(115200);
	pinMode(ERROR_PIN, INPUT_PULLUP);
	FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, LED_COUNT);
	FastLED.setBrightness(LED_BRIGHTNESS);
}

void loop()
{
	uint32_t cur_ms = millis();

  // if (cur_ms - effect.fade_ms > FADE_MS) {
    // 	effect.fade_ms = cur_ms;
    // 	Serial.println("fade");
    //  brightness += 5;
    // 	effect.color = CRGB::White;
    // 	fill_solid(leds, LED_COUNT, CRGB::Black);
    //  leds[effect.index] = CHSV(255, 0, brightness);
    //  if (brightness >= 240) brightness = 250;
  // }
		for (uint8_t i = 0; i < LED_COUNT; i++) {
			if (cur_ms - effect.step_ms > pixel[i].delta_t) {
				effect.step_ms = cur_ms;
				Serial.println(pixel[i].delta_t);
			}
		}
  
  // 	if (effect.index++ >= LED_COUNT)
  // 		effect.index = LED_COUNT;

	// FastLED.show();
	// delay(10);
}

hum... some ideas but not there yet. Actually there is no need for the structure as the LED array will remember the brightness. So we only need to store ∆T0

here is something to work on (typed here, untested, not even sure it's right and I may have inserted intentional bugs)

#include <FastLED.h>
const byte ledPin = 4;
const byte ledCount = 5;
const byte globalLedBrightness = 32;
const byte hue = 255, saturation = 255;
const unsigned long fadeDuration = 400;
const uint32_t pixelsDeltaT0[ledCount] = {0, 200, 400, 600, 800};

const unsigned long T0 = 3000; // start time

CRGB leds[ledCount];

void setup()
{
  Serial.begin(115200);
  FastLED.addLeds<WS2812B, ledPin, GRB>(leds, ledCount);
  FastLED.setBrightness(globalLedBrightness);
}

void loop()
{
  uint32_t now = millis();
  if (now < T0) return; // wait until it's time to start
  uint32_t T = now - T0; // relative time to start time
  for (byte ledIndex = 0; ledIndex < ledCount-1; ledIndex++) {
    if (T >= pixelsDeltaT0[ledIndex] + fadeDuration) {
       // SO WHAT'S THAT STATE ? leds[ledIndex] = ...;   (use  CHSV())
    } else if (T >= pixelsDeltaT0[ledIndex]) {
       // SO WHAT'S THAT STATE ? leds[ledIndex] = ... ;  (use map and CHSV())
    }
  } // end for
  FastLED.show();
}

The human eye has a 10log curve. I think the ramp up should not be linear. I would make a function that calculates the intensity for that moment and then call that function with different timing offsets for the different leds.

@avr_dude, this is a simple question that needs serious thinking and programming skills to put in code. There is no single best solution, there are a few good solutions. I suggest to start with one led.

1 Like

This code seems to work fine, but the LEDs' brightness doesn't change as smooth as I wish it would.
When each one reaches almost maximum brightness it seems glitching/jumping (not a natural fade).

#include <Arduino.h>
#include <FastLED.h>

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

#define LED_PIN				(4)
#define LED_COUNT			(5)
#define LED_BRIGHTNESS			(20)
#define FADE_MS				(400)

CRGB leds[LED_COUNT];

uint16_t pixel_delta[LED_COUNT] = {0, 200, 400, 600, 800};
uint16_t pixel_brightness[LED_COUNT];

void setup()
{
	Serial.begin(115200);
	FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, LED_COUNT);
	FastLED.setBrightness(LED_BRIGHTNESS);
}

void loop()
{
	uint32_t cur_ms = millis();

	for (uint8_t index = 0; index < LED_COUNT; index++) {
		if (cur_ms >= pixel_delta[index] + FADE_MS) {
			leds[index] = CHSV(255, 0, 255);
		} else if (cur_ms >= pixel_delta[index]) {
			leds[index] = CHSV(255, 0, pixel_brightness[index]);
			Serial.println(pixel_brightness[index]);
			if (++pixel_brightness[index] >= 255) pixel_brightness[index] = 255;
		}
	}
	FastLED.show();
}

The Serial prints show the problem:

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
0
82
1
83
2
84
3
85
4
86
5
87
6
88
7
89
8
90
9
91
10
92
11
93
12
94
13
95
14
96
15
97
16
98
17
99
18
100
19
101
20
102
21
103
22
104
23
105
24
106
25
107
26
108
27
109
28
110
29
111
30
112
31
113
32
114
33
115
34
116
35
117
36
118
37
119
38
120
39
121
40
122
41
123
42
124
43
125
44
126
45
127
46
128
47
129
48
130
49
131
50
132
51
133
52
134
53
135
54
136
55
137
56
138
57
139
58
140
59
141
60
142
61
143
62
144
63
145
64
146
65
147
66
148
67
149
68
150
69
151
70
152
71
153
72
154
73
155
74
156
75
157
76
158
77
159
78
79
0
80
1
81
2
82
3
83
4
84
5
85
6
86
7
87
8
88
9
89
10
90
11
91
12
92
13
93
14
94
15
95
16
96
17
97
18
98
19
99
20
100
21
101
22
102
23
103
24
104
25
105
26
106
27
107
28
108
29
109
30
110
31
111
32
112
33
113
34
114
35
115
36
116
37
117
38
118
39
119
40
120
41
121
42
122
43
123
44
124
45
125
46
126
47
127
48
128
49
129
50
130
51
131
52
132
53
133
54
134
55
135
56
136
57
137
58
138
59
139
60
140
61
141
62
142
63
143
64
144
65
145
66
146
67
147
68
148
69
149
70
150
71
151
72
152
73
153
74
154
75
155
76
156
77
157
78
158
79
80
0
81
1
82
2
83
3
84
4
85
5
86
6
87
7
88
8
89
9
90
10
91
11
92
12
93
13
94
14
95
15
96
16
97
17
98
18
99
19
100
20
101
21
102
22
103
23
104
24
105
25
106
26
107
27
108
28
109
29
110
30
111
31
112
32
113
33
114
34
115
35
116
36
117
37
118
38
119
39
120
40
121
41
122
42
123
43
124
44
125
45
126
46
127
47
128
48
129
49
130
50
131
51
132
52
133
53
134
54
135
55
136
56
137
57
138
58
139
59
140
60
141
61
142
62
143
63
144
64
145
65
146
66
147
67
148
68
149
69
150
70
151
71
152
72
153
73
154
74
155
75
156
76
157
77
158
78
159
79
80
0
81
1
82
2
83
3
84
4
85
5
86
6
87
7
88
8
89
9
90
10
91
11
92
12
93
13
94
14
95
15
96
16
97
17
98
18
99
19
100
20
101
21
102
22
103
23
104
24
105
25
106
26
107
27
108
28
109
29
110
30
111
31
112
32
113
33
114
34
115
35
116
36
117
37
118
38
119
39
120
40
121
41
122
42
123
43
124
44
125
45
126
46
127
47
128
48
129
49
130
50
131
51
132
52
133
53
134
54
135
55
136
56
137
57
138
58
139
59
140
60
141
61
142
62
143
63
144
64
145
65
146
66
147
67
148
68
149
69
150
70
151
71
152
72
153
73
154
74
155
75
156
76
157
77
158
78
159
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

I suggested to use map()
You want the brightness to increase based on the moment of the 400ms

@Koepel yes if you deal with RGB - but if you use CHSV this is handled for you. (Assuming they implemented this right)

This is an example of "gamma fade" (if you will).
That's all it does, it may perhaps prove useful in some way --

// millisgammafade01
// It Works! 2019.11.06
// 
//

extern const uint8_t gamma[];
byte led;       // the PWM pin the LED is attached to
int brightness;    // how bright the LED is
int corrected;     // gamma comp'd pick from PROGMEM table

unsigned long markTime;
unsigned long runningTime;
const unsigned long limit = 5UL;  // "speed"
bool change_it;

bool alternate;

void setup()
{
  pinMode(led, OUTPUT);
}

void loop()
{
  alternate = false;
  for (brightness = 31; brightness < 248; brightness ++)
  {
    makeithappen();
  }
  
  for (brightness = 248; brightness > 31; brightness --)
  {
    makeithappen();
  }

  alternate = true;
  for (brightness = 31; brightness < 248; brightness ++)
  {
    makeithappen();
  }
  
  for (brightness = 248; brightness > 31; brightness --)
  {
    makeithappen();
  }
}

void makeithappen ()
{
  if(alternate == false)
  {
    led = 3;
  }
  else
  {
    led = 5;
  }
  change_it = false;
  markTime = millis();
  runningTime = millis();
  while((millis() - markTime) < limit)
  {
    if (change_it == false)
    {
      corrected = pgm_read_byte(&gamma[brightness]);
      analogWrite(led, corrected);
      change_it = true;
    }
    runningTime = millis();
  }
}

const uint8_t PROGMEM gamma[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255};

I don't think I'm using it right.

leds[index] = CHSV(255, 0, map(pixel_brightness[index], 0, 255,0,400));

Although it looks better now, it doesn't seem right.
the syntax for map() is as follows:
map(value, fromLow, fromHigh, toLow, toHigh)

But if now the value of pixel_brightness[index] can reach 400 it overflows.
I mean, "brightness" inside CHSV() should get a value between 0-255 and now I give it values between 0-400. How is it possible?

I would use something like (based on my original code variables)

map(T-pixelsDeltaT0[ledIndex], 0, fadeDuration, 0, 255))

that is you get the relative time by doing T-pixelsDeltaT0[ledIndex]. You know it varies between 0 and fadeDuration (400ms) and you map that between "no brightness" (0) to full brightness (255).

as you might not hit exactly the 400ms mark, your LED would not be at full brightness and thius that's why we keep the other if test to set it to full bright.

I get what you say, but the pixelDeltaT0 array has fixed number I shouldn't change/map.
That's why I created a brightness array pixel_brightness to hold, change, and map the value for each LED.

Can't figure out if I putted map in the right place and used it the right way or not.
Here's my code:

#include <Arduino.h>
#include <FastLED.h>

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

#define LED_PIN				(4)
#define LED_COUNT			(5)
#define LED_BRIGHTNESS			(20)
#define FADE_MS				(400)

CRGB leds[LED_COUNT];

uint16_t pixel_delta[LED_COUNT] = {0, 200, 400, 600, 800};
uint16_t pixel_brightness[LED_COUNT];

void setup()
{
	Serial.begin(115200);
	FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, LED_COUNT);
	FastLED.setBrightness(LED_BRIGHTNESS);
}

void loop()
{
	uint32_t cur_ms = millis();

	for (uint8_t index = 0; index < LED_COUNT; index++) {
		if (cur_ms >= pixel_delta[index] + FADE_MS) {
			leds[index] = CHSV(255, 0, 255);
		} else if (cur_ms >= pixel_delta[index]) {
			leds[index] = CHSV(255, 0, map(pixel_brightness[index], 0, 255,0,400));
			if (++pixel_brightness[index] >= 255) pixel_brightness[index] = 255;
		}
	}
	FastLED.show();
}

you don't need that array, you just calculate the brightness at a given point in time for that LED. map will let you do that, providing a ramp between 0 (black) and 255 (full brightness) as that LED is in the RAMP stage for the 400ms (which you ensure first with the if () test)

that is: you calculate a time value that is within [0, 400] and you map that to [0, 255] to get the brightness