Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Run Multiple Neopixel WS2812 Patterns Simultaneously
- Modified from Bill Earl's Adafruit Multitasking Tutorial (which is excellent!)
- Includes a Candy Cane Pattern that reverses, Runs a Controlled Number of Repetitions,
- then Changes Colors, then Resets to start over again
- */
- /* Here is a video of this program in action - https://www.youtube.com/watch?v=uFzPAEqjF38 */
- #include <Adafruit_NeoPixel.h>
- // Pattern types supported:
- enum pattern { NONE, CANDY_CANE, RAINBOW_CYCLE, THEATER_CHASE, COLOR_WIPE, SCANNER, FADE };
- // Patern directions supported:
- enum direction { FORWARD, REVERSE };
- // NeoPattern Class - Derived from the Adafruit_NeoPixel class
- // PUBLIC Variables and Functions are available everywhere - otherwise, ERRORS!
- class NeoPatterns : public Adafruit_NeoPixel
- {
- public:
- // Member Variables:
- pattern ActivePattern; // which pattern is running
- direction Direction; // direction to run the pattern
- unsigned long Interval; // milliseconds between updates - essentially, the FRAME RATE
- unsigned long lastUpdate; // Last Update of position
- uint32_t Color1, Color2; // What Colors are in use
- uint16_t TotalSteps; // Total Number of Steps in the Pattern
- uint16_t Index; // Current Step Within the Pattern - Which FRAME
- uint32_t Stripe1, Stripe2; // What Colors are in use for Candy Cane Patterns
- int Width; // Width for Candy Cane Stripes in Pixels
- int Offset; // Offset for Pattern Start
- int Sets; // Number of Repetitions of This Pattern
- int SetCount; // Count Repetitions of Current Pattern Set
- void (*OnComplete)(); // Callback on Completion of Pattern
- // Constructor - Calls base-class Constructor to initialize strip
- NeoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)())
- : Adafruit_NeoPixel(pixels, pin, type)
- {
- OnComplete = callback;
- }
- // Update the pattern
- void Update()
- {
- if ((millis() - lastUpdate) > Interval) // Time to Update?
- {
- lastUpdate = millis();
- switch (ActivePattern)
- {
- case CANDY_CANE:
- CandyCaneUpdate();
- break;
- case RAINBOW_CYCLE:
- RainbowCycleUpdate();
- break;
- case THEATER_CHASE:
- TheaterChaseUpdate();
- break;
- case COLOR_WIPE:
- ColorWipeUpdate();
- break;
- case SCANNER:
- ScannerUpdate();
- break;
- case FADE:
- FadeUpdate();
- break;
- default:
- break;
- }
- }
- }
- // Increment the Index Variable and Reset at the End of the Pattern (Number of Steps)
- void Increment()
- {
- if (Direction == FORWARD)
- {
- Index++; // Increment the INDEX
- if (Index >= TotalSteps)
- {
- Index = 0;
- if (OnComplete != NULL)
- {
- OnComplete(); // Call the Completion Callback
- }
- }
- }
- else // Direction == REVERSE
- {
- --Index; // Decrement the INDEX
- if (Index <= 0)
- {
- Index = TotalSteps - 1;
- if (OnComplete != NULL)
- {
- OnComplete(); // Call the Completion Callback
- }
- }
- }
- }
- // Reverse the Pattern Direction
- void Reverse()
- {
- if (Direction == FORWARD)
- {
- Direction = REVERSE;
- Index = TotalSteps - 1;
- }
- else
- {
- Direction = FORWARD;
- Index = 0;
- }
- }
- // Initialize the CandyCane Pattern
- /* CandyCane CHASING COLOR STRIPES
- // Create scrolling RED & WHITE - candy cane - stripes.
- // Try adjusting the width in pixels for various results.
- // Value "sets" should evenly divide into strand length
- // EXAMPLE USAGE: CandyCane(30,8,50); //30 sets, 8 pixels wide, 50us delay
- */
- #define Brightness 2 //Set brightness to 1/2
- #define Full (255/Brightness)
- void CandyCane(int sets, int width, uint8_t interval, uint32_t stripe1, uint32_t stripe2, direction dir = FORWARD)
- {
- ActivePattern = CANDY_CANE; // Names of this Pattern for other functions
- Interval = interval; // Speed of the Pattern
- TotalSteps = numPixels(); // Number of steps for this Pattern
- Stripe1 = stripe1; // Stripe Color1
- Stripe2 = stripe2; // Stripe Color2
- Index = 0;
- Direction = dir;
- Offset = 0; // Offset to start anywhere
- Sets = sets; // Number of sets for the pattern
- Width = width; // Width of the alternating Stripes
- }
- void CandyCaneUpdate()
- {
- int L;
- // Loop for Setting Pixel L Color;
- for (int i = 0; i < numPixels(); i++) {
- L = numPixels() - i - 1; // Which Pixel to Update;
- if ( ((Index + i) % ((Width * 2)) ) < (Width) ) {
- //setPixelColor(L, Full, 0, 0); // SET PIXEL L COLOR TO RED
- setPixelColor(L, Stripe1); // SET PIXEL L COLOR TO RED
- } else {
- //setPixelColor(L, Full, Full, Full); // SET PIXEL L COLOR TO WHITE
- setPixelColor(L, Stripe2); // SET PIXEL L COLOR TO WHITE
- }
- }; // End of Setting Pixel Color;
- show();
- // delay(50); // For Debugging;
- if (Index == (numPixels() - 1)) {
- if (Direction == FORWARD) {
- Direction = REVERSE;
- } else if (Direction == REVERSE) {
- Direction = FORWARD;
- }
- }
- Increment(); // Increment the Index for the Next Frame;
- }; // End of Function;
- // Initialize for a RainbowCycle
- void RainbowCycle(uint8_t interval, direction dir = FORWARD)
- {
- ActivePattern = RAINBOW_CYCLE;
- Interval = interval;
- TotalSteps = 255;
- Index = 0;
- Direction = dir;
- }
- // Update the Rainbow Cycle Pattern
- void RainbowCycleUpdate()
- {
- for (int i = 0; i < numPixels(); i++)
- {
- setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index) & 255));
- }
- show();
- Increment();
- }
- // Initialize for a Theater Chase
- void TheaterChase(uint32_t color1, uint32_t color2, uint8_t interval, direction dir = FORWARD)
- {
- ActivePattern = THEATER_CHASE;
- Interval = interval;
- TotalSteps = numPixels();
- Color1 = color1;
- Color2 = color2;
- Index = 0;
- Direction = dir;
- }
- // Update the Theater Chase Pattern
- void TheaterChaseUpdate()
- {
- for (int i = 0; i < numPixels(); i++)
- {
- if ((i + Index) % 3 == 0)
- {
- setPixelColor(i, Color1);
- }
- else
- {
- setPixelColor(i, Color2);
- }
- }
- show();
- Increment();
- }
- // Initialize for a ColorWipe
- void ColorWipe(uint32_t color, uint8_t interval, direction dir = FORWARD)
- {
- ActivePattern = COLOR_WIPE;
- Interval = interval;
- TotalSteps = numPixels();
- Color1 = color;
- Index = 0;
- Direction = dir;
- }
- // Update the Color Wipe Pattern
- void ColorWipeUpdate()
- {
- setPixelColor(Index, Color1);
- show();
- Increment();
- }
- // Initialize for a SCANNNER
- void Scanner(uint32_t color1, uint8_t interval)
- {
- ActivePattern = SCANNER;
- Interval = interval;
- TotalSteps = (numPixels() - 1) * 2;
- Color1 = color1;
- Index = 0;
- }
- // Update the Scanner Pattern
- void ScannerUpdate()
- {
- for (int i = 0; i < numPixels(); i++)
- {
- if (i == Index) // Scan Pixel to the right
- {
- setPixelColor(i, Color1);
- }
- else if (i == TotalSteps - Index) // Scan Pixel to the left
- {
- setPixelColor(i, Color1);
- }
- else // Fading tail
- {
- setPixelColor(i, DimColor(getPixelColor(i)));
- }
- }
- show();
- Increment();
- }
- // Initialize for a Fade
- void Fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval, direction dir = FORWARD)
- {
- ActivePattern = FADE;
- Interval = interval;
- TotalSteps = steps;
- Color1 = color1;
- Color2 = color2;
- Index = 0;
- Direction = dir;
- }
- // Update the Fade Pattern
- void FadeUpdate()
- {
- // Calculate linear interpolation between Color1 and Color2
- // Optimise order of operations to minimize truncation error
- uint8_t red = ((Red(Color1) * (TotalSteps - Index)) + (Red(Color2) * Index)) / TotalSteps;
- uint8_t green = ((Green(Color1) * (TotalSteps - Index)) + (Green(Color2) * Index)) / TotalSteps;
- uint8_t blue = ((Blue(Color1) * (TotalSteps - Index)) + (Blue(Color2) * Index)) / TotalSteps;
- ColorSet(Color(red, green, blue));
- show();
- Increment();
- }
- // Calculate 50% dimmed version of a color (Used by ScannerUpdate)
- uint32_t DimColor(uint32_t color)
- {
- // Shift R, G and B components one bit to the right
- uint32_t dimColor = Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1);
- return dimColor;
- }
- // Set all pixels to a color (synchronously)
- void ColorSet(uint32_t color)
- {
- for (int i = 0; i < numPixels(); i++)
- {
- setPixelColor(i, color);
- }
- show();
- }
- // Returns the Red component of a 32-bit color
- uint8_t Red(uint32_t color)
- {
- return (color >> 16) & 0xFF;
- }
- // Returns the Green component of a 32-bit color
- uint8_t Green(uint32_t color)
- {
- return (color >> 8) & 0xFF;
- }
- // Returns the Blue component of a 32-bit color
- uint8_t Blue(uint32_t color)
- {
- return color & 0xFF;
- }
- // Input a value 0 to 255 to get a color value.
- // The colours are a transition r - g - b - back to r.
- uint32_t Wheel(byte WheelPos)
- {
- WheelPos = 255 - WheelPos;
- if (WheelPos < 85)
- {
- return Color(255 - WheelPos * 3, 0, WheelPos * 3);
- }
- else if (WheelPos < 170)
- {
- WheelPos -= 85;
- return Color(0, WheelPos * 3, 255 - WheelPos * 3);
- }
- else
- {
- WheelPos -= 170;
- return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
- }
- }
- };
- // Define some NeoPatterns used for any of the three Strings
- // as well as some completion routines
- // NeoPatterns Instantiate String by Name(number of LEDs, LED pin, Serial OUT COLOR Order & Frequency, Something Else);
- NeoPatterns String1(50, 6, NEO_GRB + NEO_KHZ800, &String1Complete);
- NeoPatterns String2(50, 5, NEO_GRB + NEO_KHZ800, &String2Complete);
- NeoPatterns String3(50, 11, NEO_GRB + NEO_KHZ800, &String3Complete);
- /* STARTUP ROUTINES GO HERE */
- // Initialize everything and prepare to start
- void setup()
- {
- Serial.begin(115200);
- pinMode(8, INPUT_PULLUP); // Setup Button #1
- pinMode(9, INPUT_PULLUP); // Setup Button #2
- // Initialize all the pixelStrips
- String1.begin();
- String2.begin();
- String3.begin();
- // Kick off a pattern for each String
- String1.TheaterChase(String1.Color(255, 255, 0), String1.Color(0, 0, 50), 100);
- String2.RainbowCycle(3);
- String2.Color1 = String1.Color1;
- // String3.Scanner(String1.Color(255, 0, 0), 55);
- // String3.TheaterChase(String3.Color(255, 255, 0), String3.Color(0, 0, 50), 100);
- String3.CandyCane(5, 5, 100, String3.Color(127, 0, 0), String3.Color(127, 127, 127));
- }
- /* MAIN PROGRAM LOOP - RUN ENDLESSLY */
- // Main loop
- void loop()
- {
- // Update the Strings on Every Loop.
- String1.Update();
- String2.Update();
- String3.Update();
- // Switch patterns on a button press:
- if (digitalRead(8) == LOW) // Button #1 Pressed;
- {
- // Switch String1 to FASE pattern
- String1.ActivePattern = FADE;
- String1.Interval = 20;
- // Speed up the rainbow on String2
- String2.Interval = 0;
- // Set String3 to all red
- // String3.ColorSet(String3.Color(255, 0, 0));
- }
- else if (digitalRead(9) == LOW) // Button #2 Pressed;
- {
- // Switch to alternating color wipes on Strings1 and 2
- String1.ActivePattern = COLOR_WIPE;
- String2.ActivePattern = COLOR_WIPE;
- String2.TotalSteps = String2.numPixels();
- // And update String3
- // String3.Update();
- }
- else // Nothing Pressed - Back to normal operation
- {
- // Restore all pattern parameters to normal values
- String1.ActivePattern = THEATER_CHASE;
- String1.Interval = 100;
- String2.ActivePattern = RAINBOW_CYCLE;
- String2.TotalSteps = 255;
- String2.Interval = min(10, String2.Interval);
- // And update String3;
- // String3.ActivePattern = CANDY_CANE;
- // String3.Update();
- }
- }
- //------------------------------------------------------------
- // Completion Routines - get called on completion of a pattern
- //------------------------------------------------------------
- // String1 Completion Callback
- void String1Complete()
- {
- if (digitalRead(9) == LOW) // Button #2 pressed
- {
- // Alternate color-wipe patterns with String2
- String2.Interval = 40;
- String1.Color1 = String1.Wheel(random(255));
- String1.Interval = 20000;
- }
- else // Return to normal
- {
- String1.Reverse();
- }
- }
- // Ring 2 Completion Callback
- void String2Complete()
- {
- if (digitalRead(9) == LOW) // Button #2 pressed
- {
- // Alternate color-wipe patterns with String1
- String1.Interval = 20;
- String2.Color1 = String2.Wheel(random(255));
- String2.Interval = 20000;
- }
- else // Return to normal
- {
- String2.RainbowCycle(random(0, 10));
- }
- }
- // String3 Completion Callback
- void String3Complete()
- {
- if (String3.SetCount < String3.Sets) {
- // Set a New Random Color for the next Set
- String3.Stripe1 = String3.Wheel(random(255));
- String3.Stripe2 = (0, 0, 0);
- String3.SetCount ++;
- } else {
- // Reset to Default Candy Cane Colors
- String3.SetCount = 0;
- String3.CandyCane(5, 5, 100, String3.Color(127, 0, 0), String3.Color(127, 127, 127)); // Reset Back to Red/White;
- }
- }
- // END OF PROGRAM;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement