Fading multiple LEDs at Different Rates

Hi Everybody!

I have my first project on an Uno utilizing the fade function. I have something working but wanted to see if I could take it a little further. To describe what is going on, I have six LED lights set to cycle through fade loops, each with different max/min values.

What I would like to be able to do is have each light running through it's cycle at an independent rate (all six are running at the same time) to give it a more organic look. I've taken a look at a few sketches for fades and running multiple things at once but I don't seem to be able to comprehend it.

A bonus would be if I could have a long form program for the LEDs where I could write out multiple hours of behavior as well as have them shut off when I do not expect people to be there.

Here is the code I was working with...

int led_1 = 3;           // the PWM pin the LED is attached to
int led_2 = 5;           // the PWM pin the LED is attached to
int led_3 = 6;           // the PWM pin the LED is attached to
int led_4 = 9;           // the PWM pin the LED is attached to
int led_5 = 10;           // the PWM pin the LED is attached to
int led_6 = 11;           // the PWM pin the LED is attached to

int brightness_1 = 175;    // how bright the LED is
int brightness_2 = 60;    // how bright the LED is
int brightness_3 = 120;    // how bright the LED is
int brightness_4 = 100;    // how bright the LED is
int brightness_5 = 75;    // how bright the LED is
int brightness_6 = 200;    // how bright the LED is

int fadeAmount_1 = 1;    // how many points to fade the LED by
int fadeAmount_2 = 1;    // how many points to fade the LED by
int fadeAmount_3 = 1;    // how many points to fade the LED by
int fadeAmount_4 = 1;    // how many points to fade the LED by
int fadeAmount_5 = 1;    // how many points to fade the LED by
int fadeAmount_6 = 1;    // how many points to fade the LED by



