#include "FastLED.h"
FASTLED_USING_NAMESPACE
#if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3001000)
#warning "Requires FastLED 3.1 or later; check github for latest version"
#endif
#define DATA_PIN 6 // set the data pin to 6
#define LED_TYPE WS2812 // look in the library for your specific LED type if not using NeoPixel/ws2812 type
#define COLOR_ORDER GRB
#define NUM_LEDS 50 // the number of pixels outside the mask
#define NUM_INT_LEDS 10 // the number of pixels inside the mouth and nose area
#define NUM_EYE_LEDS 2 // the number of pixels for the eyes. you could use more, but it limits visibility
CRGB leds[NUM_LEDS + NUM_INT_LEDS + NUM_EYE_LEDS];
// palettes
DEFINE_GRADIENT_PALETTE( Sunset_Real_gp ) {
0, 120, 0, 0,
22, 179, 22, 0,
51, 255,104, 0,
85, 167, 22, 18,
135, 100, 0,103,
198, 16, 0,130,
255, 0, 0,160};
DEFINE_GRADIENT_PALETTE( es_rivendell_15_gp ) {
0, 1, 14, 5,
101, 16, 36, 14,
165, 56, 68, 30,
242, 150,156, 99,
255, 150,156, 99};
DEFINE_GRADIENT_PALETTE( retro2_16_gp ) {
0, 188,135, 1,
255, 46, 7, 1};
DEFINE_GRADIENT_PALETTE( es_ocean_breeze_036_gp ) {
0, 1, 6, 7,
89, 1, 99,111,
153, 144,209,255,
255, 0, 73, 82};
DEFINE_GRADIENT_PALETTE( es_vintage_01_gp ) {
0, 4, 1, 1,
51, 16, 0, 1,
76, 97,104, 3,
101, 255,131, 19,
127, 67, 9, 4,
153, 16, 0, 1,
229, 4, 1, 1,
255, 4, 1, 1};
DEFINE_GRADIENT_PALETTE( rainbowsherbet_gp ) {
0, 255, 33, 4,
43, 255, 68, 25,
86, 255, 7, 25,
127, 255, 82,103,
170, 255,255,242,
209, 42,255, 22,
255, 87,255, 65};
// define the palette array to cycle through
CRGBPalette16 aPal[] = {
Sunset_Real_gp,
es_rivendell_15_gp,
es_vintage_01_gp,
es_ocean_breeze_036_gp,
rainbowsherbet_gp,
retro2_16_gp
};
// clickPal changes as you press the palette buttons
int clickPal;
// button pins
const int BUTPIN1 = 3;
const int BUTPIN2 = 7;
const int BUTPIN3 = 8;
// standard input set up
int button1State;
int lastButton1State = LOW;
int button2State;
int lastButton2State = LOW;
int button3State;
int lastButton3State = LOW;
long lastDebounceTime = 0;
long debounceDelay = 50;
// BRIGHTNESS and FRAMES_PER_SECOND: you can slow the plasma by reducing the fps, but I recommend 90 or higher, brightness is user preference, 160+ looks good.
#define BRIGHTNESS 255
#define FRAMES_PER_SECOND 120
// off: when true, the plasma stops
bool off;
// x and y coordinates for the plasma. if you want the inner and outer to sync, you'll need to add " + NUM_INT_LEDS" and not call the interior mask functions
uint8_t x[NUM_LEDS];
uint8_t y[NUM_LEDS];
CRGBPalette16 gPal;
void setup() {
pinMode(BUTPIN1, INPUT);
pinMode(BUTPIN2, INPUT);
pinMode(BUTPIN3, INPUT);
// define the initial angle for the plasma
for (uint16_t i = 0; i < NUM_LEDS; i++) {
uint8_t angle = (i * 255) / NUM_LEDS;
x[i] = cos8( angle );
y[i] = sin8( angle );
}
// 3 second delay for recovery
delay(3000);
// tell FastLED the LED strip configuration
FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS + NUM_INT_LEDS + NUM_EYE_LEDS).setCorrection(TypicalLEDStrip);
// set master brightness control
FastLED.setBrightness(BRIGHTNESS);
}
// List of patterns to cycle through. Patterns are defined as functions below.
typedef void (*SimplePatternList[])();
// you can write your own pattern functions and include them here, no arguments allowed.
SimplePatternList gPatterns = { turnOn, slow_xy, slow_yx, fast_z, turnOff };
uint8_t gCurrentPatternNumber = 0; // start the plasma with the "turnOn" function
uint8_t gHue = 0; // rotating base color used by some of the patterns
void loop() {
button1State = digitalRead(BUTPIN1);
button2State = digitalRead(BUTPIN2);
button3State = digitalRead(BUTPIN3);
unsigned long curMillis = millis();
if ((unsigned long)(curMillis - lastDebounceTime) >= debounceDelay)
{
lastButton1State = checkButtonState(BUTPIN1, button1State, lastButton1State);
lastButton2State = checkButtonState(BUTPIN2, button2State, lastButton2State);
lastButton3State = checkButtonState(BUTPIN3, button3State, lastButton3State);
lastDebounceTime = millis();
}
// Call the current pattern function once updating the leds array
gPatterns[gCurrentPatternNumber]();
gPal = aPal[clickPal];
// if the plasma is running, also run the mouth and eyes functions
if(off == false){
mouth();
eyes();
}
// send the leds array to the strip
FastLED.show();
// insert a delay to keep the framerate reasonable
FastLED.delay(1000 / FRAMES_PER_SECOND);
// perform periodic updates
EVERY_N_MILLISECONDS( 20 ) {
gHue++; // change the base color every 20 ms
}
}
// button and input control functions
int checkButtonState(int button, int bState, int lBState)
{
if ( lBState != bState )
{
// call change function
if(bState == HIGH)
{
buttonHigh(button);
}
} else {
// do other thing
}
return bState;
}
void buttonHigh(int button)
{
if(button == BUTPIN1)
{
bPatClick();
}
if(button == BUTPIN2)
{
bPalDClick();
}
if(button == BUTPIN3)
{
bPalUClick();
}
}
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A) [0]))
void bPalDClick()
{
clickPal--;
if(clickPal < 0)
{
clickPal = ARRAY_SIZE(aPal) - 1;
}
}
void bPalUClick()
{
clickPal++;
if(clickPal > ARRAY_SIZE(aPal) - 1)
{
clickPal = 0;
}
}
void bPatClick()
{
nextPattern();
}
void nextPattern()
{
// add one to the current pattern number and wrap around at the end
gCurrentPatternNumber = (gCurrentPatternNumber + 1) % ARRAY_SIZE( gPatterns );
}
// plasma functions
void addGlitter( fract8 chanceOfGlitter, CRGB::HTMLColorCode ColorGlit )
{
fadeToBlackBy(leds, NUM_LEDS, 20);
if ( random8() < chanceOfGlitter ) {
leds[ random16(NUM_LEDS) ] += ColorGlit;
}
}
void slow_xy()
{
uint8_t scale = 255; // noise zoom factor
for( uint16_t i = 0; i < NUM_LEDS; i++ )
{
uint16_t shift_x = beatsin8(17); // x pos of noise field swings @ 17 bpm
uint16_t shift_y = millis() / 100; // y pos slowly incremented
uint32_t real_x = (x[i] + shift_x) * scale; // calculate coords within noise field
uint32_t real_y = (y[i] + shift_y) * scale; // based on precalc-ed positions
uint8_t noise = inoise16(real_x, real_y, 4223) >> 8; // get noise data and scale down
uint8_t index = noise * 3; // map led color based on noise data
uint8_t bri = noise;
CRGB color = ColorFromPalette( gPal, index, bri);
leds[i] = color;
}
}
void slow_yx()
{
uint8_t scale = 255; // the "zoom factor" for the noise
for (uint16_t i = 0; i < NUM_LEDS; i++) {
uint16_t shift_x = millis() / 10; // x as a function of time
uint16_t shift_y = 0;
uint32_t real_x = (x[i] + shift_x) * scale; // calculate the coordinates within the noise field
uint32_t real_y = (y[i] + shift_y) * scale; // based on the precalculated positions
uint8_t noise = inoise16(real_x, real_y, 4223) >> 8; // get the noise data and scale it down
uint8_t index = noise * 3; // map led color based on noise data
uint8_t bri = noise;
CRGB color = ColorFromPalette( gPal, index, bri);
leds[i] = color;
}
}
void fast_z()
{
uint8_t scale = 255; // the "zoom factor" for the noise
for (uint16_t i = 0; i < NUM_LEDS; i++) {
uint16_t shift_x = 0; // no movement along x and y
uint16_t shift_y = 0;
uint32_t real_x = (x[i] + shift_x) * scale; // calculate the coordinates within the noise field
uint32_t real_y = (y[i] + shift_y) * scale; // based on the precalculated positions
uint32_t real_z = millis() * 20; // increment z linear
uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down
uint8_t index = noise * 3; // map led color based on noise data
uint8_t bri = noise;
CRGB color = ColorFromPalette( gPal, index, bri);
leds[i] = color;
}
}
// non-plasma palette cycles
void mouth()
{
jPuggle(NUM_LEDS, NUM_INT_LEDS);
}
void eyes()
{
rBuggle(NUM_LEDS + NUM_INT_LEDS, NUM_EYE_LEDS);
}
void cFuggle(int startPixel, int pixelCount)
{
fadeToBlackBy( leds + startPixel, pixelCount, 5 );
int pos = random8(pixelCount);
leds[pos] += ColorFromPalette(gPal, gHue, gHue + (30));
}
void sLuggle(int startPixel, int pixelCount)
{
fadeToBlackBy( leds + startPixel, pixelCount, 20 );
int pos = beatsin16(12, 0, pixelCount);
leds[pos + startPixel] += ColorFromPalette(gPal, gHue, gHue + 13);
}
void jPuggle(int startPixel, int pixelCount)
{
fadeToBlackBy( leds + startPixel, pixelCount, 20 );
CRGBPalette16 palette = aPal[0];
for (int i = 0; i < 8; i++) {
leds[(startPixel) + beatsin16( i + 7, 0, pixelCount)] = ColorFromPalette(palette, gHue + (i * 2), gHue + (i * 10));
}
}
void turnOff()
{
off = true;
fadeToBlackBy( leds, NUM_LEDS + NUM_INT_LEDS + NUM_EYE_LEDS, 20 );
byte dothue = 0;
for ( int i = 0; i < 8; i++ ) {
leds[beatsin16(i + 7, 0, NUM_LEDS + NUM_INT_LEDS + NUM_EYE_LEDS)] |= CHSV(dothue, 0, 0);
}
}
void turnOn()
{
off = false;
addGlitter(3, CRGB::DarkBlue);
}
void rBuggle(int startPixel, int endPixel)
{
// built-in rainbow
fill_rainbow( leds + startPixel, endPixel, gHue, 7 );
}
Comments