/*
- Andrew Bolton & Issac Landman - 11/14/23
- FIRE led code (w/diffuser)
- #include "FastLED.h"
- Version 2.0 adapted from v1.1 and v1.2 on 11/14 by ABuck
Version 1.1 - adapted from version 1.0 on 11/1/23
Search for the "AB" to see my notes in comments.
I don't have any other snippets of code that I can integrate.
*/
#include <FastLED.h>
#define COLOR_ORDER GRB
#define CHIPSET WS2812B
#define BRIGHTNESS 150
#define VOLTS 5
#define MAX_AMPS 3600 // value in milliamps--changed to 3600 AB
// Constants defined here
#define NUM_LEDS 150 // The total # leds
#define PIN 5 // Placeholder number, not actual data pin number
//Global variables *
CRGB leds [NUM_LEDS];
// Below is for Fire Palette code
#define FRAMES_PER_SECOND 900
bool gReverseDirection = false;
CRGBPalette16 gPal = HeatColors_p;
// Need the following statement for the counter--AB
uint8_t patternCounter = 0;
// FastLED - Version: Latest
void setup() {
FastLED.addLeds<CHIPSET,PIN,COLOR_ORDER>(leds,NUM_LEDS);
FastLED.setMaxPowerInVoltsAndMilliamps(VOLTS,MAX_AMPS);
FastLED.setBrightness(BRIGHTNESS);
FastLED.clear();
FastLED.show();
gPal = CRGBPalette16( CRGB(175, 3, 210), CRGB(81, 0, 255), CRGB(170, 255, 0));
}
void loop() {
// ***Putting in the code for the loop here. Fire can be fussy. AB
switch (patternCounter) {
case 0:
FireI(50, 100, 10);; //effect one--Isaac's effect AB
break;
case 1:
BouncingBalls(0xff,0,0, 3); //effect two--replace this with your call for function name--Fire2012A? AB
break;
// You need to uncomment the following 6 lines and add your function calls here AB
case 2:
CylonBounce(206, 129, 189, 4, 30, 50);
break;
case 3:
random16_add_entropy( random());
Fire2012WithPalette(); // run simulation frame, using palette colors
// FastLED.show(); // display this frame
// FastLED.delay(1000 / FRAMES_PER_SECOND);
break;
// After you add each call to a function in the loop, you need to add the following function **below* the line 136--AB
}
EVERY_N_SECONDS(10) { //Change the time as needed--AB
nextPattern();
}
FastLED.show();
}
// Change the number after the % to the number of patterns you have--you have to do this AB
void nextPattern() {
patternCounter = (patternCounter + 1) % 4;
}
// **** Now we add the functions you called in the loop above--AB
// *** This is the first function called in the loop above. This and subfunctions take approx 60 lines--AB
// FlameHeight - Use larger value for shorter flames, default=50.
// Sparks - Use larger value for more ignitions and a more active fire (between 0 to 255), default=100.
// DelayDuration - Use larger value for slower flame speed, default=10.
void FireI(int FlameHeight, int Sparks, int DelayDuration) {
static byte heat[NUM_LEDS];
int cooldown;
// Cool down each cell a little
for(int i = 0; i < NUM_LEDS; i++) {
cooldown = random(0, ((FlameHeight * 5) / NUM_LEDS) + 2);
if(cooldown > heat[i]) {
heat[i] = 0;
}
else {
heat[i] = heat[i] - cooldown;
}
}
// Heat from each cell drifts up and diffuses slightly
for(int k = (NUM_LEDS - 1); k >= 2; k--) {
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3;
}
// Randomly ignite new Sparks near bottom of the flame
if(random(255) < Sparks) {
int y = random(7);
heat[y] = heat[y] + random(160, 255);
}
// Convert heat to LED colors
for(int j = 0; j < NUM_LEDS; j++) {
setPixelHeatColor(j, heat[j]);
}
FastLED.show();
delay(DelayDuration);
}
void setPixelHeatColor(int Pixel, byte temperature) {
// Rescale heat from 0-255 to 0-191
byte t192 = round((temperature / 255.0) * 191);
// Calculate ramp up from
byte heatramp = t192 & 0x3F; // 0...63
heatramp <<= 2; // scale up to 0...252
// Figure out which third of the spectrum we're in:
if(t192 > 0x80) { // hottest
leds[Pixel].setRGB(255, 255, heatramp);
}
else if(t192 > 0x40) { // middle
leds[Pixel].setRGB(255, heatramp, 0);
}
else { // coolest
leds[Pixel].setRGB(heatramp, 0, 0);
}
}
// Citation: https://github.com/Electriangle/Fire_Main/blob/main/Fire_Main.ino
// Citation: https://github.com/Electriangle/Fire_Main/blob/main/Fire_Animation.ino
// ****Under here put your second function (and any subfunctions it calls) that you call in the loop above--AB
void BouncingBalls(byte red, byte green, byte blue, int BallCount) {
float Gravity = -9.81;
int StartHeight = 1;
float Height[BallCount];
float ImpactVelocityStart = sqrt( -2 * Gravity * StartHeight );
float ImpactVelocity[BallCount];
float TimeSinceLastBounce[BallCount];
int Position[BallCount];
long ClockTimeSinceLastBounce[BallCount];
float Dampening[BallCount];
for (int i = 0 ; i < BallCount ; i++) {
ClockTimeSinceLastBounce[i] = millis();
Height[i] = StartHeight;
Position[i] = 0;
ImpactVelocity[i] = ImpactVelocityStart;
TimeSinceLastBounce[i] = 0;
Dampening[i] = 0.90 - float(i)/pow(BallCount,2);
}
uint32_t bounceStart = millis(); // added this for timing AB
uint32_t bounceFor = .2 * 60000L; // added this for timing AB
while ((millis() - bounceStart) < bounceFor) { //replaced this for timing AB
for (int i = 0 ; i < BallCount ; i++) {
TimeSinceLastBounce[i] = millis() - ClockTimeSinceLastBounce[i];
Height[i] = 0.5 * Gravity * pow( TimeSinceLastBounce[i]/1000 , 2.0 ) + ImpactVelocity[i] * TimeSinceLastBounce[i]/1000;
if ( Height[i] < 0 ) {
Height[i] = 0;
ImpactVelocity[i] = Dampening[i] * ImpactVelocity[i];
ClockTimeSinceLastBounce[i] = millis();
if ( ImpactVelocity[i] < 0.01 ) {
ImpactVelocity[i] = ImpactVelocityStart;
}
}
Position[i] = round( Height[i] * (NUM_LEDS - 1) / StartHeight);
}
for (int i = 0 ; i < BallCount ; i++) {
setPixel(Position[i],red,green,blue);
}
FastLED.show(); // showStrip(); //replaced this--AB
setAll(0,0,0);
}
}
void setPixel(int Pixel, byte red, byte green, byte blue) {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.setPixelColor(Pixel, strip.Color(red, green, blue));
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
leds[Pixel].r = red;
leds[Pixel].g = green;
leds[Pixel].b = blue;
#endif
}
void setAll(byte red, byte green, byte blue) {
for(int i = 0; i < NUM_LEDS; i++ ) {
setPixel(i, red, green, blue);
}
FastLED.show(); //showStrip(); //replaced this AB
}
// Citation for bouncingBalls https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/
// Timing additions that were added from https://forum.arduino.cc/t/cant-break-out-of-timed-function/1082315/4
// ****Under here put your third function (and any subfunctions it calls) that you call in the loop above--AB
void CylonBounce(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay){
for(int i = 0; i < NUM_LEDS-EyeSize-2; i++) {
setAll(0,0,0);
setPixel(i, red/10, green/10, blue/10);
for(int j = 1; j <= EyeSize; j++) {
setPixel(i+j, red, green, blue);
}
setPixel(i+EyeSize+1, red/10, green/10, blue/10);
FastLED.show();
delay(SpeedDelay);
}
delay(ReturnDelay);
for(int i = NUM_LEDS-EyeSize-2; i > 0; i--) {
setAll(0,0,0);
setPixel(i, red/10, green/10, blue/10);
for(int j = 1; j <= EyeSize; j++) {
setPixel(i+j, red, green, blue);
}
setPixel(i+EyeSize+1, red/10, green/10, blue/10);
FastLED.show();
delay(SpeedDelay);
}
delay(ReturnDelay);
}
// ****Under here put your fourth function (and any subfunctions it calls) that you call in the loop above--AB
#define COOLING 55
// SPARKING: What chance (out of 255) is there that a new spark will be lit?
// Higher chance = more roaring fire. Lower chance = more flickery fire.
// Default 120, suggested range 50-200.
#define SPARKING 50
void Fire2012WithPalette()
{
// Array of temperature readings at each simulation cell
static uint8_t heat[NUM_LEDS];
// Step 1. Cool down every cell a little
for( int i = 0; i < NUM_LEDS; i++) {
heat[i] = qsub8( heat[i], random8(0, ((COOLING * 2) / NUM_LEDS) + 2));
}
// Step 2. Heat from each cell drifts 'up' and diffuses a little
for( int k= NUM_LEDS - 1; k >= 2; k--) {
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
}
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
if( random8() < SPARKING ) {
int y = random8(7);
heat[y] = qadd8( heat[y], random8(160,255) );
}
// Step 4. Map from heat cells to LED colors
for( int j = 0; j < NUM_LEDS; j++) {
// Scale the heat value from 0-255 down to 0-240
// for best results with color palettes.
uint8_t colorindex = scale8( heat[j], 240);
CRGB color = ColorFromPalette( gPal, colorindex);
int pixelnumber;
if( gReverseDirection ) {
pixelnumber = (NUM_LEDS-1) - j;
} else {
pixelnumber = j;
}
leds[pixelnumber] = color;
}
}