// the setup routine runs once when you press reset:
void setup() {
  // declare pin 9 to be an output:
  pinMode(led_1, OUTPUT);
  pinMode(led_2, OUTPUT);
  pinMode(led_3, OUTPUT);
  pinMode(led_4, OUTPUT);
  pinMode(led_5, OUTPUT);
  pinMode(led_6, OUTPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  // set the brightness of pin 9:
  analogWrite(led_1, brightness_1);
  analogWrite(led_2, brightness_2);
  analogWrite(led_3, brightness_3);
  analogWrite(led_4, brightness_4);
  analogWrite(led_5, brightness_5);
  analogWrite(led_6, brightness_6);

  // change the brightness for next time through the loop:
  brightness_1 = brightness_1 + fadeAmount_1;
  brightness_2 = brightness_2 + fadeAmount_2;
  brightness_3 = brightness_3 + fadeAmount_3;
  brightness_4 = brightness_4 + fadeAmount_4;
  brightness_5 = brightness_5 + fadeAmount_5;
  brightness_6 = brightness_6 + fadeAmount_6;

  // reverse the direction of the fading at the ends of the fade:
  if (brightness_1 <= 7 || brightness_1 >= 205) {
    fadeAmount_1 = -fadeAmount_1;
  } if (brightness_2 <= 5 || brightness_2 >= 175) {
    fadeAmount_2 = -fadeAmount_2;
  } if (brightness_3 <= 10 || brightness_3 >= 180) {
    fadeAmount_3 = -fadeAmount_3;
  } if (brightness_4 <= 15 || brightness_4 >= 210) {
    fadeAmount_4 = -fadeAmount_4;
  } if (brightness_5 <= 10 || brightness_5 >= 200) {
    fadeAmount_5 = -fadeAmount_5;    
  } if (brightness_6 <= 20 || brightness_6 >= 240) {
    fadeAmount_6 = -fadeAmount_6; 
  }
  // wait for 30 milliseconds to see the dimming effect
  delay(90);
}

Any help would be greatly appreciated.

Have you tried messing with the fadeAmount variables? They don't all have to be set to 1.

Also, you would make your life much easier if you used arrays and for loops. You will avoid the inevitable copy-paste errors which arise with numbered variable names too.

Also also, try to avoid comments that don't match the code:

// wait for 30 milliseconds to see the dimming effect
delay(90);

Here is an example of how it would be done with arrays:

const int CHANNELS = 6;

const int LED_PINS[CHANNELS] = {3, 5, 6, 9, 10, 11};
const int MIN_BRIGHTNESS[CHANNELS] = {7, 5, 10, 15, 10, 20};
const int MAX_BRIGHTNESS[CHANNELS] = {205, 175, 180, 210, 200, 240};

int CurrentBrightness[CHANNELS] =  {175, 60, 120, 100, 75, 200};
int FadeAmount[CHANNELS] = {1, 1, 1, 1, 1, 1};

// the setup routine runs once when you press reset:
void setup() {
  for (int i = 0; i < CHANNELS; i++) {
    pinMode(LED_PINS[i], OUTPUT);
  }
}

// the loop routine runs over and over again forever:
void loop() {
  for (int i = 0; i < CHANNELS; i++) {
    analogWrite(LED_PINS[i], CurrentBrightness[i]);

    CurrentBrightness[i] += FadeAmount[i];

    // reverse the direction of the fading at the ends of the fade:
    if (CurrentBrightness[i] <= MIN_BRIGHTNESS[i] ||
        CurrentBrightness[i] >= MAX_BRIGHTNESS[i]) {
      FadeAmount[i] = -FadeAmount[i];
    }
  }

  // wait for 90 milliseconds to see the dimming effect
  delay(90);
}

saximus:
Have you tried messing with the fadeAmount variables? They don't all have to be set to 1.

Also, you would make your life much easier if you used arrays and for loops. You will avoid the inevitable copy-paste errors which arise with numbered variable names too.

Also also, try to avoid comments that don't match the code:

// wait for 30 milliseconds to see the dimming effect

delay(90);

I tried that but it seemed like increasing it made the amount run faster. The goal is slow fades. If I am incorrect in this assessment I will try it again.

johnwasser:
Here is an example of how it would be done with arrays:

const int CHANNELS = 6;

const int LED_PINS[CHANNELS] = {3, 5, 6, 9, 10, 11};
const int MIN_BRIGHTNESS[CHANNELS] = {7, 5, 10, 15, 10, 20};
const int MAX_BRIGHTNESS[CHANNELS] = {205, 175, 180, 210, 200, 240};

int CurrentBrightness[CHANNELS] =  {175, 60, 120, 100, 75, 200};
int FadeAmount[CHANNELS] = {1, 1, 1, 1, 1, 1};

// the setup routine runs once when you press reset:
void setup() {
 for (int i = 0; i < CHANNELS; i++) {
   pinMode(LED_PINS[i], OUTPUT);
 }
}

// the loop routine runs over and over again forever:
void loop() {
 for (int i = 0; i < CHANNELS; i++) {
   analogWrite(LED_PINS[i], CurrentBrightness[i]);

CurrentBrightness[i] += FadeAmount[i];

// reverse the direction of the fading at the ends of the fade:
   if (CurrentBrightness[i] <= MIN_BRIGHTNESS[i] ||
       CurrentBrightness[i] >= MAX_BRIGHTNESS[i]) {
     FadeAmount[i] = -FadeAmount[i];
   }
 }

// wait for 90 milliseconds to see the dimming effect
 delay(90);
}

Thanks, I will mess around with this over the weekend and report back.

One way to have more control over the fade rates is to use fixed-point math. Multiply all of the brightness values by a fixed amount and then divide by that amount when you use the brightness. For example if you multiply them all by 100 you then can adjust the FadeAmount in hundredths of a step. Instead of every 90 milliseconds you can adjust brightness every millisecond and still have reasonably slow fade rates.

On a microcontroller like the Arduino, division operations are very slow. Multiply isn't much better. Because of this it is better to use powers of 2 for scaling. Then you can 'multiply' and 'divide' using shift operations.

const int CHANNELS = 6;

const int LED_PINS[CHANNELS] = {3, 5, 6, 9, 10, 11};

// Note: There is no speed penalty to use multiply or divide in compile-time constants since the
// math is done by the compiler, not the microprocessor.
// Note: To avoid overflow warnings, constants that, multiplied together, won't fit in a signed integer 
// had to be marked "unsigned"
const unsigned int MIN_BRIGHTNESS[CHANNELS] = {7*256, 5*256, 10*256, 15*256, 10*256, 20*256};
const unsigned int MAX_BRIGHTNESS[CHANNELS] = {205U*256U, 175U*256U, 180U*256U, 210U*256U, 200U*256U, 240U*256U};

unsigned int CurrentBrightness[CHANNELS] =  {175U*256U, 60*256, 120*256, 100*256, 75*256, 200U*256U};
int FadeAmount[CHANNELS] = {3, 3, 3, 3, 3, 3};  // Slow the fades down by a factor of 85

// the setup routine runs once when you press reset:
void setup() {
  for (int i = 0; i < CHANNELS; i++) {
    pinMode(LED_PINS[i], OUTPUT);
  }
}

// the loop routine runs over and over again forever:
void loop() {
  for (int i = 0; i < CHANNELS; i++) {
    analogWrite(LED_PINS[i], CurrentBrightness[i]>>8);

    CurrentBrightness[i] += FadeAmount[i];

    // reverse the direction of the fading at the ends of the fade:
    if (CurrentBrightness[i] <= MIN_BRIGHTNESS[i] ||
        CurrentBrightness[i] >= MAX_BRIGHTNESS[i]) {
      FadeAmount[i] = -FadeAmount[i];
    }
  }

  // wait for one milliseconds to see the dimming effect
  delay(1);  // Speed the fades up by a factor of 90
}

Wow that is great, thanks guys. This community is awesome, and this project is going to be so cool.