//RossRobotics.com
// 5-16-22
// -Initial Release
// 5-18-22
// -Added Fire pattern
// 5-22-22
// -trying to implement a non-blocking meteorRain without success
// -Tried numerous examples but all use blocking code
// 5-26-22
// -Had to ask reddit to get me close
// -Huge thanks to the user https://www.reddit.com/user/christian_suryanto/
// for the working meteorRain version!
// 5-27-22 (2am!)
// -Adjusted settings (figured out how to change full animation intervals)
// -Added color() feature. Just sets all leds to a color via a pot
// 5-28-22
// -Added swipe speed feature [swipeSpeed]
// -Added swipe animation delay(non-blocking) feature. [animationSpeed]
// 5-29-22
// -Added selectable swipe color
// -tweaked a few parameters
#include "FastLED.h"
#include "JC_Button.h"
#define NUM_LEDS 44
CRGB leds[NUM_LEDS];
#define PIN 3
//int swipe = 60; //depreciated! This value is set by pot //Speed of full animation. Higher is Slower
int animationSpeedInput = A3; //how fast the swipe travels.
int swipeSpeedInput = A4;
int swipeColorInput = A1;
int buttonPin = 2;
int colorPin = A2;
Button patternSelect(buttonPin, 25, false, false); // Declare the butto
int buttonPushCounter = 1;
uint8_t thisdelay = 40; // A delay value for the sequence(s)
uint8_t thishue = 0; // Starting hue value.
int8_t thisrot = 1; // Hue rotation speed. Includes direction.
uint8_t deltahue = 1; // Hue change between pixels.
bool thisdir = 0;
void setup() {
//Serial.begin(9600);
FastLED.addLeds<WS2812B, PIN, GRB>(leds, NUM_LEDS).setDither(0);
patternSelect.begin();
pinMode(animationSpeedInput, INPUT);
pinMode(swipeSpeedInput, INPUT);
pinMode(swipeColorInput, INPUT);
pinMode(colorPin, INPUT);
}
void loop() {
readbutton();
switch (buttonPushCounter) {
case 1:
buttonPushCounter == 1; {
meteorRain(0xff,0xff,0xff,3, 64, false, 50);
break;
}
case 2:
buttonPushCounter == 2; {
Fire(35,120,55);
break;
}
case 3:
buttonPushCounter == 3; {
color();
break;
}
case 4:
buttonPushCounter == 4; {
ChangeMe();
EVERY_N_MILLISECONDS(thisdelay) { // FastLED based non-blocking delay to update/display the sequence.
rainbow_march();
}
FastLED.show();
break;
}
}
}
void readbutton() {
patternSelect.read();
if(patternSelect.wasPressed()) {
buttonPushCounter++;
if (buttonPushCounter == 5 ) {
buttonPushCounter = 1;
}else{}
}
}//end_readbutton
void color() {
int mappedHue;
mappedHue = map(analogRead(colorPin), 0, 1023, 0, 255);
fill_solid( leds, NUM_LEDS, CHSV(mappedHue, 255, 255));
FastLED.show();
}
void Fire(int Cooling, int Sparking, int SpeedDelay) {
static byte heat[NUM_LEDS];
int cooldown;
// Step 1. Cool down every cell a little
for( int i = 0; i < NUM_LEDS; i++) {
cooldown = random(0, ((Cooling * 10) / NUM_LEDS) + 2);
if(cooldown>heat[i]) {
heat[i]=0;
} else {
heat[i]=heat[i]-cooldown;
}
}
// 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' near the bottom
if( random(255) < Sparking ) {
int y = random(7);
heat[y] = heat[y] + random(160,255);
//heat[y] = random(160,255);
}
// Step 4. Convert heat to LED colors
for( int j = 0; j < NUM_LEDS; j++) {
setPixelHeatColor(j, heat[j] );
}
showStrip();
delay(SpeedDelay);
}
void setPixelHeatColor (int Pixel, byte temperature) {
// Scale 'heat' down 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
setPixel(Pixel, 255, 255, heatramp);
} else if( t192 > 0x40 ) { // middle
setPixel(Pixel, 255, heatramp, 0);
} else { // coolest
setPixel(Pixel, heatramp, 0, 0);
}
}
byte * Wheel(byte WheelPos) {
static byte c[3];
if(WheelPos < 85) {
c[0]=WheelPos * 3;
c[1]=255 - WheelPos * 3;
c[2]=0;
} else if(WheelPos < 170) {
WheelPos -= 85;
c[0]=255 - WheelPos * 3;
c[1]=0;
c[2]=WheelPos * 3;
} else {
WheelPos -= 170;
c[0]=0;
c[1]=WheelPos * 3;
c[2]=255 - WheelPos * 3;
}
return c;
}
uint16_t i = 0;
void meteorRain(byte red, byte green, byte blue, byte meteorSize, byte meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay)
{
int animationSpeed = map(analogRead(animationSpeedInput), 0, 1023, 100, 0); //time between swipes
int swipeColor = map(analogRead(swipeColorInput), 0, 1023, 0, 255);
int swipeSpeed = map(analogRead(swipeSpeedInput), 0, 1023, 50, 10); //speed of swipe crossing
//Serial.println(swipeSpeed);
if (i == 0) setAll(0,0,0);
EVERY_N_MILLIS_I(timeObj, swipeSpeed){
timeObj.setPeriod(swipeSpeed);
// fade brightness all LEDs one step
for(int j=0; j<NUM_LEDS; j++) {
if( (!meteorRandomDecay) || (random(10)>5) ) {
fadeToBlack(j, meteorTrailDecay );
}
}
// draw meteor
for(int j = 0; j < meteorSize; j++) {
if( ( i-j <NUM_LEDS) && (i-j>=0) ) {
leds[i-j] = CHSV(swipeColor, 255, 255);
}
}
showStrip();
if (i < NUM_LEDS+animationSpeed) i++; else i = 0;
}
}
void rainbow_march() { // The fill_rainbow call doesn't support brightness levels. You would need to change the max_bright value.
if (thisdir == 0) thishue += thisrot; else thishue-= thisrot; // I could use signed math, but 'thisdir' works with other routines.
fill_rainbow(leds, NUM_LEDS, thishue, deltahue);
} // rainbow_march()
void ChangeMe() { // A time (rather than loop) based demo sequencer. This gives us full control over the length of each sequence.
uint8_t secondHand = (millis() / 1000) % 90; // Change '60' to a different value to change length of the loop.
static uint8_t lastSecond = 99; // Static variable, means it's only defined once. This is our 'debounce' variable.
if (lastSecond != secondHand) { // Debounce to make sure we're not repeating an assignment.
lastSecond = secondHand;
switch(secondHand) {
// case 0: thisrot=5; deltahue=10; break;
case 5: thisdir=-1; deltahue=5; break;
//case 10: thisrot=5; break;
//case 15: thisrot=5; thisdir=-1; deltahue=20; break;
// case 20: deltahue=30; break;
// case 25: deltahue=2; thisrot=5; break;
// case 30: break;
}
}
showStrip();
} // ChangeMe()
void fadeToBlack(int ledNo, byte fadeValue) {
#ifdef ADAFRUIT_NEOPIXEL_H
uint32_t oldColor;
uint8_t r, g, b;
int value;
oldColor = strip.getPixelColor(ledNo);
r = (oldColor & 0x00ff0000UL) >> 16;
g = (oldColor & 0x0000ff00UL) >> 8;
b = (oldColor & 0x000000ffUL);
r=(r<=10)? 0 : (int) r-(r*fadeValue/256);
g=(g<=10)? 0 : (int) g-(g*fadeValue/256);
b=(b<=10)? 0 : (int) b-(b*fadeValue/256);
strip.setPixelColor(ledNo, r,g,b);
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
leds[ledNo].fadeToBlackBy( fadeValue );
#endif
}
void showStrip() {
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
strip.show();
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
FastLED.show();
#endif
}
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);
leds[i] = CRGB(red, green, blue);
}
}