Skip to content

Instantly share code, notes, and snippets.

@marmilicious
Last active October 22, 2018 21:25
Show Gist options
  • Save marmilicious/a27843f79a1e40b4f3c2a0bfc4d1249a to your computer and use it in GitHub Desktop.
Save marmilicious/a27843f79a1e40b4f3c2a0bfc4d1249a to your computer and use it in GitHub Desktop.
//***************************************************************
// Example for Michael Sime with button added.
//
// Each time button is pressed the next palette is selected.
// Open the serial monitor to see some feedback.
// Pixel zero will also flash bright purple each time the button
// is pressed as a visual feedback.
//
// Search for "BUTTON STUFF" to find the various button releated
// lines of code that were put in place.
// And also search for "Serial.print" to find the various print
// lines that were added to provide feedback.
//
//***************************************************************
#include "FastLED.h"
#define DATA_PIN 11
#define CLK_PIN 13
#define LED_TYPE LPD8806
#define COLOR_ORDER GRB
#define BRIGHTNESS 255
#define VOLTS 5
#define MAX_MA 1000
#define NUM_LEDS 32
//BUTTON STUFF
// JChristensen's Button Library from https://github.com/JChristensen/Button
#include "Button.h" // Button library
const int buttonPin = 4; // Digital pin used for debounced pushbutton
Button myButton(buttonPin, true, true, 50); // Declare the button
//---------------------------------------------------------------
CRGBArray<NUM_LEDS> leds;
// Overall twinkle speed.
// 0 (VERY slow) to 8 (VERY fast).
#define TWINKLE_SPEED 5
// Overall twinkle density.
// 0 (NONE lit) to 16 (ALL lit at once).
uint8_t gDensity = 0;
// How often to change color palettes.
#define SECONDS_PER_PALETTE 10
// Also: toward the bottom of the file is an array
// called "ActivePaletteList" which controls which color
// palettes are used; you can add or remove color palettes
// from there freely.
// Background color for 'unlit' pixels
// Can be set to CRGB::Black if desired.
CRGB gBackgroundColor = CRGB::Black;
// Example of dim incandescent fairy light background color
//CRGB gBackgroundColor = CRGB(CRGB::FairyLight).nscale8_video(16);
// If AUTO_SELECT_BACKGROUND_COLOR is set to 1,
// then for any palette where the first two entries
// are the same, a dimmed version of that color will
// automatically be used as the background color.
#define AUTO_SELECT_BACKGROUND_COLOR 0
// If COOL_LIKE_INCANDESCENT is set to 1, colors will
// fade out slighted 'reddened', similar to how
// incandescent bulbs change color as they get dim down.
#define COOL_LIKE_INCANDESCENT 0
CRGBPalette16 gCurrentPalette;
CRGBPalette16 gTargetPalette;
//---------------------------------------------------------------
void setup() {
Serial.begin(115200); // Allows serial monitor output (check baud rate)
delay(3000); // 3 second delay for recovery
FastLED.setMaxPowerInVoltsAndMilliamps( VOLTS, MAX_MA);
//FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
FastLED.setBrightness(BRIGHTNESS);
chooseNextColorPalette(gTargetPalette);
Serial.println("Setup done.");
Serial.println(" ");
}
//BUTTON STUFF
//-------function to read the button and do something--------
void readbutton() {
myButton.read();
if(myButton.wasPressed()) {
Serial.println("Button pressed! Picking new palette... ");
chooseNextColorPalette( gTargetPalette );
//Flash pixel zero purple as a visual that button was pressed.
leds[0] = CHSV(192,255,255); //Set first pixel color
FastLED.show(); //Update display
delay(100); //Very short pause so we can see leds[0] flash
}
}//end_readbutton
//---------------------------------------------------------------
void loop()
{
//BUTTON STUFF
/* Not using this timer any more. Instead readbutton will handle this:
*
*
EVERY_N_SECONDS( SECONDS_PER_PALETTE )
{
Serial.println("Picking new palette... ");
chooseNextColorPalette( gTargetPalette );
}
*/
EVERY_N_MILLISECONDS( 5 ) {
nblendPaletteTowardPalette( gCurrentPalette, gTargetPalette, 254); //Increased to 254 and
nblendPaletteTowardPalette( gCurrentPalette, gTargetPalette, 254); //dublicate line for faster change
nblendPaletteTowardPalette( gCurrentPalette, gTargetPalette, 254);
}
drawTwinkles( leds);
FastLED.setBrightness(255);
//FastLED.delay(2);
gDensity = 4;
FastLED.show();
//BUTTON STUFF
readbutton(); // check for button press
}//end_main_loop
// This function loops over each pixel, calculates the
// adjusted 'clock' that this pixel should use, and calls
// "CalculateOneTwinkle" on each pixel. It then displays
// either the twinkle color of the background color,
// whichever is brighter.
void drawTwinkles( CRGBSet& L)
{
// "PRNG16" is the pseudorandom number generator
// It MUST be reset to the same starting value each time
// this function is called, so that the sequence of 'random'
// numbers that it generates is (paradoxically) stable.
uint16_t PRNG16 = 11337;
uint32_t clock32 = millis();
// Set up the background color, "bg".
// if AUTO_SELECT_BACKGROUND_COLOR == 1, and the first two colors of
// the current palette are identical, then a deeply faded version of
// that color is used for the background color
CRGB bg;
if( (AUTO_SELECT_BACKGROUND_COLOR == 1) &&
(gCurrentPalette[0] == gCurrentPalette[1] )) {
bg = gCurrentPalette[0];
uint8_t bglight = bg.getAverageLight();
if( bglight > 64) {
bg.nscale8_video( 16); // very bright, so scale to 1/16th
} else if( bglight > 16) {
bg.nscale8_video( 64); // not that bright, so scale to 1/4th
} else {
bg.nscale8_video( 86); // dim, scale to 1/3rd.
}
} else {
bg = gBackgroundColor; // just use the explicitly defined background color
}
uint8_t backgroundBrightness = bg.getAverageLight();
for( CRGB& pixel: L) {
PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
uint16_t myclockoffset16= PRNG16; // use that number as clock offset
PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
// use that number as clock speed adjustment factor (in 8ths, from 8/8ths to 23/8ths)
uint8_t myspeedmultiplierQ5_3 = ((((PRNG16 & 0xFF)>>3) + (PRNG16 & 0x1F)) & 0x1F) + 0x10;
//uint32_t myclock30 = (uint32_t)((clock32 * myspeedmultiplierQ5_3) >> 3) + myclockoffset16;
uint32_t myclock30 = (uint32_t)((((uint32_t)(clock32) + myclockoffset16) * myspeedmultiplierQ5_3) >> 3);
uint8_t myunique8 = PRNG16 >> 8; // get 'salt' value for this pixel
// We now have the adjusted 'clock' for this pixel, now we call
// the function that computes what color the pixel should be based
// on the "brightness = f( time )" idea.
CRGB c = computeOneTwinkle( myclock30, myunique8);
uint8_t cbright = c.getAverageLight();
int16_t deltabright = cbright - backgroundBrightness;
if( deltabright >= 32 || (!bg)) {
// If the new pixel is significantly brighter than the background color,
// use the new color.
pixel = c;
} else if( deltabright > 0 ) {
// If the new pixel is just slightly brighter than the background color,
// mix a blend of the new color and the background color
pixel = blend( bg, c, deltabright * 8);
} else {
// if the new pixel is not at all brighter than the background color,
// just use the background color.
pixel = bg;
}
}
}
// This function takes a time in pseudo-milliseconds,
// figures out brightness = f( time ), and also hue = f( time )
// The 'low digits' of the millisecond time are used as
// input to the brightness wave function.
// The 'high digits' are used to select a color, so that the color
// does not change over the course of the fade-in, fade-out
// of one cycle of the brightness wave function.
// The 'high digits' are also used to determine whether this pixel
// should light at all during this cycle, based on the TWINKLE_DENSITY.
CRGB computeOneTwinkle( uint32_t ms, uint8_t salt)
{
uint16_t ticks = ms >> (8-TWINKLE_SPEED);
uint8_t fastcycle8 = ticks;
uint8_t slowcycle8 = (ticks >> 8) + salt;
uint8_t bright = 0;
if( ((slowcycle8 & 0x0F)) < gDensity) {
bright = attackDecayWave8( fastcycle8);
}
uint8_t hue = (slowcycle8 * 16) + salt;
CRGB c = ColorFromPalette( gCurrentPalette, hue, bright, NOBLEND);
if( COOL_LIKE_INCANDESCENT == 1 ) {
coolLikeIncandescent( c, fastcycle8);
}
return c;
}
// This function is like 'triwave8', which produces a
// symmetrical up-and-down triangle sawtooth waveform, except that this
// function produces a triangle wave with a faster attack and a slower decay:
//
// / \
// / \
// / \
// / \
//
uint8_t attackDecayWave8( uint8_t i)
{
if( i < 86) {
return i * 3;
} else {
i -= 86;
return 255 - (i + (i/2));
}
}
// This function takes a pixel, and if its in the 'fading down'
// part of the cycle, it adjusts the color a little bit like the
// way that incandescent bulbs fade toward 'red' as they dim.
void coolLikeIncandescent( CRGB& c, uint8_t phase)
{
if( phase < 128) return;
uint8_t cooling = (phase - 128) >> 4;
c.g = qsub8( c.g, cooling);
c.b = qsub8( c.b, cooling * 2);
}
// A mostly red palette with green accents and white trim.
// "CRGB::Gray" is used as white to keep the brightness more uniform.
const TProgmemRGBPalette16 RedGreenWhite_p FL_PROGMEM =
{ CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red,
CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red,
CRGB::Red, CRGB::Red, CRGB::Gray, CRGB::Gray,
CRGB::Green, CRGB::Green, CRGB::Green, CRGB::Green };
// A mostly (dark) green palette with red berries.
#define Holly_Green 0x00580c
#define Holly_Red 0xB00402
//CRGB gBackgroundColor = CRGB(CRGB::FairyLight).nscale8_video(16);
const TProgmemRGBPalette16 Holly_p FL_PROGMEM =
{ CRGB:: Black, CRGB:: Black, Holly_Green, Holly_Green,
Holly_Green, Holly_Green, Holly_Green, Holly_Green,
Holly_Green, Holly_Green, Holly_Green, Holly_Green,
Holly_Green, Holly_Green, Holly_Green, Holly_Red
};
// A red and white striped palette
// "CRGB::Gray" is used as white to keep the brightness more uniform.
const TProgmemRGBPalette16 RedWhite_p FL_PROGMEM =
{ CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red,
CRGB::Gray, CRGB::Gray, CRGB::Gray, CRGB::Gray,
CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red,
CRGB::Gray, CRGB::Gray, CRGB::Gray, CRGB::Gray };
// A mostly blue palette with white accents.
// "CRGB::Gray" is used as white to keep the brightness more uniform.
const TProgmemRGBPalette16 BlueWhite_p FL_PROGMEM =
{ CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue,
CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue,
CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue,
CRGB::Blue, CRGB::Gray, CRGB::Gray, CRGB::Gray };
// A pure "fairy light" palette with some brightness variations
#define HALFFAIRY ((CRGB::FairyLight & 0xFEFEFE) / 2)
#define QUARTERFAIRY ((CRGB::FairyLight & 0xFCFCFC) / 4)
const TProgmemRGBPalette16 FairyLight_p FL_PROGMEM =
{ CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight,
HALFFAIRY, HALFFAIRY, CRGB::FairyLight, CRGB::FairyLight,
QUARTERFAIRY, QUARTERFAIRY, CRGB::FairyLight, CRGB::FairyLight,
CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight };
// A palette of soft snowflakes with the occasional bright one
const TProgmemRGBPalette16 Snow_p FL_PROGMEM =
{ 0x304048, 0x304048, 0x304048, 0x304048,
0x304048, 0x304048, 0x304048, 0x304048,
0x304048, 0x304048, 0x304048, 0x304048,
0x304048, 0x304048, 0x304048, 0xE0F0FF };
// A palette reminiscent of large 'old-school' C9-size tree lights
// in the five classic colors: red, orange, green, blue, and white.
#define C9_Red 0xB80400
#define C9_Orange 0x902C02
#define C9_Green 0x046002
#define C9_Blue 0x070758
#define C9_White 0x606820
const TProgmemRGBPalette16 RetroC9_p FL_PROGMEM =
{ C9_Red, C9_Orange, C9_Red, C9_Orange,
C9_Orange, C9_Red, C9_Orange, C9_Red,
C9_Green, C9_Green, C9_Green, C9_Green,
C9_Blue, C9_Blue, C9_Blue,
C9_White
};
// A cold, icy pale blue palette
#define Ice_Blue1 0x0C1040
#define Ice_Blue2 0x182080
#define Ice_Blue3 0x5080C0
const TProgmemRGBPalette16 Ice_p FL_PROGMEM =
{
Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1,
Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1,
Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1,
Ice_Blue2, Ice_Blue2, Ice_Blue2, Ice_Blue3
};
// Add or remove palette names from this list to control which color
// palettes are used, and in what order.
const TProgmemRGBPalette16* ActivePaletteList[] = {
// &RetroC9_p,
&BlueWhite_p,
// &RainbowColors_p,
&FairyLight_p,
// &RedGreenWhite_p,
// &PartyColors_p,
// &RedWhite_p,
&Snow_p,
&Holly_p,
// &Ice_p
};
// Advance to the next color palette in the list (above).
void chooseNextColorPalette( CRGBPalette16& pal)
{
const uint8_t numberOfPalettes = sizeof(ActivePaletteList) / sizeof(ActivePaletteList[0]);
static uint8_t whichPalette = -1;
whichPalette = addmod8( whichPalette, 1, numberOfPalettes);
pal = *(ActivePaletteList[whichPalette]);
Serial.print(" Number of palettes to choose from: "); Serial.println(numberOfPalettes);
Serial.print(" Current palette choice: "); Serial.println(whichPalette);
Serial.println(" ");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment