Last Modified: | February 27, 2014, at 10:11 PM |
By: | garthfielding2 |
Author: | Garth Fielding II |
This sketch is a program to randomly turn on LED's fading them up and down as they turn on/off. The LED's stay on for a random amount of time, stay turned off for a random amount of time, and the fade between is constant. They simulate fireflies in nature or with 2 LED's they can simulate glowing spooky eyes.
You can easily change the intervals that fireflies are randomly chosen from for both the amount of time to wait before turning an LED on and how long to actually keep the LED on. You can also change the maximum number of fireflies that could potentially be on at once.
I discovered the Arduino when I wanted to create a ton of fireflies floating in my yard for Halloween. With the help of a neighbor, we got 3 fireflies working and fading using hareware that I've had for 20+ years: a 555 timer, resistors, capacitors, and some green LED's. It was a huge hit. Afterwards, I thought there's got to be some major advances since 20 years ago when I last did anything with hardware and switched to writing software. So I spoke to another neighbor about a device I'd heard he had built and he introduced me to the Arduino.
You can find some 22/4 security wire at many hardware stores. It's 22awg wire with 4 strands. Strip off about one to two feet (30-60cm) of the jacketing (the outside sheath) to expose the 4 wires. Strip just a little bit off the end of each of the 4 wires. Attach 2 LED's to the stripped off ends of the 4 wires (pick a color - one end you'll plug into ground and the other to where you have a current limiting resistor coming from a pin). You can solder the wires if you want or just use electrician's tape to affix the LED's to the wires like I did. Either way, wrap some electrician's tape between and around the exposed wires and LED leads to prevent them from touching each other. It also helps to give weight to the wire. Now, hang the wire from a tree, some paracord, a halloween spider web, etc. such that the jacket of the wire is what is touching the tree branch, etc. The 1-2 feet of really thin wire is hanging down towards the ground. When a slight wind picks up it will cause these wires with a bit of tape and an LED to wiggle back and forth - making them look like they are flying. Or, to make some spooky eyes, use the 22/4 security wire and put 2 red LED's in series on the same pin. Then place these LED's close to each other in the bushes or in a tree.
I've also built into the setup code where every LED that you've plugged in will light briefly when the program starts. This is so you can check your hardware setup in your yard. If you realize a firefly didn't light after you've attached everything and started the Arduino, fix it, then press the reset button on the Arduino and it will light every LED again (it will never exceed MAX_FIREFLIES_ON).
LEDs with current limiting resistors attached from each of the 14 pins to ground.
The perfect firefly in my opinion is a 5mm Flat Top LED with a 2.1v forward voltage and a current of 6mA (this is NOT an ultra-bright LED and is a bit harder to find).
If you can't find that since ultra-bright is common, you can use an ultra-bright 5mm Round Green 3.0-3.4v Forward Voltage 20,000mcd LED with 0.14 mA.
You can also experiment with differing values of resistors to get the brightness that you want.
R = (VS - VL) / I ResistorNeeded = (SourceVoltage - LEDForwardVoltage) / Current
Example of a 1 LED setup (where the LED has a Forward Voltage of 3.4v). R=(5v-3.4v)/.00014=11428.6=round up to 12000 ohm Example of a 1 LED setup (where the LED has a Forward Voltage of 2.1v). R=(5v-2.1v)/.006=483.33=round up to 560 ohm Example of a 2 LED setup in series (where the LED has a Forward Voltage of 2.1v R=(5v-2.1v-2.1v)/.006=133.33=round up to 150 ohm NOTE that you cannot do two 3.1v LED's in series as there's only 5v of power).
Note: Why 6mA for the current instead of 20mA? 2 reasons. 1, it looks better with that particular LED. 2, read the warning below on overloading your Arduino.
Note: Forward Voltages are different for every LED. Your package should tell you what they are. For example: Clear Red and Clear Yellow 1.88-2.0V, Clear Green: 2.89-3.1V, Clear Blue, Clear White and Clear Pink: 3.0-3.2V. If you are unsure of what voltage your LED is rated at, connect it up to a circuit with 5V power, a 10k-ohm resistor and use a voltmeter to measure the voltage across the 2 wires of the LED. That will tell you the approximate voltage. Once you have that setting, do the math above to find a 6ma current and then after building that check the LED with the voltmeter again. The settings for the forward voltage may change slightly if at all.
You can easily build this entire circuit on your breadboard to get it working the way you want then come Halloween just pull the LED's off the board and plug in the 22/4 security wire's you've attached to the LED's and voila, instant fireflies.
The code below is setup so that it currently outputs to all 14 pins with the maximum number of pins that could ever be on at the same time set to MAX_FIREFLIES_ON.
Ever wondered why every example of lighting up LED's only lights up 10 pins total? While each pin can send 40mA of power through it, the total power sent through the system at one time cannot exceed 150mA. That means that if you were running LED's on more than 7 pins at full brightness (20mA) you could hit that limit. Some people say you have 200mA and in that case you'd be able to have 10 pins running LED's at full brightness simultaneously (like you see on other examples of PWM with LED's).
When I built my circuit, I ran 28 LED's (2 LED's on each pin). Each LED had a Forward Voltage of 2.1volts and the current on each pin was only 6mA (84ma Total for the system). At that rate, you could run at max 25 different pins (on a mega 2560 for example) simultaneously before you'd hit the limit of 150 mA. You want to stay far away from the limit of 150mA though as running at the limit can also ruin your Arduino. I'd recommend you don't exceed around half of the total (for example 84mA out of 150mA). When running, I've found you typically don't come close to hitting MAX_FIREFLIES_ON if there are 14 pins and you have MAX_FIREFLIES_ON set to 7. In that case you'll see around half of that light on average.
For firefly brightness, I've found that 6mA with a 5mm flat top 2.1v LED is plenty bright. I found that an ultra-bright LED with a 3.4v forward voltage looked good with 0.14mA - which is even less. Play around with the brightness and then make note of how many mA you are using.
There are 2 versions of the code below. They are nearly identical and differ only in how they choose which LED to light up next. What if you setup a set of glowing spooky eyes that took 5 minutes to cycle through all 54 pins on a Mega 2560? That means in one hour you'd have each set of eyes show only 12 times IF every single set of eyes showed once without repeating. If it randomly chose, you could easily have at least one LED out of the 54 show zero times and others that show 24 or more. And if you went to work on Halloween to setup 54 sets of eyes and it's only going to last for 3 hours, you may feel bad that some of the eyes never showed. The second code listing (shuffle sort) solves that problem by making the sequence of lighting up less random. It does this by creating an array of all of the pins and then shuffle sorting that array (like shuffling a deck of cards). It then iterates through that array choosing LED's that are not currently on. When it gets to the end of the array it shuffle sorts the array again.
So why not always pick the second version? Because it's not random anymore it loses something in the way it feels while watching them. Both will work, but I prefer the first code listing more for fireflies and the second if I had a set of glowing spooky eyes.
In short, pick the first version unless you really really want to make sure that every LED must light.
/* Analog and Digital Fireflies This sketch is a program to randomly turn on LED's fading them up and down as they turn on/off. The LED's stay on for a random amount of time, stay turned off for a random amount of time, and the fade between is constant. They simulate fireflies in nature or with 2 LED's they can simulate glowing spooky eyes. You can easily change the intervals that fireflies are randomly chosen from for both the amount of time to wait before turning an LED on and how long to actually keep the LED on. You can also change the maximum number of fireflies that could potentially be on at once. created 2014 by Garth Fielding II The circuit: LEDs with current limiting resistors attached from each of the 14 pins to ground. The perfect firefly in my opinion is a 5mm Flat Top LED with a 2.1v forward voltage and a current of 6mA (this is NOT an ultra-bright LED and is a bit harder to find). If you can't find that since ultra-bright is common, you can use an ultra-bright 5mm Round Green 3.0-3.4v Forward Voltage 20,000mcd LED with 0.14 mA. You can also experiment with differing values of resistors to get the brightness that you want. R = (VS - VL) / I ResistorNeeded = (SourceVoltage - LEDForwardVoltage) / Current Example of a 1 LED setup (where the LED has a Forward Voltage of 3.4v). R=(5v-3.4v)/.00014=11428.6=round up to 12000 ohm 12000 ohm LED (3.4v) Ground PIN ---`/\/\/\/`------|>|--------___ - ` Example of a 1 LED setup (where the LED has a Forward Voltage of 2.1v). R=(5v-2.1v)/.006=483.33=round up to 560 ohm 12000 ohm LED (3.4v) Ground PIN ---`/\/\/\/`------|>|--------___ - ` Example of a 2 LED setup in series (where the LED has a Forward Voltage of 2.1v R=(5v-2.1v-2.1v)/.006=133.33=round up to 150 ohm 150 ohm LED (2.1v) LED (2.1v) Ground PIN ---`/\/\/\/`------|>|------------|>|--------___ - ` NOTE that you cannot do two 3.1v LED's in series as there's only 5v of power). Note: Why 6mA for the current instead of 20mA? 2 reasons. 1, it looks better with that particular LED. 2, read the warning below on overloading your Arduino. Note: Forward Voltages are different for every LED. Your package should tell you what they are. For example: Clear Red and Clear Yellow 1.88-2.0V, Clear Green: 2.89-3.1V, Clear Blue, Clear White and Clear Pink: 3.0-3.2V. If you are unsure of what voltage your LED is rated at, connect it up to a circuit with 5V power, a 10k-ohm resistor and use a voltmeter to measure the voltage across the 2 wires of the LED. That will tell you the approximate voltage. Once you have that setting, do the math above to find a 6ma current and then after building that check the LED with the voltmeter again. The settings for the forward voltage may change slightly if at all. You can easily build this entire circuit on your breadboard to get it working the way you want then come Halloween just pull the LED's off the board and plug in the 22/4 security wire's you've attached to the LED's and voila, instant fireflies. Setup in your yard You can find some 22/4 security wire at many hardware stores. It's 22awg wire with 4 strands. Strip off about one to two feet (30-60cm) of the jacketing (the outside sheath) to expose the 4 wires. Strip just a little bit off the end of each of the 4 wires. Attach 2 LED's to the 4 wires (pick a color - one end you'll plug into ground and the other to where you have a current limiting resistor coming from a pin). You can solder the wires if you want or just use electrician's tape to affix the LED's to the wires like I did. Either way, wrap some electrician's tape between and around the exposed wires and LED leads to prevent them from touching each other. Now, hang the wire from a tree, some paracord, a halloween spider web, etc. such that the jacket of the wire is what is touching the tree branch, etc. The 1-2 feet of really thin wire is hanging down towards the ground. When a slight wind picks up it will cause these wires with a bit of tape and an LED to wiggle back and forth - making them look like they are flying. Or, to make some spooky eyes, use the 22/4 security wire and put 2 red LED's in series on the same pin. Then place these LED's close to each other in the bushes or in a tree. I've also built into the setup code where every LED that you've plugged in will light up briefly. This is so you can check your setup. If you realize a firefly didn't light after you've attached everything, fix it and then press the reset button on the arduino to have it cycle through all of the LED's again. */ /* --------------------WARNING ON CHANGING THIS VALUE------------------- ---DO NOT BLOW UP YOUR ARDUINO BY SENDING TOO MUCH POWER THROUGH IT--- The code below is setup so that it currently outputs to all 14 pins with the maximum number of pins that could ever be on at the same time set to MAX_FIREFLIES_ON. Ever wondered why every example of lighting up LED's only lights up 10 pins total? While each pin can send 40mA of power through it, the total power sent through the system at one time cannot exceed 150mA. That means that if you were running LED's on more than 7 pins at full brightness (20mA) you could hit that limit. Some people say you have 200mA and in that case you'd be able to have 10 pins running LED's at full brightness simultaneously (like you see on other examples of PWM with LED's). When I built my circuit, I ran 28 LED's (2 LED's on each pin). Each LED had a Forward Voltage of 2.1volts and the current on each pin was only 6mA (84ma Total for the system). At that rate, you could run at max 25 different pins (on a mega 2560 for example) simultaneously before you'd hit the limit of 150 mA. You want to stay far away from the limit of 150mA though as running at the limit can also ruin your Arduino. I'd recommend you don't exceed around half of the total (for example 84mA out of 150mA). When running, I've found you typically don't come close to hitting MAX_FIREFLIES_ON if there are 14 pins and you have MAX_FIREFLIES_ON set to 7. In that case you'll see around half of that light on average. For firefly brightness, I've found that 6mA with a 5mm flat top 2.1v LED is plenty bright. I found that an ultra-bright LED with a 3.4v forward voltage looked good with 0.14mA - which is even less. Play around with the brightness and then make note of how many mA you are using. ------------------END WARNING ON CHANGING THIS VALUE----------------- Also, realize that this is the MAX. In usage, you may rarely come close to this. */ #define MAX_FIREFLIES_ON 7 //If you get an Arduino Mega 2560 and want to have all 54 pins showing fireflies then uncomment this line. //#define MEGA_2560 true //Change these values to determine how long the LED stays OFF and how long it stays ON for the Analog fireflies. //These values are in milliseconds times 10 (i.e. 27 = 270 milliseconds). #define ANALOG_MIN_OFF 410 #define ANALOG_MAX_OFF 3000 #define ANALOG_MIN_ON 27 #define ANALOG_MAX_ON 270 //Change these values to determine how long the LED stays OFF and how long it stays ON for the Digital fireflies. //These values are in milliseconds. #define DIGITAL_MIN_OFF 4410 #define DIGITAL_MAX_OFF 30000 #define DIGITAL_MIN_ON 210 #define DIGITAL_MAX_ON 2100 //The number of levels of fade before the LED is off with a digital PWM. //Best to not change these #define DIGITAL_FADE_INTERVAL 20 #define DIGITAL_FADE_WAIT 20 //Used to indicate the 4 states we can be in. typedef enum {FADEUP, ON, FADEDOWN, OFF} FireflyState; typedef struct FireFlyStruct { byte pin; //PWM output pins are 3,5,6,9,10,and 11 FireflyState state; //used to determine what state the LED is in, fading up/down or on/off unsigned long value; //used as LED's current value //Analog Values int duration; //specifies how long the led will be on/off //Digital Values unsigned long time; //Used for time calculations to see if it's time to change state boolean toggle; //Used for toggling the LED on/off with PWM unsigned long fade; //used to calculate how long the led will be on/off for PWM during a fade up/down unsigned long fadeWait; //used to increase the time it takes to fade so it lasts just a little longer. } Firefly; #ifdef MEGA_2560 //MEGA 2560 - 54 pins int analogPins[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 44, 45, 46 }; //int digitalPins[] = { 0, 1, 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, 47, 48, 49, 50, 51, 52, 53 }; int allPins[] = { 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 }; #else //UNO R3 - 14 pins int analogPins[] = { 3, 5, 6, 9, 10, 11 }; //int digitalPins[] = { 0, 1, 2, 4, 7, 8, 12, 13 }; int allPins[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }; #endif Firefly fireflies[sizeof(allPins)/sizeof(*allPins)]; //Used to determine if the current pin is an Analog or a Digital Pin. boolean isAnalog(int pin) { int length = sizeof(analogPins)/sizeof(*analogPins); for (int i=0; i<length; i++) { if (analogPins[i] == pin) return true; } return false; } //At the end of this function, all of the fireflies will be setup //with the data they need in order to work properly. //We also turn on MAX_FIREFLIES_ON fireflies to start us off. void initialize() { for (int i=0; i < (sizeof(fireflies)/sizeof(Firefly)); i++) { //Why am I using this pointer notation of taking the address of the object //and then dereferencing it? It was to show someone how to do it. //If it bothers you, replace every occurrence of "ff->" with "fireflies[i]." and //it will run the same. Firefly *ff = &fireflies[i]; ff->pin = allPins[i]; if (i < MAX_FIREFLIES_ON) ff->state = ON; else ff->state = OFF; ff->value = 0; //Analog Values ff->duration = 0; //Digital Values ff->time = 0; ff->toggle = true; ff->fade = 0; ff->fadeWait = 0; if (i < MAX_FIREFLIES_ON) { if (isAnalog(ff->pin) == true) ff->duration = random(ANALOG_MIN_ON, ANALOG_MAX_ON); else ff->value = millis() + random(DIGITAL_MIN_ON, DIGITAL_MAX_ON); } else { if (isAnalog(ff->pin) == true) ff->duration = random(ANALOG_MIN_OFF, ANALOG_MAX_OFF); else ff->value = ff->time + random(DIGITAL_MIN_OFF, DIGITAL_MAX_OFF); } } } //Determine how many LED's are currently ON and if that is equal to MAX_FIREFLIES_ON, return true. boolean isMaxFireflies() { boolean retValue = false; int cnt = 0; for (int i=0; i < (sizeof(fireflies)/sizeof(Firefly)); i++) { Firefly *ff = &fireflies[i]; if (ff->state != OFF) cnt++; } if (cnt >= MAX_FIREFLIES_ON) { retValue = true; } return retValue; } //Used for our delay of 10ms for analog. unsigned long analogDelayTime = 0; /* ANALOG FIREFLIES NOTE: (there is a 10ms delay on all analog fireflies). There are 4 states the fireflies can be in. ON = Keeps the LED on until the counter reaches the duration set for on. OFF = Keeps the LED off until the counter reaches the duration set for on. FADEUP = Over the course of 500ms, change the LED's brightness about 51 times FADEDOWN = Over the course of 500ms, change the LED's brightness about 51 times When the firefly has finished it's FADEUP, it will determine a random duration for how long to keep the LED on. Similarly, FADEDOWN determines a random duration for how long to keep the LED off. If an LED is ready to be turned on (FADEUP) we check to see if we have reached MAX_FIREFLIES_ON. If we have, then we set that LED back to the OFF state and tell it to wait again without turning on. */ void analogFireflies() { //Put a 10ms delay on all of the analog stuff. if (millis()-analogDelayTime < 10) return; analogDelayTime = millis(); //Iterate through all of the analog fireflies for (int i=0; i < (sizeof(fireflies)/sizeof(Firefly)); i++) { Firefly *ff = &fireflies[i]; if (isAnalog(ff->pin) == false) continue; if (ff->state == ON) { // Pin On analogWrite (ff->pin, 255); ff->value +=1; if (ff->value == ff->duration) { ff->state=FADEDOWN; ff->value = 255; } } else if (ff->state == OFF) { // Pin Off analogWrite (ff->pin, 0); ff->value +=1; if (ff->value == ff->duration) { if (isMaxFireflies()) { ff->value = 0; ff->state=OFF; ff->duration = random(ANALOG_MIN_OFF, ANALOG_MAX_OFF); } else { ff->state=FADEUP; ff->value = 0; } } } else if (ff->state == FADEUP){ // Pin Fade Up ff->value +=5; analogWrite (ff->pin, ff->value); if (ff->value == 255) { ff->value = 0; ff->state=ON; ff->duration = random(ANALOG_MIN_ON, ANALOG_MAX_ON); } } else if (ff->state == FADEDOWN) { // Pin Fade Down ff->value -=5; analogWrite (ff->pin, ff->value); if (ff->value == 0) { ff->value = 0; ff->state=OFF; ff->duration = random(ANALOG_MIN_OFF, ANALOG_MAX_OFF); } } } } /* DIGITAL FIREFLIES There are 4 states the fireflies can be in. ON = Keeps the LED on until the current time becomes greater than how long we set to wait for OFF = Keeps the LED off until the current time becomes greater than how long we set to wait for FADEUP = We turn the LED on and off, changing the duration of time between each to simulate growing brighter FADEDOWN = We turn the LED on and off, changing the duration of time between each to simulate growing dimmer When the firefly has finished it's FADEUP, it will determine a random duration for how long to keep the LED on. Similarly, FADEDOWN determines a random duration for how long to keep the LED off. The code for digital fireflies behaves in the same manner as the analog ones with the following exception. We have to execute PWM manually. PWM (Pulse Width Modulation) is where you turn the LED on/off faster than the human eye can see a change. The rate at which you change how long it is off versus on fools the eye into thinking that it is dimmer when in fact it is just flashing at a different rate. 100% brightness = ------------------------------------ = 5 volts on all the time 75% brightness = ---------___---------___---------___ = Alternating between 5 volts on then 0v off 50% brightness = ------______------______------______ = Alternating between 5 volts on then 0v off 25% brightness = ---_________---_________---_________ = Alternating between 5 volts on then 0v off The digital fireflies replace the "duration" variable with "time, toggle, fade, & fadeWait". These values are used to determine whether to be in the on or off state as the LED flashes in varying intervals to simulate growing dimmer or brighter. For the most part, it works just like the digital fade examples you can find digitalWrite(pin, LOW); delayMicroseconds(period-i); digitalWrite(pin, HIGH); delayMicroseconds(i); The difference being that we don't use delayMicroseconds but do comparisons of time using millis, the value of "i" is "ff->value", and we have a flag to determine whether we are setting HIGH or LOW with the digitalWrite. If an LED is ready to be turned on (FADEUP) we check to see if we have reached MAX_FIREFLIES_ON. If we have, then we set that LED back to the OFF state and tell it to wait again without turning on. */ void digitalFireflies() { for (int i=0; i < (sizeof(fireflies)/sizeof(Firefly)); i++) { Firefly *ff = &fireflies[i]; if (isAnalog(ff->pin) == true) continue; if (ff->state == ON) { // Pin On digitalWrite (ff->pin, HIGH); if (ff->time >= ff->value) { ff->value = DIGITAL_FADE_INTERVAL; ff->state=FADEDOWN; ff->fadeWait = millis(); } } else if (ff->state == OFF) { // Pin Off digitalWrite (ff->pin, LOW); if (ff->time >= ff->value) { if (isMaxFireflies()) { ff->state=OFF; ff->value = ff->time + random(DIGITAL_MIN_OFF, DIGITAL_MAX_OFF); } else { ff->value = 0; ff->state=FADEUP; ff->value = 0; ff->fadeWait = millis(); } } } else if (ff->state == FADEUP){ // Pin Fade Up unsigned long currentMillis = millis(); //We have a short wait before incrementing the value to make the fade take just a little longer. if (millis() - ff->fadeWait > DIGITAL_FADE_WAIT) { ff->value++; ff->fadeWait = millis(); } if (currentMillis - ff->fade > DIGITAL_FADE_INTERVAL - ff->value && ff->toggle == true) { ff->toggle = false; ff->fade = currentMillis; } else if (currentMillis - ff->fade > ff->value && ff->toggle == false) { ff->toggle = true; ff->fade = currentMillis; } if (ff->toggle == true) digitalWrite(ff->pin, LOW); else digitalWrite(ff->pin, HIGH); if (ff->value == DIGITAL_FADE_INTERVAL) { ff->state=ON; ff->value = ff->time + random(DIGITAL_MIN_ON, DIGITAL_MAX_ON); } } else if (ff->state == FADEDOWN) { // Pin Fade Down unsigned long currentMillis = millis(); //We have a short wait before incrementing the value to make the fade take just a little longer. if (millis() - ff->fadeWait > DIGITAL_FADE_WAIT) { ff->value--; ff->fadeWait = millis(); } if (currentMillis - ff->fade > DIGITAL_FADE_INTERVAL - ff->value && ff->toggle == true) { ff->toggle = false; ff->fade = currentMillis; } else if (currentMillis - ff->fade > ff->value && ff->toggle == false) { ff->toggle = true; ff->fade = currentMillis; } if (ff->toggle == true) digitalWrite(ff->pin, LOW); else digitalWrite(ff->pin, HIGH); if (ff->value == 1) { ff->state=OFF; ff->value = ff->time + random(DIGITAL_MIN_OFF, DIGITAL_MAX_OFF); } } ff->time = millis(); } } //---------------------------------------------------------------------------------------------------- void turnLedOn(int pin) { if (isAnalog(pin) == true) analogWrite (pin, 255); else digitalWrite(pin, HIGH); } void turnLedOff(int pin) { if (isAnalog(pin) == true) analogWrite (pin, 0); else digitalWrite(pin, LOW); } //Iterates through all of the pins (digital and analog) and turns them on (up to MAX_FIREFLIES_ON). //Allows us a chance to make sure all of the LED's are connected and working before the program starts //and when we hit reset on the arduino. void caterpillar() { int allcount = (sizeof(allPins)/sizeof(*allPins)); for (int i=allcount-1; i>=0; i--) { if (i < allcount-MAX_FIREFLIES_ON) turnLedOff(allPins[MAX_FIREFLIES_ON+i]); turnLedOn(allPins[i]); delay(250); } for (int i=MAX_FIREFLIES_ON-1; i >=0; i--) { turnLedOff(allPins[i]); delay(250); } } void setup() { //Set all of the digital pins to OUTPUT for (int i=0; i < (sizeof(allPins)/sizeof(*allPins)); i++) { if (isAnalog(i) == false) pinMode(i, OUTPUT); } caterpillar(); initialize(); } void loop() { analogFireflies(); digitalFireflies(); }
/* Analog and Digital Fireflies - Shuffle Sort This sketch is a program to randomly turn on LED's fading them up and down as they turn on/off. The LED's stay on for a random amount of time, stay turned off for a random amount of time, and the fade between is constant. They simulate fireflies in nature or with 2 LED's they can simulate glowing spooky eyes. You can easily change the intervals that fireflies are randomly chosen from for both the amount of time to wait before turning an LED on and how long to actually keep the LED on. You can also change the maximum number of fireflies that could potentially be on at once. This differs from the other "Analog and Digital Fireflies" in that there is more of a guarantee that every LED will light. Due to the nature of randomness, it could be possible for you to light up one LED out of 54 over forty times before another LED has even lit once. This solves that problem by making the sequence of lighting up less random. It does this by creating an array of all of the pins and then shuffle sorting that array (like shuffling a deck of cards). It then iterates through that array choosing LED's that are not currently on. When it gets to the end of the array it shuffle sorts the array again. Why would you want this version over the other one that just chooses a pin at random and uses it as long as the total of pins that are not off is <= MAX_FIREFLIES_ON? What if you setup a set of glowing spooky eyes that took 5 minutes to cycle through all 54 pins on a Mega 2560? That means in one hour you'd have each set of eyes show only 12 times if every single set of eyes showed once without repeating. If it randomly chose, you could easily have at least one LED out of the 54 show zero times and others show 24 or more. And if you went to work on Halloween to setup 54 sets of eyes and it's only going to last for 3 hours, you may feel bad that some of the eyes never showed. created 2014 by Garth Fielding II The circuit: LEDs with current limiting resistors attached from each of the 14 pins to ground. The perfect firefly in my opinion is a 5mm Flat Top LED with a 2.1v forward voltage and a current of 6mA (this is NOT an ultra-bright LED and is a bit harder to find). If you can't find that since ultra-bright is common, you can use an ultra-bright 5mm Round Green 3.0-3.4v Forward Voltage 20,000mcd LED with 0.14 mA. You can also experiment with differing values of resistors to get the brightness that you want. R = (VS - VL) / I ResistorNeeded = (SourceVoltage - LEDForwardVoltage) / Current Example of a 1 LED setup (where the LED has a Forward Voltage of 3.4v). R=(5v-3.4v)/.00014=11428.6=round up to 12000 ohm 12000 ohm LED (3.4v) Ground PIN ---`/\/\/\/`------|>|--------___ - ` Example of a 1 LED setup (where the LED has a Forward Voltage of 2.1v). R=(5v-2.1v)/.006=483.33=round up to 560 ohm 12000 ohm LED (3.4v) Ground PIN ---`/\/\/\/`------|>|--------___ - ` Example of a 2 LED setup in series (where the LED has a Forward Voltage of 2.1v R=(5v-2.1v-2.1v)/.006=133.33=round up to 150 ohm 150 ohm LED (2.1v) LED (2.1v) Ground PIN ---`/\/\/\/`------|>|------------|>|--------___ - ` NOTE that you cannot do two 3.1v LED's in series as there's only 5v of power). Note: Why 6mA for the current instead of 20mA? 2 reasons. 1, it looks better with that particular LED. 2, read the warning below on overloading your Arduino. Note: Forward Voltages are different for every LED. Your package should tell you what they are. For example: Clear Red and Clear Yellow 1.88-2.0V, Clear Green: 2.89-3.1V, Clear Blue, Clear White and Clear Pink: 3.0-3.2V. If you are unsure of what voltage your LED is rated at, connect it up to a circuit with 5V power, a 10k-ohm resistor and use a voltmeter to measure the voltage across the 2 wires of the LED. That will tell you the approximate voltage. Once you have that setting, do the math above to find a 6ma current and then after building that check the LED with the voltmeter again. The settings for the forward voltage may change slightly if at all. You can easily build this entire circuit on your breadboard to get it working the way you want then come Halloween just pull the LED's off the board and plug in the 22/4 security wire's you've attached to the LED's and voila, instant fireflies. Setup in your yard You can find some 22/4 security wire at many hardware stores. It's 22awg wire with 4 strands. Strip off about one to two feet (30-60cm) of the jacketing (the outside sheath) to expose the 4 wires. Strip just a little bit off the end of each of the 4 wires. Attach 2 LED's to the 4 wires (pick a color - one end you'll plug into ground and the other to where you have a current limiting resistor coming from a pin). You can solder the wires if you want or just use electrician's tape to affix the LED's to the wires like I did. Either way, wrap some electrician's tape between and around the exposed wires and LED leads to prevent them from touching each other. Now, hang the wire from a tree, some paracord, a halloween spider web, etc. such that the jacket of the wire is what is touching the tree branch, etc. The 1-2 feet of really thin wire is hanging down towards the ground. When a slight wind picks up it will cause these wires with a bit of tape and an LED to wiggle back and forth - making them look like they are flying. Or, to make some spooky eyes, use the 22/4 security wire and put 2 red LED's in series on the same pin. Then place these LED's close to each other in the bushes or in a tree. I've also built into the setup code where every LED that you've plugged in will light up briefly. This is so you can check your setup. If you realize a firefly didn't light after you've attached everything, fix it and then press the reset button on the arduino to have it cycle through all of the LED's again. */ /* --------------------WARNING ON CHANGING THIS VALUE------------------- ---DO NOT BLOW UP YOUR ARDUINO BY SENDING TOO MUCH POWER THROUGH IT--- The code below is setup so that it currently outputs to all 14 pins with the maximum number of pins that could ever be on at the same time set to MAX_FIREFLIES_ON. Ever wondered why every example of lighting up LED's only lights up 10 pins total? While each pin can send 40mA of power through it, the total power sent through the system at one time cannot exceed 150mA. That means that if you were running LED's on more than 7 pins at full brightness (20mA) you could hit that limit. Some people say you have 200mA and in that case you'd be able to have 10 pins running LED's at full brightness simultaneously (like you see on other examples of PWM with LED's). When I built my circuit, I ran 28 LED's (2 LED's on each pin). Each LED had a Forward Voltage of 2.1volts and the current on each pin was only 6mA (84ma Total for the system). At that rate, you could run at max 25 different pins (on a mega 2560 for example) simultaneously before you'd hit the limit of 150 mA. You want to stay far away from the limit of 150mA though as running at the limit can also ruin your Arduino. I'd recommend you don't exceed around half of the total (for example 84mA out of 150mA). When running, I've found you typically don't come close to hitting MAX_FIREFLIES_ON if there are 14 pins and you have MAX_FIREFLIES_ON set to 7. In that case you'll see around half of that light on average. For firefly brightness, I've found that 6mA with a 5mm flat top 2.1v LED is plenty bright. I found that an ultra-bright LED with a 3.4v forward voltage looked good with 0.14mA - which is even less. Play around with the brightness and then make note of how many mA you are using. ------------------END WARNING ON CHANGING THIS VALUE----------------- Also, realize that this is the MAX. In usage, you may rarely come close to this. */ #define MAX_FIREFLIES_ON 7 //If you get an Arduino Mega 2560 and want to have all 54 pins showing fireflies then uncomment this line. //#define MEGA_2560 true //Change these values to determine how long the LED stays OFF and how long it stays ON for the Analog fireflies. //These values are in milliseconds times 10 (i.e. 27 = 270 milliseconds). #define ANALOG_MIN_OFF 410 #define ANALOG_MAX_OFF 1500 #define ANALOG_MIN_ON 27 #define ANALOG_MAX_ON 270 //Change these values to determine how long the LED stays OFF and how long it stays ON for the Digital fireflies. //These values are in milliseconds. #define DIGITAL_MIN_OFF 410 #define DIGITAL_MAX_OFF 15000 #define DIGITAL_MIN_ON 210 #define DIGITAL_MAX_ON 2100 //The number of levels of fade before the LED is off with a digital PWM. //Best to not change these #define DIGITAL_FADE_INTERVAL 20 #define DIGITAL_FADE_WAIT 20 //Used to indicate the 4 states we can be in. typedef enum {FADEUP, ON, FADEDOWN, OFF} FireflyState; typedef struct FireFlyStruct { byte pin; //PWM output pins are 3,5,6,9,10,and 11 FireflyState state; //used to determine what state the LED is in, fading up/down or on/off unsigned long value; //used as LED's current value //Analog Values int duration; //specifies how long the led will be on/off //Digital Values unsigned long time; //Used for time calculations to see if it's time to change state boolean toggle; //Used for toggling the LED on/off with PWM unsigned long fade; //used to calculate how long the led will be on/off for PWM during a fade up/down unsigned long fadeWait; //used to increase the time it takes to fade so it lasts just a little longer. } Firefly; #ifdef MEGA_2560 //MEGA 2560 - 54 pins int analogPins[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 44, 45, 46 }; //int digitalPins[] = { 0, 1, 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, 47, 48, 49, 50, 51, 52, 53 }; int allPins[] = { 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 }; #else //UNO R3 - 14 pins int analogPins[] = { 3, 5, 6, 9, 10, 11 }; //int digitalPins[] = { 0, 1, 2, 4, 7, 8, 12, 13 }; int allPins[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }; #endif Firefly fireflies[MAX_FIREFLIES_ON]; //Used to determine if the current pin is an Analog or a Digital Pin. boolean isAnalog(int pin) { int length = sizeof(analogPins)/sizeof(*analogPins); for (int i=0; i<length; i++) { if (analogPins[i] == pin) return true; } return false; } int counter = 0; //At the end of this function, all of the fireflies will be setup //with the data they need in order to work properly. //We also turn on MAX_FIREFLIES_ON fireflies to start us off. void initialize() { randomize(); for (int i=0; i < (sizeof(fireflies)/sizeof(Firefly)); i++) { //Why am I using this pointer notation of taking the address of the object //and then dereferencing it? It was to show someone how to do it. //If it bothers you, replace every occurrence of "ff->" with "fireflies[i]." and //it will run the same. Firefly *ff = &fireflies[i]; ff->pin = allPins[i]; if (i < MAX_FIREFLIES_ON) ff->state = ON; else ff->state = OFF; ff->value = 0; //Analog Values ff->duration = 0; //Digital Values ff->time = 0; ff->toggle = true; ff->fade = 0; ff->fadeWait = 0; if (i < MAX_FIREFLIES_ON) { if (isAnalog(ff->pin) == true) ff->duration = random(ANALOG_MIN_ON, ANALOG_MAX_ON); else ff->value = millis() + random(DIGITAL_MIN_ON, DIGITAL_MAX_ON); } else { if (isAnalog(ff->pin) == true) ff->duration = random(ANALOG_MIN_OFF, ANALOG_MAX_OFF); else ff->value = ff->time + random(DIGITAL_MIN_OFF, DIGITAL_MAX_OFF); } counter++; } } //---------------------------------------------------------------------------------------------------- //Used by randomize to swap 2 integers with each other. void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } //Used to shuffle sort all of the elements within the array allPins. void randomize() { int length = sizeof(allPins)/sizeof(*allPins); for (int i= length-1; i>0; i--) { int j = random(length) % (i+1); swap(&allPins[i], &allPins[j]); } } //Retrieves the next element in the array. If we reach the end of the array it performs a shuffle //sort and then grabs the first element in that array. If that element is currently being used by //a firefly then we grab the next one. int getNextValue() { int retValue = getArrayElementOrShuffle(); int lengthFireflies = sizeof(fireflies)/sizeof(Firefly); if (counter < lengthFireflies) { for (int i = 0; i < lengthFireflies; i++) { if (fireflies[i].pin == retValue) { i=-1; retValue = getArrayElementOrShuffle(); } } } return retValue; } //This grabs the next element in the array. If we reach the end of the array it performs a shuffle //sort and then grabs the first element in that array. int getArrayElementOrShuffle() { int length = sizeof(allPins)/sizeof(*allPins); if (counter == length) { counter = 0; randomize(); } int retValue = allPins[counter++]; return retValue; } //---------------------------------------------------------------------------------------------------- //Used for our delay of 10ms for analog. unsigned long analogDelayTime = 0; /* ANALOG FIREFLIES NOTE: (there is a 10ms delay on all analog fireflies). There are 4 states the fireflies can be in. ON = Keeps the LED on until the counter reaches the duration set for on. OFF = Keeps the LED off until the counter reaches the duration set for on. FADEUP = Over the course of 500ms, change the LED's brightness about 51 times FADEDOWN = Over the course of 500ms, change the LED's brightness about 51 times When the firefly has finished it's FADEUP, it will determine a random duration for how long to keep the LED on. Similarly, FADEDOWN determines a random duration for how long to keep the LED off. When we are finished with one LED, we grab the next one from the array. If we hit the end of the array, we shuffle sort the array and then grab the next one. For the first MAX_FIREFLIES_ON in the array, we check to see if they are already being used. If they are, we skip them and move on to the next item in the array. */ void analogFireflies() { //Put a 10ms delay on all of the analog stuff. if (millis()-analogDelayTime < 10) return; analogDelayTime = millis(); //Iterate through all of the analog fireflies for (int i=0; i < (sizeof(fireflies)/sizeof(Firefly)); i++) { Firefly *ff = &fireflies[i]; if (isAnalog(ff->pin) == false) continue; if (ff->state == ON) { // Pin On analogWrite (ff->pin, 255); ff->value +=1; if (ff->value == ff->duration) { ff->state=FADEDOWN; ff->value = 255; } } else if (ff->state == OFF) { // Pin Off analogWrite (ff->pin, 0); ff->value +=1; if (ff->value == ff->duration) { ff->state=FADEUP; ff->value = 0; ff->pin = getNextValue(); } } else if (ff->state == FADEUP){ // Pin Fade Up ff->value +=5; analogWrite (ff->pin, ff->value); if (ff->value == 255) { ff->value = 0; ff->state=ON; ff->duration = random(ANALOG_MIN_ON, ANALOG_MAX_ON); } } else if (ff->state == FADEDOWN) { // Pin Fade Down ff->value -=5; analogWrite (ff->pin, ff->value); if (ff->value == 0) { ff->value = 0; ff->state=OFF; ff->duration = random(ANALOG_MIN_OFF, ANALOG_MAX_OFF); } } } } /* DIGITAL FIREFLIES There are 4 states the fireflies can be in. ON = Keeps the LED on until the current time becomes greater than how long we set to wait for OFF = Keeps the LED off until the current time becomes greater than how long we set to wait for FADEUP = We turn the LED on and off, changing the duration of time between each to simulate growing brighter FADEDOWN = We turn the LED on and off, changing the duration of time between each to simulate growing dimmer When the firefly has finished it's FADEUP, it will determine a random duration for how long to keep the LED on. Similarly, FADEDOWN determines a random duration for how long to keep the LED off. The code for digital fireflies behaves in the same manner as the analog ones with the following exception. We have to execute PWM manually. PWM (Pulse Width Modulation) is where you turn the LED on/off faster than the human eye can see a change. The rate at which you change how long it is off versus on fools the eye into thinking that it is dimmer when in fact it is just flashing at a different rate. 100% brightness = ------------------------------------ = 5 volts on all the time 75% brightness = ---------___---------___---------___ = Alternating between 5 volts on then 0v off 50% brightness = ------______------______------______ = Alternating between 5 volts on then 0v off 25% brightness = ---_________---_________---_________ = Alternating between 5 volts on then 0v off The digital fireflies replace the "duration" variable with "time, toggle, fade, & fadeWait". These values are used to determine whether to be in the on or off state as the LED flashes in varying intervals to simulate growing dimmer or brighter. For the most part, it works just like the digital fade examples you can find digitalWrite(pin, LOW); delayMicroseconds(period-i); digitalWrite(pin, HIGH); delayMicroseconds(i); The difference being that we don't use delayMicroseconds but do comparisons of time using millis, the value of "i" is "ff->value", and we have a flag to determine whether we are setting HIGH or LOW with the digitalWrite. When we are finished with one LED, we grab the next one from the array. If we hit the end of the array, we shuffle sort the array and then grab the next one. For the first MAX_FIREFLIES_ON in the array, we check to see if they are already being used. If they are, we skip them and move on to the next item in the array. */ void digitalFireflies() { for (int i=0; i < (sizeof(fireflies)/sizeof(Firefly)); i++) { Firefly *ff = &fireflies[i]; if (isAnalog(ff->pin) == true) continue; if (ff->state == ON) { // Pin On digitalWrite (ff->pin, HIGH); if (ff->time >= ff->value) { ff->value = DIGITAL_FADE_INTERVAL; ff->state=FADEDOWN; ff->fadeWait = millis(); } } else if (ff->state == OFF) { // Pin Off digitalWrite (ff->pin, LOW); if (ff->time >= ff->value) { ff->value = 0; ff->state=FADEUP; ff->value = 0; ff->fadeWait = millis(); ff->pin = getNextValue(); } } else if (ff->state == FADEUP){ // Pin Fade Up unsigned long currentMillis = millis(); //We have a short wait before incrementing the value to make the fade take just a little longer. if (millis() - ff->fadeWait > DIGITAL_FADE_WAIT) { ff->value++; ff->fadeWait = millis(); } if (currentMillis - ff->fade > DIGITAL_FADE_INTERVAL - ff->value && ff->toggle == true) { ff->toggle = false; ff->fade = currentMillis; } else if (currentMillis - ff->fade > ff->value && ff->toggle == false) { ff->toggle = true; ff->fade = currentMillis; } if (ff->toggle == true) digitalWrite(ff->pin, LOW); else digitalWrite(ff->pin, HIGH); if (ff->value == DIGITAL_FADE_INTERVAL) { ff->state=ON; ff->value = ff->time + random(DIGITAL_MIN_ON, DIGITAL_MAX_ON); } } else if (ff->state == FADEDOWN) { // Pin Fade Down unsigned long currentMillis = millis(); //We have a short wait before incrementing the value to make the fade take just a little longer. if (millis() - ff->fadeWait > DIGITAL_FADE_WAIT) { ff->value--; ff->fadeWait = millis(); } if (currentMillis - ff->fade > DIGITAL_FADE_INTERVAL - ff->value && ff->toggle == true) { ff->toggle = false; ff->fade = currentMillis; } else if (currentMillis - ff->fade > ff->value && ff->toggle == false) { ff->toggle = true; ff->fade = currentMillis; } if (ff->toggle == true) digitalWrite(ff->pin, LOW); else digitalWrite(ff->pin, HIGH); if (ff->value == 1) { ff->state=OFF; ff->value = ff->time + random(DIGITAL_MIN_OFF, DIGITAL_MAX_OFF); } } ff->time = millis(); } } //---------------------------------------------------------------------------------------------------- void turnLedOn(int pin) { if (isAnalog(pin) == true) analogWrite (pin, 255); else digitalWrite(pin, HIGH); } void turnLedOff(int pin) { if (isAnalog(pin) == true) analogWrite (pin, 0); else digitalWrite(pin, LOW); } //Iterates through all of the pins (digital and analog) and turns them on (up to MAX_FIREFLIES_ON). //Allows us a chance to make sure all of the LED's are connected and working before the program starts //and when we hit reset on the arduino. void caterpillar() { int allcount = (sizeof(allPins)/sizeof(*allPins)); for (int i=0; i < allcount; i++) { if (i >= MAX_FIREFLIES_ON) turnLedOff(allPins[i-MAX_FIREFLIES_ON]); turnLedOn(allPins[i]); delay(250); } for (int i=allcount-MAX_FIREFLIES_ON; i < allcount; i++) { turnLedOff(allPins[i]); delay(250); } } void setup() { //Set all of the digital pins to OUTPUT for (int i=0; i < (sizeof(allPins)/sizeof(*allPins)); i++) { if (isAnalog(i) == false) pinMode(i, OUTPUT); } caterpillar(); initialize(); } void loop() { analogFireflies(); digitalFireflies(); }