Increase brightness of single led until value is met.

I have a set of 30 leds on strip. I also am counting seconds. As the seconds go up, I want the brightness of the first led to slowly increase, until a vlue is met, where it is set permanently on.
This is my current script:

#include <FastLED.h>
#define LED_PIN     17
#define NUM_LEDS    30
CRGB leds[NUM_LEDS];

unsigned long currentSecs = 0;

int totalTime = 99;

void setup() {
  Serial.begin(115200);
  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);

}
void loop() {
  currentSecs = millis() / 1000;

  int sections = totalTime / NUM_LEDS;
  Serial.println(currentSecs);
  for (int i = 0; i < NUM_LEDS; i++) {
    if (currentSecs < sections * i) {
      float b = sections - currentSecs;
      int a = map(b, currentSecs, sections * i, 0, 255);
      leds[i] = CRGB(0, 0, a);
    }
    else {
      leds[i] = CRGB(0, 0, 255);
      FastLED.show();
    }
  }
}

What I am trying here is to map a value to allow it to increase the brightness slowly. However this doesn't work.
What am I doing wrong?

Dream

 currentSecs = millis() / 1000;

There may be several problems, and this may or may not be one of them.

I suspect that you need to learn how C/C++ implements integer math.

currentSecs can only take on the values 0, 1, 2, 3, ...
If millis() is any value from 0 through 999, currentSecs will be 0.
If millis() is any value from 1000 through 1999, currentSecs will be 1.
etc.

If this is your intention, then perhaps I need to look at your code more carefully. If this was not your intention, then perhaps you have some learning to do.

Think you are on the right track BUT

Don't you want the higher leds to be off when time has not yep passed instead of full blue?

And linked to the first, the map functions does NOT contain the output. For example,

unsigned int value = map(2000, 0, 1024, 0, 255);
//value will be 500 which is more than 'toHigh'

[edit after vaj4088]
Ah, yes, if you also want gradual fading during a second you want to stick to ms instead of dividing by 1000 to get seconds. I thought that was intentional though, to get noticeable steps. But indeed might not be.

Some extra notes:

No need for the float. Completely useless here.

Change

map(b, currentSecs, sections * i, 0, 255);
//to
map(sections - currentSecs, currentSecs, sections * i +1, 0, 256);
//NOTE, multiple changes ;)

I would change the variable name 'sections' to 'SectionTime' (which can be a constant).

float b = sections - currentSecs;

sections is an int, currentSecs is unsigned long.
I don't think you're going to get a float for a result.

Along with the other issues I think you need to call FastLED.show() after this line

leds[i] = CRGB(0, 0, a);

Yes and no.

Yes, you need to call .show() to actually set the led.

But no, I would not do it there. Do it after the loop so all leds are updated in one go. Saves a lot of time :slight_smile:

Thanks for all the replies!

I noticed that you pointed out some of my silly mistakes like leaving out .show(), which of course wasn't intended!

Firstly, I changed

currentSecs = millis() / 1000;

to

uint32_t Nmillis = millis();
uint32_t secs = Nmillis / 1000;

this still might not be a good way to do it. (I found it here mathematics - Converting `millis()` to decimal seconds? - Arduino Stack Exchange)

I also changed sections to a float.

Lastly I changed my map to: map(sections - currentSecs, currentSecs, sections * i +1, 0, 256); (this is without new variable names) and moved the .show() function outside the loop.

This is my new code:

uint32_t Nmillis = millis();
  uint32_t secs = Nmillis / 1000; 

  float sections = totalTime / NUM_LEDS;
    for(int i = 0; i < NUM_LEDS; i++){
      if(secs < sections * i){
        float b = sections - secs;
        unsigned int a = map(sections - secs, secs, sections * i +1, 0, 256);
        leds[i] = CRGB(0,0,a);
      }
    }
   FastLED.show();

It had produced a different result to the other code, but still not what I wanted.

Thanks again,
Dream

Splitting it to 'Nmillis' doesn't change a thing.:wink:

DreamingInsanity:
I also changed sections to a float.

Don't! Al your outputs are integers (not to confuse with int) so just stay with integers and simply do the calculations in ms.

septillion:
Splitting it to 'Nmillis' doesn't change a thing.:wink:

Ok, but then how should I do it? From my research, all of what I found divided millis by 1000. And serial.println() prints:

1
1
1
...
2
2
2
....
3
3
3
3
....

every second. I don't understand whats wrong. Would you mind providing some proper code?

septillion:
Al your outputs are integers (not to confuse with int) so just stay with integers and simply do the calculations in ms.

I will change them back.

Thanks,
Dream

DreamingInsanity:
Ok, but then how should I do it?

But why do you need seconds? What's wrong with milliseconds?

Just do all calculations in ms and you're alright :slight_smile:

septillion:
What's wrong with milliseconds?

I was using only small values as an example and to test. When I put this in my real script, I will have at least a time of over 7200 seconds, which is 7,200,000 milliseconds. This is one of the lower end values. On the other end I could be looking at over 61,200,000 milliseconds, which is a lot. By converting it to seconds it's only 61,200 which is much smaller.

I could do it in milliseconds but seconds make the number smaller.

Yeah, it large. So? An unsigned long alone (which is what millis() returns) goes up to 4.294.967.295. And even that's not really a limit.

Because as you noticed, going with seconds does reduce the size of the number. But it also reduces the resolution (aka, the finest timing you can use) to a second. Which is clearly not what you wanted :wink: