Firefly Night Light 2.0

I hope the mods here don't mind (or it isn't frowned upon) to continue upon one of the topics from the read-only forums. I wasn't able to get an answer from elsewhere, so I thought this might be my only option (posting in the new forums about the old topic). The original topic is http://arduino.cc/forum/index.php/topic,7940.0.html.

I modified the code from this originally to utilize the TrueRandom library because I found when the program was powered up after being shut down it was actually not random at all but picking the exact same LEDs (meaning if I watched the pattern for 5 minutes and it was lighting LEDs 1, 4, 3, 2, 2, 5, etc, if I powered it down and powered it back up again it would light 1, 4, 3, 2, 2, 5, etc). I also tweaked the delay times to get shorter times between one LED blinking to another starting to blink. None of that is really the issue. Here's my modified code:

/*This sketch is intended to approximate the blinking of fireflies.  It varies the delay between
blinks and varies the total blink time.  I've used the random() function to vary which PWM  output
is chosen for the next blink.
Hope you get some enjoyment out of it.  I created it as a fun night light for my kids.
Chad Richardson -- Chad@ChadsCustomWood.net
*/

#include <TrueRandom.h>  // Include TrueRandom Library

int value;
int pwmPin  = 11;                    // light connected to digital pin 11-- I just chose an initial value
//int ledpin2 = 9;
long time=0;
int period = 500;
int i = 0;
long blink_delay = 1000;		// these must be declared as long due to the random() operation
long blink = 3;
long random_led = 55;
const byte pwmPins [] = {3, 5, 6, 9, 10, 11};

void setup()
{						//nothing to setup
}

void loop()
{
  choose_firefly();
  fade();

  blink_delay = random(50, 500);
  delay(blink_delay);  
  blink = random(2, 12);  //Orginal number wasd (2, 5)
                          //Using 10 instead of 5 gives longer
                          //possible blink times
  
}
void fade()
{
  for(i=0; i<255;)
  {
    time = i;
    value = abs(-127+127*cos(4*PI/period*i));		//the -127 value shifts the cosine curve negative with a zero initial value; abs shifts everything positive
    analogWrite(pwmPin, value);           // sets the value (range from 0 to 255)
    delay(blink);
    i++;
  }
}

void choose_firefly()
  {
    pwmPin = pwmPins [TrueRandom.random (0, 6)];
    
  }

Here's the issue I have.

The code works great as is. It blinks a random LED for a "random" length of time between two numbers and once it stops blinking it'll blink another LED. THAT is the problem. It only blinks one LED at a time! It waits for one LED to stop blinking before it'll initiate another LED blinking. The effect I'd like to have is that up to 3 LEDs could possibly blink at the same time (I say up to 3 because I'd generally not prefer that every LED start blinking at the same time constantly).

I know the problem lies with the "choose_firefly()" function. I've tried initializing pwmPin as an array but that gives me an error. I've tried eliminating choose_firefly from the code but that results in only the LED on pin 11 ever blinking (because pin 11 gets initialized first from the start of the code). I am unfortunately a novice at programming. I took an intro to Java course in college but that's as far as I've been able to get. I see the code above and I understand how it all functions together, but the problem is I'm just stuck on how to make more than one LED light up at a time without it looking like a disco room.

If anyone could offer advice and code on this I'd be very grateful. I'm trying to put this together as a little night light for my niece. The code is fine as is and I'll use it if need be, but I think it would more more realistic and better overall if more than one LED was capable of turning on at a time.

This is how the code functions currently:

Instead of just having blink, make an array blinks with a blink value for each LED. Also have delays and times arrays of the same size. Set a slot of blinks to 0 when the corresponding pin isn't blinking (that is, initially and at the end of a fade).

Have your main loop, with very low probability (determined by the clock speed of the Arduino chip; if you want one blink per second on average [slightly lower, because if all lights are already blinking then you won't start a new blink] then this probability should just be the inverse of the clock speed), pick a slot of blinks that is equal to 0 (if one exists) and set it (and the corresponding delays slot) to some delay value instead, and also set the corresponding times slot to the current time. Then call the fade function (a new one, not your current fade function), which should find the minimum value in delays (call this value D), decrease everything in delays by D, reset delays_i to blinks_i if delays_i is 0 (for all i), and then delay by D. This will let you run different speed blinks in parallel. You'll be able to use the current time and the value of times_i to determine the brightness for the ith LED.

Obviously I haven't tested this, but the general approach will do what you want (multiple blinks of different lengths in parallel), unless I totally screwed up.

Thanks for the reply :). I have a general (more or less elementary) understanding of what you're saying to do, but I have no idea how to go about coding it. This was often the problem I faced when I was taking my java class in college - I knew what the program was supposed to do but I just couldn't figure out how to go about coding it without seeing similar previously written code and figuring out how to apply that to my problem at hand. Using the original code supplied by the original author, I can look through all the coding and understand how it all works together, but take it away and ask me to rewrite it myself from memory or my own knowledge and I'd be completely lost.

Well it's your lucky day, I wrote the code for you, since I'm learning Arduino myself and it seemed like decent practice:

#include <Tlc5940.h>
#include <tlc_animations.h>
#include <tlc_config.h>
#include <tlc_fades.h>
#include <tlc_progmem_utils.h>
#include <tlc_servos.h>
#include <tlc_shifts.h>

#define NUM_LEDS 5
#define BLINK_RES 100
#define MIN_DELAY_MS 5
#define MAX_DELAY_MS 12

int blinks[NUM_LEDS];
int delays[NUM_LEDS];
int values[NUM_LEDS];


void init_led(int led) {
  blinks[led] = delays[led] = values[led] = 0;
}

void set_led(int led, int r, int g, int b) {
  Tlc.set(led * 3, b);
  Tlc.set(led * 3 + 1, g);
  Tlc.set(led * 3 + 2, r);
}

void setup() {
  randomSeed(analogRead(0));
  Tlc.init();
  
  for(int led = 0; led < NUM_LEDS; led++) {
    init_led(led);
  }
}

int fade() {
  int min_delay = -1;
  
  // find min delay
  for(int led = 0; led < NUM_LEDS; led++) {
    if(blinks[led]) { // if this led isn't currently blinking then we ignore it
      if(delays[led] < min_delay || min_delay == -1) {
        min_delay = delays[led];
      }
    }
  }
  
  // decrement all current delays by min delay found
  for(int led = 0; led < NUM_LEDS; led++) {
    if(blinks[led]) { // if this led isn't currently blinking then we ignore it
      delays[led] -= min_delay;
      if(delays[led] == 0) {
        values[led]++;
        delays[led] = blinks[led];
      }
    }
  }
  
  for(int led = 0; led < NUM_LEDS; led++) {
    int val = (BLINK_RES / 2) - abs((BLINK_RES / 2) - values[led]);
    val = val * (4096 / BLINK_RES);
    set_led(led, val, val, 0);
  }
  
  min_delay = max(0, min_delay);
  delay(min_delay);
  
  return min_delay;
}


void loop() {
  Tlc.clear();
  
  // 3000 and 27 arbitrarily chosen
  if(random(3000) < 27) {
    int led_start = random(NUM_LEDS);
    
    // find a random free LED, if one exists
    for(int led = led_start; (led + 1) % NUM_LEDS != led_start; led = led + 1 % NUM_LEDS) {
      if(blinks[led] == 0) {
        blinks[led] = random(MIN_DELAY_MS, MAX_DELAY_MS);
        delays[led] = blinks[led];
        values[led] = 0;
        break;
      }
    }
  }
  
  for(int led = 0; led < NUM_LEDS; led++) {
    if(values[led] == BLINK_RES) {
      init_led(led);
    }
  }
  
  delay(MAX_DELAY_MS - fade());
  
  Tlc.update();
}

I have some TLC 5940-specific stuff in there, but it should be easy enough for you to factor that out. Also, this line val = val * (4096 / BLINK_RES); is where you'll want to put your nonlinear/sinusoid lighting formula; I just did a simple linear fade. Change the 3000 and 27 to change the blink frequency (e.g. lowering 27 will make blinks less frequent; I made it pretty high so I didn't have to wait to see multiple blinks at once.).

Here's a Youtube link; filmed through an anti-static bag to make it easier to see which LEDs are on (without the bag as a filter one LED creates a bright blur covering several LEDs). Firefly - YouTube

The effect looks amazing, but a couple of things. I didn't have the TLC5940 library downloaded before so I got a compile error when I tried to upload the file to board. Once I downloaded and installed that, it worked fine (just a heads up for anybody else who might read this later on). Last issue I had/have is that the code uploaded fine, however, only two LEDs are lighting. They turned on immediately after the program uploaded and haven't turned off. No other LEDs have blinked or fluttered or anything. I'm using the Arduino Uno with the built in ATMega328P chip if that helps any thinking on what the issue could be.

In any event, your code and the video looks EXACTLY like the kind of effect I'm wanting to put together so I really hope I can get this figured out :slight_smile:

