1

I think many people know about the staircase lights, which will get triggered by 2 PIR-sensors (1x upstairs and 1x downstairs).

Here is my code - which works well. It's not cleaned up - as i don't know how i can simplify it. I think there'll be a much nicer way of getting the same output. :)

#include "FastLED.h"
#define NUM_LEDS 300
CRGB leds[NUM_LEDS];
#define PIN 3
int sensorUP = 5;
int sensorDOWN = 7;
int state = LOW;
int valUP = 0;
int valDOWN = 0;

void setup()
{
  FastLED.addLeds<WS2811, PIN, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
  FastLED.setBrightness(20);
  pinMode(2, INPUT_PULLUP); // internal pull-up resistor
  pinMode(sensorUP, INPUT);
  pinMode(sensorDOWN, INPUT);
  Serial.begin(9600);
}

void loop() {
  valUP = digitalRead(sensorUP);
  valDOWN = digitalRead(sensorDOWN);

  if (valUP == HIGH) {
    colorWipeUP(0x55, 0xFF, 0x00, 2);
    delay(600);
    colorWipeUP(0x00, 0x00, 0x00, 2);
    delay(100);                
  }
  if (valDOWN == HIGH) {
    colorWipeDOWN(0x55, 0xFF, 0x00, 2);
    delay(6000);
    colorWipeDOWN(0x00, 0x00, 0x00, 2);
    delay(100);                
  }
}

void colorWipeUP(byte red, byte green, byte blue, int SpeedDelay) {
  for (uint16_t i = 0; i < NUM_LEDS; i++) {
    setPixel(i, red, green, blue);
   FastLED.show();
    delay(SpeedDelay);
  }
}
void colorWipeDOWN(byte red, byte green, byte blue, int SpeedDelay) {
  for (uint16_t i = 299; i < NUM_LEDS; i--) {
    setPixel(i, red, green, blue);
    FastLED.show();
    delay(SpeedDelay);
  }
}

void setPixel(int Pixel, byte red, byte green, byte blue) {
  leds[Pixel].r = red;
  leds[Pixel].g = green;
  leds[Pixel].b = blue;
}

void setAll(byte red, byte green, byte blue) {
  for (int i = 0; i < NUM_LEDS; i++ ) {
    setPixel(i, red, green, blue);
  }
  FastLED.show();
}

At the moment the LEDs just go on and after a delay off again (one-by-one).

QUESTION: I wish for a little smoother effect by fading them on and off. So i reached the actual output by using different snippets and trying to understand. What i don't understand atm is how to add fading.

1
  • look up analogWrite and pulsed width modulation, or PWM, for how to fade LEDs.
    – MichaelT
    Jan 1, 2020 at 17:39

2 Answers 2

2

Your code is currently written as blocking, so we can leave it that way and add another blocking nested loop. Let's take the colorWipeUP() function as example:

void colorWipeUP(byte red, byte green, byte blue, int SpeedDelay) {
  for (uint16_t i = 0; i < NUM_LEDS; i++) {
    setPixel(i, red, green, blue);
   FastLED.show();
    delay(SpeedDelay);
  }
}

You go through all leds, lighting them up one after another with the provided color, delaying between the LEDs. The brightness of an LED is controlled by the overall RGB value. If you just multiply the RGB components red, green and blue with a number between 0 and 1, you (mostly) keep the color and only control the brightness. For example like this:

void colorWipeUP(byte red, byte green, byte blue, int SpeedDelay) {
  for (uint16_t i = 0; i < NUM_LEDS; i++) {
    for(uint8_t brightness = 0; brightness <= 100; brightness++){
      setPixel(i, red*brightness/100, green*brightness/100, blue*brightness/100);
      FastLED.show();
      delay(fadeDelay);
    }
    delay(SpeedDelay);
  }
}

For every LED we are now going from zero brightness to 100% brightness in a loop, showing each individual step on the LED strip. fadeDelay determines, how fast this fade in should be. You will have to tune both delays to fit your expectations. You can use the same principle for the wipe down.

You may be asking yourself, why I count from 0 to 100 and then dividing by 100 instead of directly counting from 0 to 1 in steps of 0.01. I've done this, because on AVR based microcontrollers you don't have native floating point calculations. This means, that every floating point calculation needs many instructions to execute (because the floating point math is implemented in software instead of hardware). Here I'm counting with integers and when calculating the brightness also only integer math is involved (dividing by 100 is an integer division, which will automatically cut all digits after the decimal point. We don't need them).

Note: With 300 LEDs, the call to FastLED.show() will take some time. I haven't tested the code, but depending on your needs the fading might be too slow, even when you remove the delay call. Then you can simply increase the increment of the for loop, for example to use 10 steps instead of 100:

for(uint8_t brightness=0; brightness<100; brightness+=10)

something like a fade over 10 LEDs

For this I would use a totally different approach. If you view it mathematically, the brightness of each LED is a function of position and time. So we can implement a function much like a mathematical function, that returns the brightness for a given position and a given time. As I understood, you want the a function, that is first constantly zero, then it grows linearly with time and position and then it is constantly full brighntess. We can count the time from the moment, that the sensor is triggered, where we then start with zero brightness and let it rise linearly. Something like this:

int fadeBrightness(int position, unsigned long time){
    int brightness = m_p*position+m_t*time;
    if(brightness > 100) return 100;
    if(brightness < 0) return 0;
    return brightness;
}

m_p and m_t are constants, that you would need to define and fine tune. For fading over 10 LEDs, m_p has to be -10. time is provided as milliseconds. I'm currently not sure about the value of m_t, but you can simply try some values and use one that's fitting.

Then in your colorWipeUP() function you can loop through all LEDs and set their pixel just like in the code above, but this time you use the newly created function.

void colorWipeUP(byte red, byte green, byte blue, int SpeedDelay) {
  unsigned long timestamp = millis();
  while(millis()-timestamp < duration){
    for (uint16_t i = 0; i < NUM_LEDS; i++) {
      setPixel(i, red*fadeBrightness(i, millis()-timestamp)/100, green*fadeBrightness(i, millis()-timestamp)/100, blue*fadeBrightness(i, millis()-timestamp)/100);
    }
    FastLED.show();
  }
}

You need to define the duration according to how long the fading will take with your m_t. If you set it longer, the loop will just loop longer, holding the brightness at 100%.

In the function we first create a timestamp from the millis() function. Then we loop, while the duration of the effect hasn't passed. In each while loop iteration, we set the color components of each LED pixel with the brightness according to our fadeBrightness() function. Then we show this on the LED strip. The function is constantly updating the strip at max speed. The actual speed of the animation is determined by the fadeBrightness() function.

This version is also blocking code, but it can easily be transformed to non-blocking code, that you would call repeatedly until the animation is done.

3
  • Hey chrisl, thank you very much for this detailed explanation. As im trying to get something out of it, i started to struggle with "fadeDelay" and it seems like still one by one LED will be turned off - but with a slightly fade this time. :) What i try to accomplish is something like a fade over 10 LEDs. Don't know how to explain it better - but i found a video which will explain it maybe better. [link]tweaking4all.com/wp-content/uploads/2015/11/… Jan 1, 2020 at 20:29
  • @AxelKummerlöwe I added this to my answer, keeping the old answer intact, since it might be useful for someone.
    – chrisl
    Jan 1, 2020 at 22:00
  • Hey Chrisl, thank you very much for your feedback - AGAIN! :) As i becoming a dad today, maybe tomorrow - i'll be back to this post asap. But i think i'm able to work with your help. Thanks again and a happy new year <3 Jan 3, 2020 at 10:11
0

You could do something like this. (not tested)

void colorWipeUP(byte red, byte green, byte blue, int SpeedDelay) {
  for (int i = -5; i < NUM_LEDS + 5; i++) {
    setPixel(i    ,      red, green, blue);   // example only
    setPixel(i + 1, .8 * red, green, blue);   // change the green and blue also
    setPixel(i + 2, .6 * red, green, blue);
    setPixel(i + 3, .4 * red, green, blue);   // successive pixels have lower brightness
    setPixel(i + 4, .2 * red, green, blue);
    FastLED.show();
    delay(SpeedDelay);
  }
}

void setPixel(int Pixel, byte red, byte green, byte blue) {

  if (Pixel < 0 || Pixel >= NUM_LEDS) return;        // do not set color of non-existent pixels

  leds[Pixel].r = red;
  leds[Pixel].g = green;
  leds[Pixel].b = blue;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.