Before You Start
If this is your first foray into the world of arduino-based microcontrollers, you'll need to install some software first. Head over to the Arduino page of the Circuit Playground Express guide for detailed installation and setup instructions.
You'll only need to do all this once, so be a little patient if it seems like a lot!
FastLED Library
You will also need to install the FastLED library in Arduino (Sketch > Include Library > Manage Libraries...
)
One other note: if you're using FastLED with Circuit Playground, be sure to #include
the Circuit Playground library FIRST and the FastLED library second, or you may run into problems.
Upload Code
Once you've got everything installed and your computer can talk to the Circuit Playground, it's time to upload the code.
Plug your Circuit Playground into your computer and select the Adafruit Circuit Playground Express under Tools > Boards
. Then select the Circuit Playground Exoress as the Port.
Copy and paste this code into a new Arduino window and click "upload".
#include <Adafruit_CircuitPlayground.h> #include <FastLED.h> #define LED_PIN A1 //led strand is soldered to pin 6 #define CP_PIN 8 //circuit playground's neopixels live on pin 8 #define NUM_LEDS 11 // number of LEDs in my strand #define NUM_CP 10 // number of neopixels on the circuit playground #define COLOR_ORDER GRB uint8_t brightness = 255; //led strand brightness control uint8_t cpbrightness = 40; //circuit playground brightness control int STEPS = 25; //makes the rainbow colors more or less spread out int NUM_MODES = 5; // change this number if you add or subtract modes CRGB leds[NUM_LEDS]; //I've set up different arrays for the neopixel strand and the circuit playground CRGB cp[NUM_CP]; // so that we can control the brightness separately CRGBPalette16 currentPalette; TBlendType currentBlending; int ledMode = 0; //Initial mode bool leftButtonPressed; bool rightButtonPressed; // SOUND REACTIVE SETUP -------------- #define MIC_PIN A4 // Analog port for microphone #define DC_OFFSET 0 // DC offset in mic signal - if unusure, leave 0 // I calculated this value by serialprintln lots of mic values #define NOISE 200 // Noise/hum/interference in mic signal and increased value until it went quiet #define SAMPLES 60 // Length of buffer for dynamic level adjustment #define TOP (NUM_LEDS + 2) // Allow dot to go slightly off scale #define PEAK_FALL 10 // Rate of peak falling dot byte peak = 0, // Used for falling dot dotCount = 0, // Frame counter for delaying dot-falling speed volCount = 0; // Frame counter for storing past volume data int vol[SAMPLES], // Collection of prior volume samples lvl = 10, // Current audio level, change this number to adjust sensitivity minLvlAvg = 0, // For dynamic adjustment of graph low & high maxLvlAvg = 512; // MOTION CONTROL SETUP---------- #define MOVE_THRESHOLD 10 // movement sensitivity. lower number = less twinklitude float X, Y, Z; // Here is where you can put in your favorite colors that will appear! // just add new {nnn, nnn, nnn}, lines. They will be picked out randomly // R G B uint8_t myFavoriteColors[][3] = {{200, 100, 200}, // I've set this for pastel twinkles {200, 200, 100}, // Change colors by inputting diferent R, G, B values on these lines {100, 200, 200}, // }; // don't edit the line below #define FAVCOLORS sizeof(myFavoriteColors) / 3 void setup() { Serial.begin(57600); CircuitPlayground.begin(); FastLED.addLeds<WS2812B, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip ); FastLED.addLeds<WS2812B, CP_PIN, COLOR_ORDER>(cp, 10).setCorrection( TypicalLEDStrip ); currentBlending = LINEARBLEND; set_max_power_in_volts_and_milliamps(5, 500); // FastLED 2.1 Power management set at 5V, 500mA } void loop() { leftButtonPressed = CircuitPlayground.leftButton(); rightButtonPressed = CircuitPlayground.rightButton(); if (leftButtonPressed) { //left button cycles through modes clearpixels(); ledMode=ledMode+1; delay(300); if (ledMode > NUM_MODES){ ledMode=0; } } if (rightButtonPressed) { // right button turns all leds off ledMode=99; } switch (ledMode) { case 0: currentPalette = RainbowColors_p; rainbow(); break; case 1: motion(); break; case 2: soundreactive(); break; case 3: currentPalette = OceanColors_p; rainbow(); break; case 4: currentPalette = LavaColors_p; rainbow(); break; case 5: currentPalette = RainbowStripeColors_p; rainbow(); break; case 99: clearpixels(); break; } } void clearpixels() { CircuitPlayground.clearPixels(); for (int i = 0; i < NUM_LEDS; i++) leds[i] = CRGB::Black; for (int i = 0; i < NUM_CP; i++) cp[i] = CRGB::Black; FastLED.show(); } void rainbow() { static uint8_t startIndex = 0; startIndex = startIndex + 1; /* motion speed */ FillLEDsFromPaletteColors( startIndex); FastLED.show(); FastLED.delay(10);} //this bit is in every palette mode, needs to be in there just once void FillLEDsFromPaletteColors( uint8_t colorIndex) { for (int i = 0; i < NUM_LEDS; i++) leds[i] = ColorFromPalette( currentPalette, colorIndex, brightness, currentBlending); for (int i = 0; i < NUM_CP; i++) cp[i] = ColorFromPalette( currentPalette, colorIndex, cpbrightness, currentBlending); colorIndex += STEPS; } void soundreactive() { uint8_t i; uint16_t minLvl, maxLvl; int n, height; n = analogRead(MIC_PIN); // Raw reading from mic n = abs(n - 512 - DC_OFFSET); // Center on zero n = (n <= NOISE) ? 0 : (n - NOISE); // Remove noise/hum lvl = ((lvl * 7) + n) >> 3; // "Dampened" reading (else looks twitchy) // Calculate bar height based on dynamic min/max levels (fixed point): height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg); if (height < 0L) height = 0; // Clip output else if (height > TOP) height = TOP; if (height > peak) peak = height; // Keep 'peak' dot at top // Color pixels based on rainbow gradient -- led strand for (i=0; i<NUM_LEDS; i++) { if (i >= height) leds[i].setRGB( 0, 0,0); else leds[i] = CHSV(map(i,0,NUM_LEDS-1,0,255), 255, brightness); //constrain colors here by changing HSV values } // Draw peak dot -- led strand if (peak > 0 && peak <= NUM_LEDS-1) leds[peak] = CHSV(map(peak,0,NUM_LEDS-1,0,255), 255, brightness); // Color pixels based on rainbow gradient -- circuit playground for (i=0; i<NUM_CP; i++) { if (i >= height) cp[i].setRGB( 0, 0,0); else cp[i] = CHSV(map(i,0,NUM_CP-1,0,255), 255, cpbrightness); //constrain colors here by changing HSV values } // Draw peak dot -- circuit playground if (peak > 0 && peak <= NUM_CP-1) cp[peak] = CHSV(map(peak,0,NUM_LEDS-1,0,255), 255, cpbrightness); // Every few frames, make the peak pixel drop by 1: if (++dotCount >= PEAK_FALL) { // fall rate if(peak > 0) peak--; dotCount = 0; } vol[volCount] = n; // Save sample for dynamic leveling if (++volCount >= SAMPLES) volCount = 0; // Advance/rollover sample counter // Get volume range of prior frames minLvl = maxLvl = vol[0]; for (i=1; i<SAMPLES; i++) { if (vol[i] < minLvl) minLvl = vol[i]; else if (vol[i] > maxLvl) maxLvl = vol[i]; } // minLvl and maxLvl indicate the volume range over prior frames, used // for vertically scaling the output graph (so it looks interesting // regardless of volume level). If they're too close together though // (e.g. at very low volume levels) the graph becomes super coarse // and 'jumpy'...so keep some minimum distance between them (this // also lets the graph go to zero when no sound is playing): if((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP; minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6; // Dampen min/max levels maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6; // (fake rolling average) show_at_max_brightness_for_power(); // Power managed FastLED display Serial.println(LEDS.getFPS()); } // fastbracelet() void motion() { X = CircuitPlayground.motionX(); Y = CircuitPlayground.motionY(); Z = CircuitPlayground.motionZ(); // Get the magnitude (length) of the 3 axis vector // http://en.wikipedia.org/wiki/Euclidean_vector#Length double storedVector = X*X; storedVector += Y*Y; storedVector += Z*Z; storedVector = sqrt(storedVector); Serial.print("Len: "); Serial.println(storedVector); // wait a bit delay(100); // get new data! X = CircuitPlayground.motionX(); Y = CircuitPlayground.motionY(); Z = CircuitPlayground.motionZ(); double newVector = X*X; newVector += Y*Y; newVector += Z*Z; newVector = sqrt(newVector); Serial.print("New Len: "); Serial.println(newVector); // are we moving if (abs(10*newVector - 10*storedVector) > MOVE_THRESHOLD) { Serial.println("Twinkle!"); flashRandom(5, 1); // first number is 'wait' delay, shorter num == shorter twinkle flashRandom(5, 3); // second number is how many neopixels to simultaneously light up flashRandom(5, 2); } } void flashRandom(int wait, uint8_t howmany) { for(uint16_t i=0; i<howmany; i++) { // pick a random favorite color! int c = random(FAVCOLORS); int red = myFavoriteColors[c][0]; int green = myFavoriteColors[c][1]; int blue = myFavoriteColors[c][2]; // get a random pixel from the list int j = random(NUM_LEDS); //Serial.print("Lighting up "); Serial.println(j); // now we will 'fade' it in 5 steps for (int x=0; x < 5; x++) { int r = red * (x+1); r /= 5; int g = green * (x+1); g /= 5; int b = blue * (x+1); b /= 5; leds[j].r = r; leds[j].g = g; leds[j].b = b; FastLED.show(); CircuitPlayground.setPixelColor(j, r, g, b); delay(wait); } // & fade out in 5 steps for (int x=5; x >= 0; x--) { int r = red * x; r /= 5; int g = green * x; g /= 5; int b = blue * x; b /= 5; leds[j].r = r; leds[j].g = g; leds[j].b = b; FastLED.show(); CircuitPlayground.setPixelColor(j, r, g, b); delay(wait); } } // LEDs will be off when done (they are faded to 0) }
If all goes well, the lights on the Circuit Playground will come on. Press the right side button and the lights will go off. Press the left side button to toggle between modes:
- Rainbow Colors
- Motion Reactive
- Sound Reactive
- Ocean Colors
- Lava Colors
- Rainbow Stripe Colors
Press the button once to enter Motion Reactive mode. Jiggle the Circuit Playground around to watch the lights dance.
Press the button again to enter Sound Reactive mode. Make some noise!
Add your own modes or customize the modes that are already there.
Page last edited March 08, 2024
Text editor powered by tinymce.