Created
September 23, 2018 02:44
-
-
Save caitlinsdad/7003e920fec9e5accce2b79f58306414 to your computer and use it in GitHub Desktop.
Circuit Playground Classic Thermometer Scarf
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Adafruit_CircuitPlayground.h> | |
#include <FastLED.h> | |
/* | |
Board is older Adafruit Circuit Playground - Arduino code only | |
Wiring to header may there for some I2C device SCL-SDA-power previous project | |
code may contain reference to 2nd neopixel strand which was not used. | |
This was orginally adapted from some demo code so some functions not used. | |
Probably from here: | |
https://www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/#library | |
The left button is pressed to cycle the animation modes | |
- Sound reactive light scarf | |
- thermometer - you will have to calibrate for accuracy and redo artwork for scales F or C or Kelvin, etc. | |
hold the button till the temp drops back down, it will beep and let go of switch to get it into | |
next mode. Timing is tough to sense switch press while doing neopixelly things... | |
- last mode is fire flame effect animation | |
battery pack takes 3 AAA batteries | |
Hack to change or add the other animations | |
Enjoy! | |
*/ | |
#define LED_PIN 6 //led strand is soldered to pin 6 | |
#define LED_PIN2 10 //led strand is soldered to pin 6 | |
#define NUM_STRIPS 3 | |
#define CP_PIN 17 //circuit playground's neopixels live on pin 17 | |
#define NUM_LEDS 30 // number of LEDs in my strand | |
#define NUM_CP 10 // number of neopixels on the circuit playground | |
#define COLOR_ORDER GRB | |
uint8_t brightness = 150; //led strand brightness control | |
uint8_t xbrightness = 150; //led strand brightness control | |
uint8_t cpbrightness = 60; //circuit playground brightness control | |
int STEPS = 25; //makes the rainbow colors more or less spread out | |
int NUM_MODES = 2; // change this number if you add or subtract modes | |
CRGB leds[NUM_STRIPS][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 170 // val 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_CP + 2) // Allow dot to go slightly off scale | |
#define xTOP (NUM_LEDS + 2) // Allow dot to go slightly off scale | |
#define PEAK_FALL 7 // 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 | |
xpeak = 0, // Used for falling dot | |
xdotCount = 0, // Frame counter for delaying dot-falling speed | |
xvolCount = 0; // Frame counter for storing past volume data | |
int | |
vol[SAMPLES], // Collection of prior volume samples | |
lvl = 12, // val 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 9.75 // movement sensitivity. lower number = less twinklitude | |
float X, Y, Z, T; | |
// 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] = {{255, 20, 0}, // I've set this for pastel twinkles | |
{255, 100, 0}, // Change colors by inputting diferent R, G, B values on these lines | |
{255, 250, 100}, // | |
}; | |
// 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[0], NUM_LEDS).setCorrection( TypicalLEDStrip ); | |
FastLED.addLeds<WS2812B, LED_PIN2, COLOR_ORDER>(leds[1], 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 | |
CircuitPlayground.redLED(HIGH); | |
delay(100); | |
} | |
void loop() { | |
leftButtonPressed = CircuitPlayground.leftButton(); | |
rightButtonPressed = CircuitPlayground.rightButton(); | |
if (leftButtonPressed) { //left button cycles through modes | |
clearpixels(); | |
CircuitPlayground.playTone(500,100); | |
CircuitPlayground.redLED(LOW); | |
delay(100); | |
CircuitPlayground.redLED(HIGH); | |
delay(100); | |
CircuitPlayground.redLED(LOW); | |
delay(100); | |
CircuitPlayground.redLED(HIGH); | |
CircuitPlayground.playTone(600,100); | |
ledMode=ledMode+1; | |
if (ledMode > NUM_MODES){ | |
ledMode=0; | |
CircuitPlayground.redLED(LOW); | |
delay(100); | |
} | |
} | |
if (rightButtonPressed) { // right button turns all leds off | |
ledMode=99; | |
CircuitPlayground.redLED(LOW); | |
} | |
switch (ledMode) { | |
// case 0: motion(); break; | |
// case 0: Strobe(0xff, 0x00, 0x00, 10, 50, 900); break; | |
// Slow: Strobe(0xff, 0x77, 0x00, 10, 100, 1000); | |
// Fast: | |
// case 1: currentPalette = LavaColors_p; rainbow(); break; | |
case 0: soundreactive(); break; | |
case 1: gettemp(); break; | |
case 2: Fire(55,130,50);; break; | |
// case 3: currentPalette = RainbowColors_p; rainbow(); break; | |
// case 4: currentPalette = OceanColors_p; rainbow(); break; | |
// case 5: currentPalette = RainbowStripeColors_p; rainbow(); break; | |
case 99: clearpixels(); break; | |
} | |
} | |
void clearpixels() | |
{ | |
CircuitPlayground.redLED(LOW); | |
CircuitPlayground.clearPixels(); | |
for (int i = 0; i < NUM_LEDS; i++) {leds[0][i] = CRGB::Black; | |
leds[1][i] = CRGB::Black; | |
} | |
for (int i = 0; i < NUM_CP; i++) cp[i] = CRGB::Black; | |
FastLED.show(); | |
CircuitPlayground.redLED(LOW); | |
} | |
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[0][i] = ColorFromPalette( currentPalette, colorIndex, brightness, currentBlending); | |
leds[1][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, xheight; | |
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); | |
xheight = xTOP * (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 | |
if (xheight < 0L) xheight = 0; // Clip output | |
else if (xheight > xTOP) xheight = xTOP; | |
if (xheight > xpeak) xpeak = xheight; // Keep 'peak' dot at top | |
Serial.print("Height: "); | |
Serial.println(height); | |
Serial.print("\t"); | |
Serial.println(xheight); | |
// Color pixels based on rainbow gradient -- led strand | |
for (i=0; i<NUM_LEDS; i++) { | |
if (i >= xheight) { leds[0][i].setRGB( 0, 0, 0); | |
leds[1][i].setRGB( 0, 0, 0); | |
} | |
else {leds[0][i] = CHSV(map(i,0,NUM_LEDS-1,0,255), 255, xbrightness); //constrain colors here by changing HSV values | |
leds[1][i] = CHSV(map(i,0,NUM_LEDS-1,0,255), 255, xbrightness); //constrain colors here by changing HSV values} | |
} | |
// Draw peak dot -- led strand | |
if (xpeak > 0 && xpeak <= NUM_LEDS-1) {leds[0][xpeak] = CHSV(map(xpeak,0,NUM_LEDS-1,0,255), 255, xbrightness); | |
leds[1][xpeak] = CHSV(map(xpeak,0,NUM_LEDS-1,0,255), 255, xbrightness); | |
} | |
} | |
// 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_CP-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; | |
} | |
if (++xdotCount >= PEAK_FALL) { // fall rate | |
if(xpeak > 0) xpeak--; | |
xdotCount = 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 gettemp(){ | |
T = CircuitPlayground.temperatureF()-8; | |
Serial.println(T); | |
int k = map(T,0,120,0,NUM_LEDS); | |
clearpixels(); | |
Serial.println(k); | |
for (int j=0; j<NUM_CP; j++) { | |
cp[j] = CHSV((255,50,0), 255, xbrightness); | |
FastLED.show(); | |
delay(90); | |
} | |
for (int i=0; i<k; i++) { | |
leds[0][i] = CHSV((255,50,0), 255, xbrightness); | |
FastLED.show(); | |
delay(90); | |
} | |
delay(3500); | |
for (int m=0; m<k; m++) { | |
leds[0][k-1-m] = CRGB::Black; | |
FastLED.show(); | |
delay(100); | |
} | |
for ( int l=0; l<NUM_CP; l++) { | |
cp[NUM_CP-1-l] = CRGB::Black; | |
FastLED.show(); | |
delay(100); | |
} | |
delay(1000); | |
} | |
//========================================================================= | |
//========================================================================= | |
void Fire(int Cooling, int Sparking, int SpeedDelay) { | |
static byte heat[NUM_LEDS]; | |
int cooldown; | |
for (int j=0; j<NUM_CP; j++) { | |
cp[j] = CHSV((255,50,0), 255, xbrightness); | |
FastLED.show(); | |
} | |
// Step 1. Cool down every cell a little | |
for( int i = 0; i < NUM_LEDS; i++) { | |
cooldown = random(0, ((Cooling * 10) / NUM_LEDS) + 2); | |
if(cooldown>heat[i]) { | |
heat[i]=0; | |
} else { | |
heat[i]=heat[i]-cooldown; | |
} | |
} | |
// 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' near the bottom | |
if( random(255) < Sparking ) { | |
int y = random(7); | |
heat[y] = heat[y] + random(160,255); | |
//heat[y] = random(160,255); | |
} | |
// Step 4. Convert heat to LED colors | |
for( int j = 0; j < NUM_LEDS; j++) { | |
setPixelHeatColor(j, heat[j] ); | |
} | |
showStrip(); | |
delay(SpeedDelay); | |
} | |
void setPixelHeatColor (int Pixel, byte temperature) { | |
// Scale 'heat' down from 0-255 to 0-191 | |
byte t192 = round((temperature/255.0)*191); | |
// calculate ramp up from | |
byte heatramp = t192 & 0x3F; // 0..63 | |
heatramp <<= 2; // scale up to 0..252 | |
// figure out which third of the spectrum we're in: | |
if( t192 > 0x80) { // hottest | |
setPixel(Pixel, 255, 255, heatramp); | |
} else if( t192 > 0x40 ) { // middle | |
setPixel(Pixel, 255, heatramp, 0); | |
} else { // coolest | |
setPixel(Pixel, heatramp, 0, 0); | |
} | |
} | |
//========================================================================= | |
//========================================================================= | |
void motion() { | |
CircuitPlayground.redLED(HIGH); | |
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(4, 9); // first number is 'wait' delay, shorter num == shorter twinkle | |
flashRandom(5, 8); // second number is how many neopixels to simultaneously light up | |
flashRandom(4, 9); | |
} | |
} | |
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[0][j].r = r; | |
leds[0][j].g = g; | |
leds[0][j].b = b; | |
leds[1][j].r = r; | |
leds[1][j].g = g; | |
leds[1][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[1][j].r = r; | |
leds[1][j].g = g; | |
leds[1][j].b = b; | |
leds[0][j].r = r; | |
leds[0][j].g = g; | |
leds[0][j].b = b; | |
FastLED.show(); | |
CircuitPlayground.setPixelColor(j, r, g, b); | |
delay(wait); | |
} | |
} | |
// LEDs will be off when done (they are faded to 0) | |
} | |
//====================================== | |
void Strobe(byte red, byte green, byte blue, int StrobeCount, int FlashDelay, int EndPause){ | |
for(int j = 0; j < StrobeCount; j++) { | |
setAll(red,green,blue); | |
FastLED.show(); | |
delay(FlashDelay); | |
setAll(0,0,0); | |
FastLED.show(); | |
delay(FlashDelay); | |
} | |
delay(EndPause); | |
} | |
void showStrip() { | |
#ifdef ADAFRUIT_NEOPIXEL_H | |
// NeoPixel | |
strip.show(); | |
#endif | |
#ifndef ADAFRUIT_NEOPIXEL_H | |
// FastLED | |
FastLED.show(); | |
#endif | |
} | |
void setPixel(int Pixel, byte red, byte green, byte blue) { | |
#ifdef ADAFRUIT_NEOPIXEL_H | |
// NeoPixel | |
strip.setPixelColor(leds[0][Pixel], strip.Color(red, green, blue)); | |
strip.setPixelColor(leds[1][Pixel], strip.Color(red, green, blue)); | |
#endif | |
#ifndef ADAFRUIT_NEOPIXEL_H | |
// FastLED | |
leds[0][Pixel].r = red; | |
leds[0][Pixel].g = green; | |
leds[0][Pixel].b = blue; | |
leds[1][Pixel].r = red; | |
leds[1][Pixel].g = green; | |
leds[1][Pixel].b = blue; | |
#endif | |
} | |
void setAll(byte red, byte green, byte blue) { | |
for(int i = 0; i < NUM_LEDS; i++ ) { | |
// FastLED | |
leds[0][i].r = red; | |
leds[0][i].g = green; | |
leds[0][i].b = blue; | |
leds[1][i].r = red; | |
leds[1][i].g = green; | |
leds[1][i].b = blue; | |
} | |
FastLED.show(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Original project:
https://www.instructables.com/id/Neopixel-Giant-Thermometer-Scarf/