Files

leds.ino
#include "FastLED.h" #include <Wire.h> // Number of RGB LEDs in the strand #define NUM_LEDS 60 #define BRIGHTNESS 64 #define LED_TYPE WS2811 #define COLOR_ORDER GRB // Define the array of leds CRGB leds[NUM_LEDS]; // Arduino pin used for Data #define PIN 6 CRGBPalette16 currentPalette; TBlendType currentBlending; uint8_t startIndex = 0; #define UPDATES_PER_SECOND 100 extern CRGBPalette16 myRedWhiteBluePalette; extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM; uint8_t starthue = 0; void ChangePalettePeriodically(); void FillLEDsFromPaletteColors(uint8_t colorIndex); void SetupBlackAndWhiteStripedPalette(); void SetupPurpleAndGreenPalette(); void SetupTotallyRandomPalette(); const int SLAVE_ADDRESS = 0x06; enum State { STATE_OK = 0, STATE_UNKNOWN_COMMAND, STATE_UNKNOWN_MODE, STATE_WRONG_BYTECOUNT }; int i2c_state = STATE_OK; enum Mode { MODE_CYCLE, // 0 MODE_GROWING_BARS, MODE_FADE, MODE_CHASE, MODE_CHASE_MULTI, MODE_PERIODIC_PALETTE, // 5 MODE_RAINBOW, MODE_RAINBOW_GLITTER, MODE_CYLON, MODE_BOUNCE, MODE_CONFETTI, // 10 MODE_SINELON, MODE_BPM, MODE_JUGGLE, MODE_FIRE, MODE_LAST }; uint8_t BeatsPerMinute = 62; Mode mode = MODE_PERIODIC_PALETTE; Mode old_mode = static_cast<Mode>(-1); void receiveData(int byteCount) { int c = Wire.read(); switch (c) { case 0: // Read status if (byteCount != 1) { while (--byteCount) Wire.read(); i2c_state = STATE_WRONG_BYTECOUNT; } break; case 1: // Set mode if (byteCount != 2) { while (--byteCount) Wire.read(); i2c_state = STATE_WRONG_BYTECOUNT; return; } mode = static_cast<Mode>(Wire.read()); i2c_state = STATE_OK; if (mode >= MODE_LAST) i2c_state = STATE_UNKNOWN_MODE; break; default: while (--byteCount) Wire.read(); i2c_state = STATE_UNKNOWN_COMMAND; break; } } void sendData() { Wire.write(i2c_state); } void setup() { FastLED.addLeds<WS2811, PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip); FastLED.setBrightness(BRIGHTNESS); currentPalette = RainbowColors_p; currentBlending = LINEARBLEND; Serial.begin(57600); Serial.println("LED Controller v 0.1"); Wire.begin(SLAVE_ADDRESS); Wire.onReceive(receiveData); Wire.onRequest(sendData); } const static CRGB chase_colours[] = { CRGB::Yellow, CRGB::Green, CRGB::HotPink, CRGB::Blue, CRGB::Red, CRGB::White }; void fadeall() { for (int i = 0; i < NUM_LEDS; i++) leds[i].nscale8(250); } void addGlitter(fract8 chanceOfGlitter) { if (random8() < chanceOfGlitter) { leds[random16(NUM_LEDS)] += CRGB::White; } } const int BUF_SIZE = 20; int index = 0; char buffer[BUF_SIZE]; int current_led = 0; int current_loop = 0; bool growing = true; // Fire2012 by Mark Kriegsman, July 2012 // as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY //// // This basic one-dimensional 'fire' simulation works roughly as follows: // There's a underlying array of 'heat' cells, that model the temperature // at each point along the line. Every cycle through the simulation, // four steps are performed: // 1) All cells cool down a little bit, losing heat to the air // 2) The heat from each cell drifts 'up' and diffuses a little // 3) Sometimes randomly new 'sparks' of heat are added at the bottom // 4) The heat from each cell is rendered as a color into the leds array // The heat-to-color mapping uses a black-body radiation approximation. // // Temperature is in arbitrary units from 0 (cold black) to 255 (white hot). // // This simulation scales it self a bit depending on NUM_LEDS; it should look // "OK" on anywhere from 20 to 100 LEDs without too much tweaking. // // I recommend running this simulation at anywhere from 30-100 frames per second, // meaning an interframe delay of about 10-35 milliseconds. // // Looks best on a high-density LED setup (60+ pixels/meter). // // // There are two main parameters you can play with to control the look and // feel of your fire: COOLING (used in step 1 above), and SPARKING (used // in step 3 above). // // COOLING: How much does the air cool as it rises? // Less cooling = taller flames. More cooling = shorter flames. // Default 50, suggested range 20-100 #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 120 bool gReverseDirection = false; void Fire2012() { // Array of temperature readings at each simulation cell static byte 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 * 10) / 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++) { CRGB color = HeatColor( heat[j]); int pixelnumber; if( gReverseDirection ) { pixelnumber = (NUM_LEDS-1) - j; } else { pixelnumber = j; } leds[pixelnumber] = color; } } #define CHECK_MODE() \ if (mode != old_mode) \ { \ old_mode = mode; \ current_led = current_loop = 0; \ break; \ } void loop() { if (Serial.available()) { // Command from PC char c = Serial.read(); if ((c == '\r') || (c == '\n')) { buffer[index] = 0; index = 0; mode = static_cast<Mode>(atoi(buffer)); memset(leds, 0, NUM_LEDS * 3); current_led = 0; current_loop = 0; Serial.print("Mode "); Serial.println(mode); } else { if (index >= BUF_SIZE) { Serial.println("MOTOR: Error: Line too long"); index = 0; return; } buffer[index++] = c; } } switch (mode) { case MODE_CYCLE: // one at a time if (current_loop >= 3) current_loop = 0; if (current_led >= NUM_LEDS) { current_led = 0; ++current_loop; } memset(leds, 0, NUM_LEDS * 3); switch(current_loop) { case 0: leds[current_led].r = 255; break; case 1: leds[current_led].g = 255; break; case 2: leds[current_led].b = 255; break; } ++current_led; break; case MODE_GROWING_BARS: // growing/receeding bars if (current_led >= NUM_LEDS) { current_led = 0; ++current_loop; } if (growing) { if (current_loop >= 3) { current_loop = 0; growing = false; break; } switch (current_loop) { case 0: leds[current_led].r = 255; break; case 1: leds[current_led].g = 255; break; case 2: leds[current_led].b = 255; break; } } else { if (current_loop >= 3) { current_loop = 0; growing = true; break; } switch (current_loop) { case 0: leds[NUM_LEDS-1-current_led].r = 0; break; case 1: leds[NUM_LEDS-1-current_led].g = 0; break; case 2: leds[NUM_LEDS-1-current_led].b = 0; break; } } ++current_led; break; case MODE_FADE: // Fade in/fade out for (int j = 0; j < 3; j++ ) { memset(leds, 0, NUM_LEDS * 3); for(int k = 0; k < 256; k++) { for(int i = 0; i < NUM_LEDS; i++ ) { switch(j) { case 0: leds[i].r = k; break; case 1: leds[i].g = k; break; case 2: leds[i].b = k; break; } } FastLED.show(); delay(3); CHECK_MODE(); } for(int k = 255; k >= 0; k--) { for(int i = 0; i < NUM_LEDS; i++ ) { switch(j) { case 0: leds[i].r = k; break; case 1: leds[i].g = k; break; case 2: leds[i].b = k; break; } } FastLED.show(); delay(3); CHECK_MODE(); } } break; case MODE_CHASE: memset(leds, 0, NUM_LEDS * 3); for (size_t c = 0; c < sizeof(chase_colours)/sizeof(chase_colours[0]); ++c) { for (int i = 0; i < NUM_LEDS; ++i) { if (i) leds[i-1] = CRGB::Black; leds[i] = chase_colours[c]; FastLED.show(); delay(50); CHECK_MODE(); } leds[NUM_LEDS-1] = CRGB::Black; } break; case MODE_BOUNCE: for (size_t c = 0; c < sizeof(chase_colours)/sizeof(chase_colours[0]); ++c) { memset(leds, 0, NUM_LEDS * 3); FastLED.show(); for (int i = 0; i < NUM_LEDS; ++i) { if (i) leds[i-1] = CRGB::Black; leds[i] = chase_colours[c]; FastLED.show(); delay(50); CHECK_MODE(); } leds[NUM_LEDS-1] = CRGB::Black; FastLED.show(); delay(50); for (int i = 0; i < NUM_LEDS; ++i) { if (i) leds[NUM_LEDS-i] = CRGB::Black; leds[NUM_LEDS-1-i] = chase_colours[c]; FastLED.show(); delay(50); CHECK_MODE(); } leds[NUM_LEDS-1] = CRGB::Black; } break; case MODE_CHASE_MULTI: memset(leds, 0, NUM_LEDS * 3); for (size_t c = 0; c < sizeof(chase_colours)/sizeof(chase_colours[0]); ++c) { const int N = 4; for (int j = 0; j < N; ++j) { memset(leds, 0, NUM_LEDS * 3); for (int i = 0; i < NUM_LEDS; ++i) { if (((i+j) % N) == 0) leds[i] = chase_colours[c]; } FastLED.show(); delay(100); CHECK_MODE(); } leds[NUM_LEDS-1] = CRGB::Black; } break; case MODE_PERIODIC_PALETTE: ChangePalettePeriodically(); startIndex = startIndex + 1; /* motion speed */ FillLEDsFromPaletteColors(startIndex); break; case MODE_RAINBOW: fill_rainbow(leds, NUM_LEDS, --starthue, 20); break; case MODE_RAINBOW_GLITTER: fill_rainbow(leds, NUM_LEDS, --starthue, 20); addGlitter(80); break; case MODE_CYLON: if (current_led >= NUM_LEDS) current_led = 0; // Set the i'th led to red leds[current_led] = CHSV(starthue++, 255, 255); // Show the leds FastLED.show(); fadeall(); // Wait a little bit before we loop around and do it again FastLED.delay(10); ++current_led; break; case MODE_CONFETTI: // random colored speckles that blink in and fade smoothly { fadeToBlackBy(leds, NUM_LEDS, 10); int pos = random16(NUM_LEDS); leds[pos] += CHSV(starthue + random8(64), 200, 255); } break; case MODE_SINELON: // a colored dot sweeping back and forth, with fading trails { fadeToBlackBy(leds, NUM_LEDS, 20); int pos = beatsin16(13, 0, NUM_LEDS); leds[pos] += CHSV(starthue, 255, 192); } break; case MODE_BPM: // colored stripes pulsing at a defined Beats-Per-Minute (BPM) { uint8_t beat = beatsin8(BeatsPerMinute, 64, 255); for (int i = 0; i < NUM_LEDS; i++) leds[i] = ColorFromPalette(PartyColors_p, starthue+(i*2), beat-starthue+(i*10)); } break; case MODE_JUGGLE: // eight colored dots, weaving in and out of sync with each other { fadeToBlackBy(leds, NUM_LEDS, 20); byte dothue = 0; for(int i = 0; i < 8; i++) { leds[beatsin16(i+7,0,NUM_LEDS)] |= CHSV(dothue, 200, 255); dothue += 32; } } break; case MODE_FIRE: Fire2012(); break; default: memset(leds, 0, NUM_LEDS * 3); FastLED.show(); break; } FastLED.show(); FastLED.delay(1000 / UPDATES_PER_SECOND); EVERY_N_MILLISECONDS(20) { ++starthue; } } void FillLEDsFromPaletteColors(uint8_t colorIndex) { uint8_t brightness = 255; for(int i = 0; i < NUM_LEDS; i++) { leds[i] = ColorFromPalette(currentPalette, colorIndex, brightness, currentBlending); colorIndex += 3; } } // There are several different palettes of colors demonstrated here. // // FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p, // OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p. // // Additionally, you can manually define your own color palettes, or you can write // code that creates color palettes on the fly. All are shown here. void ChangePalettePeriodically() { // Change palette every 8 seconds const int secondHand = millis()/8000; static int lastSecond = 999; if(lastSecond != secondHand) { lastSecond = secondHand; const int pal = random(11); switch (pal) { case 0: currentPalette = RainbowColors_p; currentBlending = LINEARBLEND; break; case 1: currentPalette = RainbowStripeColors_p; currentBlending = NOBLEND; break; case 2: currentPalette = RainbowStripeColors_p; currentBlending = LINEARBLEND; break; case 3: SetupPurpleAndGreenPalette(); currentBlending = LINEARBLEND; break; case 4: SetupTotallyRandomPalette(); currentBlending = LINEARBLEND; break; case 5: SetupBlackAndWhiteStripedPalette(); currentBlending = NOBLEND; break; case 6: SetupBlackAndWhiteStripedPalette(); currentBlending = LINEARBLEND; break; case 7: currentPalette = CloudColors_p; currentBlending = LINEARBLEND; break; case 8: currentPalette = PartyColors_p; currentBlending = LINEARBLEND; break; case 9: currentPalette = myRedWhiteBluePalette_p; currentBlending = NOBLEND; break; case 10: currentPalette = myRedWhiteBluePalette_p; currentBlending = LINEARBLEND; break; } } } // This function fills the palette with totally random colors. void SetupTotallyRandomPalette() { for(int i = 0; i < 16; i++) { currentPalette[i] = CHSV(random8(), 255, random8()); } } // This function sets up a palette of black and white stripes, // using code. Since the palette is effectively an array of // sixteen CRGB colors, the various fill_* functions can be used // to set them up. void SetupBlackAndWhiteStripedPalette() { // 'black out' all 16 palette entries... fill_solid(currentPalette, 16, CRGB::Black); // and set every fourth one to white. currentPalette[0] = CRGB::White; currentPalette[4] = CRGB::White; currentPalette[8] = CRGB::White; currentPalette[12] = CRGB::White; } // This function sets up a palette of purple and green stripes. void SetupPurpleAndGreenPalette() { CRGB purple = CHSV(HUE_PURPLE, 255, 255); CRGB green = CHSV(HUE_GREEN, 255, 255); CRGB black = CRGB::Black; currentPalette = CRGBPalette16( green, green, black, black, purple, purple, black, black, green, green, black, black, purple, purple, black, black ); } // This example shows how to set up a static color palette // which is stored in PROGMEM (flash), which is almost always more // plentiful than RAM. A static PROGMEM palette like this // takes up 64 bytes of flash. const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM = { CRGB::Red, CRGB::Gray, // 'white' is too bright compared to red and blue CRGB::Blue, CRGB::Black, CRGB::Red, CRGB::Gray, CRGB::Blue, CRGB::Black, CRGB::Red, CRGB::Red, CRGB::Gray, CRGB::Gray, CRGB::Blue, CRGB::Blue, CRGB::Black, CRGB::Black };
Report a bug