EDIT
I imagine it's probably going to be very important that I note that while I'm using the on board ATMega328P chip on the Uno to test code and everything, my goal is to put the finalized code onto an ATTiny85 and have it run off of that. I've seen where you can supposedly wire up to 6 LEDs from 6 of the 8 pins on the Tiny but from the schematic of the Tiny it seems there are only 5 pins that can be used for out (the other 3 are ground, reset, and VCC).

You need a TLC5940 LED driver chip in order to utilize this code.

Edit the code to remove all Tlc library instructions, and you'll be able to output your LED instructions to the built-in PWM pins of the arduino.

That totally makes sense.... now to figure out how to rewrite the code without using TLC......

The TLC stuff is all in one place; rewrite set_led to match your own setup and you should be all set (you'll note I have RGB LEDs connected; I think yours are all just single color, right? So you'd have to adjust it anyway). The Tlc.init() call in setup just initializes the lights to being off, and the Tlc.updateI() call at the end of loop just makes the values that were set with Tlc.set() active. You should be able to remove both of those.

Yeah each of mine are single color, though I'm only using two different color LEDs (yellow and pink) for the final set up. Currently I'm still trying to get the wooden housing set up but once I finish with that I'll tinker around and see if I can figure out how to rewrite the coding. Thanks again for all the help!

No prob, good luck!

OK, I've been working with this code all afternoon taking a few breaks here and there out of frustration. I've been trying to mix and match bits and pieces from different codes but it's like one set of code just isn't compatible with how another set of code has been written. Then the detective work clues in to try and figure out how to make them work together. This is what I've gotten so far:

/* Blink Multiple LEDs without Delay
*
* Turns on and off several light emitting diode(LED) connected to a digital
* pin, without using the delay() function.  This means that other code
* can run at the same time without being interrupted by the LED code.
*/
#include <TrueRandom.h>;
int value;
int times = 0;
int k = 0;
long blink = 3;
int period = 500;
long blink_delay = 1000;


const int NUMLEDS = 6;
byte pin[NUMLEDS] = {3, 5, 6, 9, 10, 11};
byte state[NUMLEDS] = {LOW, LOW, LOW, LOW, LOW, LOW};
unsigned long interval[NUMLEDS] = {TrueRandom.random (200,15000)};
unsigned long time[NUMLEDS];

void setup()
{
 for (int i=0; i<NUMLEDS; ++i)
   pinMode(pin[i], OUTPUT);
}

void loop()
{
  ///////////////////////////////////////////////////////
  blink_delay = random(500, 2001);
  delay(blink_delay);  
  blink = random(2, 15); 
  ///////////////////////////////////////////////////////
  
  
  ///////////////////////////////////////////////////////
 /*unsigned long m = millis();

 for (int i=0; i<NUMLEDS; ++i)
   if (m - time[i] > interval[i])
   {
     time[i] = m;
     state[i] = state[i] == LOW ? HIGH : LOW;
     digitalWrite(pin[i], state[i]);
   }*/
 ////////////////////////////////////////////////////////
 
for(k=0; k<255;)
  {
    times = k;
    value = abs(-127+127*cos(4*PI/period*k));		//the -127 value shifts the cosine curve negative with a zero initial value; abs shifts everything positive
    analogWrite(pin[NUMLEDS], value);           // sets the value (range from 0 to 255)
    delay(blink);
    k++;
  } 
}

OK, so in the void loop() I've separated two key pieces of code. The second part of the code that is separated by the two sets of //////////////, starting with /*unsigned long m.... , when I have it active in the code I get sort of an out of control disco effect. I added in the bit of code, the first block of text separated by two sets of //////// beginning with blink_delay...., from the original source code I was working with in hopes that it would get rid of the disco effect. Well it did....... but in the process 4 of the 6 LEDs turn on and stay turned on and do nothing else. I tried using code from http://www.arduino.cc/en/Tutorial/Fading to little gain. The main bulk of the code is taken from this website http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1225593807. Ya know... I really enjoy challenges and finding stuff out on my own and solving things on my own but I feel like I'm in way over my head on this. I know to get the effect I'm looking for isn't all that complex but I just can't get the code right :(. I guess it's bad when you have so many examples in front of you and can't even figure out how to combine them without issue.

If you just copy/paste my code, remove the TLC stuff, and rewrite set_led, it should work. I removed all the time stuff anyway - the values array (based on BLINK_RES) is now doing that job.

I'll be honest with you, after 30 minutes of bumbling around, I still have no clue how I need to rewrite the set_led bit of code sigh :(. I removed any and all references to TLC and I tried just replacing TLC with values, blinks, delay, etc but nothing was working. I obviously have no clue what I'm doing lol. I understand the concept of getters and setters in programming but I just can't figure out what exactly is being set by that bit of code (other than set_led(led, val, val, 0); ).

set_led just sets the value of an LED. I'm using the TLC library so I call Tlc.set(). If your LEDs are just connected to the Arduino's PWM outs, then you probably want to replace the Tlc.set() calls with analogWrite() calls. So instead of:

void set_led(int led, int r, int g, int b) {
  Tlc.set(led * 3, b);
  Tlc.set(led * 3 + 1, g);
  Tlc.set(led * 3 + 2, r);
}

...you might have something like:

void set_led(int led, int intensity) {
  analogWrite(led, intensity);
}

Remember to limit yourself to 0-255 rather than 0-4096 if you're using the Arduino's 8-bit PWM outputs rather than the 5940's 12-bit ones.

Ahh! See that totally makes sense. OK, so I updated the code just as you suggested. I edited the code so that set_led would get the values led and intensity. I received an error message saying that intensity wasn't in the scope of int fade(). I assumed it just needed some initial starting value, so I added int intensity = 0. The program uploaded but only two of the LEDs are on and they're staying on, no flashing. I edited the code for intensity to equal 255, thinking maybe that would resolve the issue but alas, same thing. This is the entirety of the code I'm using (which is pretty much as you suggested):

#define NUM_LEDS 6
#define BLINK_RES 100
#define MIN_DELAY_MS 5
#define MAX_DELAY_MS 12

int blinks[NUM_LEDS];
int delays[NUM_LEDS];
int values[NUM_LEDS];


void init_led(int led) {
  blinks[led] = delays[led] = values[led] = 0;
}

void set_led(int led, int intensity) {
  analogWrite (led, intensity);
}

void setup() {
  randomSeed(analogRead(0));
  
  
  for(int led = 0; led < NUM_LEDS; led++) {
    init_led(led);
  }
}

int fade() {
 int intensity = 255;
  int min_delay = -1;
  
  // find min delay
  for(int led = 0; led < NUM_LEDS; led++) {
    if(blinks[led]) { // if this led isn't currently blinking then we ignore it
      if(delays[led] < min_delay || min_delay == -1) {
        min_delay = delays[led];
      }
    }
  }
  
  // decrement all current delays by min delay found
  for(int led = 0; led < NUM_LEDS; led++) {
    if(blinks[led]) { // if this led isn't currently blinking then we ignore it
      delays[led] -= min_delay;
      if(delays[led] == 0) {
        values[led]++;
        delays[led] = blinks[led];
      }
    }
  }
  
  for(int led = 0; led < NUM_LEDS; led++) {
    int val = (BLINK_RES / 2) - abs((BLINK_RES / 2) - values[led]);
    val = val * (255 / BLINK_RES);
    set_led(led, intensity);
  }
  
  min_delay = max(0, min_delay);
  delay(min_delay);
  
  return min_delay;
}


void loop() {
  
  // 3000 and 27 arbitrarily chosen
  if(random(3000) < 27) {
    int led_start = random(NUM_LEDS);
    
    // find a random free LED, if one exists
    for(int led = led_start; (led + 1) % NUM_LEDS != led_start; led = led + 1 % NUM_LEDS) {
      if(blinks[led] == 0) {
        blinks[led] = random(MIN_DELAY_MS, MAX_DELAY_MS);
        delays[led] = blinks[led];
        values[led] = 0;
        break;
      }
    }
  }
  
  for(int led = 0; led < NUM_LEDS; led++) {
    if(values[led] == BLINK_RES) {
      init_led(led);
    }
  }
  
  delay(MAX_DELAY_MS - fade());
  
  ;
}

I don't really know if I can say thank you enough for the help and advice and effort and essentially doing all the work for me lol. One day I'll get all this stuff down.... I'm doing this project for a birthday gift for my niece's 4th birthday this weekend and I probably bit off more than I can chew considering this is really my first project using Arduino. Then again, I generally try to be the overachiever when it comes to gifts - rather put a lot of time and energy into it than doing the old run of the mill drive to the mall and grab something :). I was originally going to do a wooden rocking horse for her but I thought "nah, a firefly night light would be so much cooler!" Two weeks later..... at least it's a fun learning experience :slight_smile:

Hey no prob, happy to help. Change set_led(led, intensity); to set_led(led, val); - val is the computed intensity value.

Also, with NUM_LEDS set to 6 and the code unmodified, the LEDs will have to be connected to pins 0-5 on the Arduino...if they're connected to e.g. 2-7 instead, then you'll want the analogWrite call in set_led to look like analogWrite(led + 2, intensity); instead. Make sense?

Getting very close! The code is functioning for a couple of pins but not the others. I think I know why, and the fix will probably involve what you mentioned with "led+2".... I'm using an Arduino Uno board, so my digital pwm pins are at 3, 5, 6, 9, 10, and 11. This is what's currently happening (with NUM_LEDS = 6) ...

Using set_led (led, intensity) as is, pins 3 and 5 light as should be.
set_led (led+1, intensity) -> pins 3, 5, and 6 light.
set_led (led+2, intensity) -> same as previous
set_led (led+3, intensity) -> same as previous
set_led (led+4, intensity) -> pins 5, 6, and 9 light (odd that 3 no longer lights but 9 begins to light)
set_led (led+5, intensity) -> pins 5, 6, 9, and 10 light (again, 3 is no longer lighting)
set_led (led+6, intensity) -> pins 6, 9, 10, and 11 light (but now pin 5 isn't lighting; 3 still isn't lighting anymore)

At led+7, pin 6 kicks out. I imagine from that point on any increase in the number will systematically lock out the remaining leds.

I was going to convert the program to run off of an ATTiny85 but after uploading your version and my original program, only 3 of the pins are outputting. I'm not sure if the other two just don't have any ability to send out signals or what... only one of the pwm pins are actually doing the code correctly anyways, the others with their boring analogue output are just blinking the lights (though I think I read you can fade LEDs with analogue signal....). In any event, it's getting kind of close to crunch time, so since I have a spare ATMega328 chip, I might just pop it in the build since it'll (hopefully) allow for 6 LED's to function like fireflies.

Most of this was just my own incoherent babbling or documentation for others (as far as the different led+ and etc goes). Rfrankel, what do you make of the code not lighting all of the LEDs at the same time? I'm guessing that because the digital pwm outs on the Uno aren't back to back (you go from 3 to 5, 6, then over to 9, 10, and 11) that the code, more or less, reads such as pins 3-8 should be lighting (using led+3 and under as an example). If that's the case, then 9 and higher would never light unless you increased the led+ count.... but that means the lower ones start being unlightable. Or am I just way off base with that thinking?

If the LEDs aren't on consecutive pins then a simple offset won't work; you'll need some kind of mapping from LED numbers to pin numbers. You could do this, for example:

int led_pin_mapping[NUM_LEDS];
// in setup()
led_pin_mapping[0] = 3;
led_pin_mapping[1] = 5;
led_pin_mapping[2] = 6;
led_pin_mapping[3] = 9;
led_pin_mapping[4] = 10;
led_pin_mapping[5] = 11;
// in set_led()
analogWrite(led_pin_mapping[led], intensity);

This will convert the LED argument (in the range 0-5) to the corresponding output pin.

You know that totally makes sense seeing it on the page and it seems like what you would obviously put there in order to initialize the pins but I would have banged my head on the wall for hours and searched through every last document on Google and probably still not realized that was all it took. I've got the code working and it's great, but one thing I'm noticing (and I'm not sure if you've experienced anything similar) that for about 30 seconds, all of the pins/leds will cycle through and light up 3 or 4 times but then only pins 10 and 11 will keep blinking. The remaining ones will remain off. I just cycled off the power and it's doing the same.

I have a theory that it might possibly be due to the leds and resistors I have currently in the system. I'm using 3 yellow leds with forward V around 2.2, 20mA, and 3 pink leds that are around 3.2V, 20mA. I wasn't exactly sure how to go about with resistance since I'm mixing and matching the forward V, so all of the resistors are around 100-120ohms. Could this be causing the yellow leds that are on pins 3, 5, and 6 to not be receiving any voltage? I don't think it is because using the previous starting code each of the leds would blink in and out without issue, though with that code only one at a time was able to be lit.... have you noticed anything similar with yours?

To test that theory out I decided to swap out the yellow leds for 3 more pink ones, so they're all using the same forward voltage and mA. Same issue. Seems that, unless I accidentally deleted a value or something, as the code continues on, one of the for loops causes only pins 10 and 11 to initiate. That's just speculation though, I'm not entirely certain other than that idea.

If you're getting the same behavior each time it could be because the random seed is always the same. Right now it's set like this:

randomSeed(analogRead(0));

I can't think why that'd be a consistent value, but maybe try changing it anyway.