Last active
January 19, 2016 01:46
-
-
Save kylemarsh/2b6257281d6c0dfc31d8 to your computer and use it in GitHub Desktop.
ShiftBrite Playground -- Different sketches that I've come up with while working on a shiftbrite project
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 "shiftbrite.h" // See https://github.com/kylemarsh/particle_shiftbrite | |
#define latchpin D0 // replace with pin you use for the latch | |
#define numleds 4 // Number of LEDs in your chain | |
typedef struct { | |
uint16_t red; | |
uint16_t green; | |
uint16_t blue; | |
} rgb; | |
rgb pixels[numleds]; | |
rgb hsv2rgb(double hue, double sat, double value); | |
ShiftBrite sb(numleds, latchpin); | |
void setup() { | |
sb.begin(); | |
sb.show(); | |
} | |
void loop() { | |
colorwheel_wave(); | |
//colorwheel(); | |
} | |
void colorwheel_wave(void) { | |
for (int hue = 0; hue < 360; ++hue) { | |
for (int i = 0; i < numleds; ++i) { | |
rgb color = hsv2rgb((double)((hue + 15*i) % 360), 1.0, 1.0); | |
sb.setPixelRGB(i, color.red, color.green, color.blue); | |
} | |
sb.show(); | |
delay(10); | |
} | |
} | |
void colorwheel(void) { | |
for (int hue = 0; hue < 360; ++hue) { | |
rgb color = hsv2rgb((double)hue, 1.0, 1.0); | |
sb.allOn(color.red, color.green, color.blue); | |
delay(10); | |
} | |
} | |
rgb hsv2rgb(double hue, double sat, double value) { | |
double sextant, chroma, q, t, ff; | |
double red, blue, green; | |
long i; | |
rgb out; | |
if(sat <= 0.0) { | |
red = value; | |
green = value; | |
blue = value; | |
return out; | |
} | |
sextant = hue; | |
if(sextant >= 360.0) sextant = 0.0; | |
sextant /= 60.0; | |
i = (long)sextant; | |
ff = sextant - i; | |
chroma = value * (1.0 - sat); | |
q = value * (1.0 - (sat * ff)); | |
t = value * (1.0 - (sat * (1.0 - ff))); | |
switch(i) { | |
case 0: | |
red = value; | |
green = t; | |
blue = chroma; | |
break; | |
case 1: | |
red = q; | |
green = value; | |
blue = chroma; | |
break; | |
case 2: | |
red = chroma; | |
green = value; | |
blue = t; | |
break; | |
case 3: | |
red = chroma; | |
green = q; | |
blue = value; | |
break; | |
case 4: | |
red = t; | |
green = chroma; | |
blue = value; | |
break; | |
case 5: | |
default: | |
red = value; | |
green = chroma; | |
blue = q; | |
break; | |
} | |
out.red = (uint32_t)(red * 1023); | |
out.green = (uint32_t)(green * 1023); | |
out.blue = (uint32_t)(blue * 1023); | |
return out; | |
} |
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
#ifndef my_structs_h | |
#define my_structs_h | |
typedef struct { | |
int16_t red; | |
int16_t green; | |
int16_t blue; | |
} rgb; | |
#endif // my_structs_h |
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
#define RegLatchPin D0 // replace with pin you use for the latch | |
#define numleds 4 // Number of LEDs in your chain | |
#define numcolors 9 // Number of colors to cycle through (adjust if you change the ColorWheel array) | |
#define train 1 // If 1 colors will cycle down through the chain. If 0 the whole chain will be the same color. | |
typedef union | |
{ | |
uint32_t value; | |
struct // Current control and clock mode registers | |
{ | |
unsigned greenDotCorrect:7; | |
unsigned clockMode:2; | |
unsigned :1; | |
unsigned redDotCorrect:7; | |
unsigned :3; | |
unsigned blueDotCorrect:7; | |
}; | |
struct // PWM registers and address bit | |
{ | |
unsigned green:10; | |
unsigned red:10; | |
unsigned blue:10; | |
unsigned command:1; | |
}; | |
} ShiftBritePacket; | |
void TransmitSerial(ShiftBritePacket packet); | |
void TransmitSPI(ShiftBritePacket packet); | |
ShiftBritePacket colorPacket(unsigned int red, unsigned int green, unsigned int blue); | |
int pos = 0; | |
ShiftBritePacket ColorWheel[numcolors]; | |
void setup() { | |
pinMode(RegLatchPin, OUTPUT); | |
digitalWrite(RegLatchPin, LOW); | |
Serial.begin(9600); // We can talk Serial over USB and SPI over pins A2-A5 at the same time. | |
// ShiftBrites are driven by the Allegro A6281 | |
// Datasheet for A6281 can be found here: https://www.pololu.com/file/download/allegroA6281.pdf?file_id=0J225 | |
// Particle Core's SPI library uses the following pins | |
// A2: SS (You can change this when invoking SPI.begin() but we're not using it in this sketch anyway) | |
// A3: SCK - Clock | |
// A4: MISO - Master in, slave out (receiving data from a downstream device) (we don't use this) | |
// A5: MOSI - Master out, slave in (sending data to a downstream device) | |
// The Allegro A6281 has a 32bit shift register and uses the following pinout: | |
// DI - Data In - Data received from upstream device (the bit to shift in on the clock's next rising edge) | |
// LI - Latch In - Pulse the latch high after last bit has been shifted in to "save" the shift registers | |
// EI - Enable In - Hold low to enable the LEDs. Hold high to disable the LEDs. | |
// CI - Clock In - Clock signal from upstream. | |
// Each input has a corresponding output that gets propagated through the chip to the next chip; | |
// DO is the oldest bit that was shifted into the shift registries, rather than the current value of DI | |
// These inputs map to the SPI outputs like so: | |
// SCK --> CI | |
// MISO --> DI | |
// We will be manually controlling LI (latch) and EI (simply connect to GND) | |
SPI.begin(); | |
SPI.setBitOrder(MSBFIRST); | |
SPI.setClockSpeed(8, MHZ); // Datasheet indicates max clock of 5 MHz, I think. Mine seem to work up to 8 MHz | |
SPI.setDataMode(SPI_MODE1); // Data Mode is an implementation-level detail of SPI defining the particular timing of signals. A6281 uses mode 1 | |
/* Cycle through Primary & Secondary colors plus a dim white */ | |
ColorWheel[0] = colorPacket( 0, 0, 0); // Off | |
ColorWheel[1] = colorPacket(1023, 0, 0); // Red | |
ColorWheel[2] = colorPacket( 0, 1023, 0); // Green | |
ColorWheel[3] = colorPacket( 0, 0, 1023); // Bue | |
ColorWheel[4] = colorPacket( 0, 1023, 1023); // Cyan | |
ColorWheel[5] = colorPacket(1023, 1023, 0); // Yellow | |
ColorWheel[6] = colorPacket(1023, 0, 1023); // Magenta | |
ColorWheel[7] = colorPacket(1023, 1023, 1023); // White | |
ColorWheel[8] = colorPacket(127, 127, 127); // Dim White | |
} | |
void loop() { | |
for (int i = 0; i < numleds; ++i) { | |
int x = train ? i : 0; | |
TransmitSerial(ColorWheel[(pos + x) % numcolors]); | |
TransmitSPI(ColorWheel[(pos + x) % numcolors]); | |
} | |
latch(); | |
pos = (pos + 1) % numcolors; | |
delay(1000); | |
} | |
void TransmitSerial(ShiftBritePacket packet) { | |
uint32_t data = packet.value; | |
Serial.printf("pos = %d\n", pos); | |
Serial.printf("Data Received: %x\n", data); | |
Serial.println("Bytes:"); | |
Serial.printf(" 3: %x\n", (byte)(data >> 24 & 0xFF)); | |
Serial.printf(" 2: %x\n", (byte)(data >> 16 & 0xFF)); | |
Serial.printf(" 1: %x\n", (byte)(data >> 8 & 0xFF)); | |
Serial.printf(" 0: %x\n", (byte)(data >> 0 & 0xFF)); | |
} | |
void TransmitSPI(ShiftBritePacket packet) { | |
uint32_t data = packet.value; | |
SPI.transfer((byte)(data >> 24 & 0xFF)); | |
SPI.transfer((byte)(data >> 16 & 0xFF)); | |
SPI.transfer((byte)(data >> 8 & 0xFF)); | |
SPI.transfer((byte)(data >> 0 & 0xFF)); | |
} | |
void latch() { | |
digitalWrite(RegLatchPin, HIGH); | |
digitalWrite(RegLatchPin, LOW); | |
} | |
ShiftBritePacket colorPacket(unsigned int red, unsigned int green, unsigned int blue) | |
{ | |
//Make a packet and initialize all of the bits to zero. | |
ShiftBritePacket shiftbrite_packet = {value:0}; | |
shiftbrite_packet.red = red; | |
shiftbrite_packet.green = green; | |
shiftbrite_packet.blue = blue; | |
return shiftbrite_packet; | |
} |
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 "ticker.h" | |
Ticker::Ticker(void (*func)(Ticker *t, uint16_t), int num_targets, int speed_adjust, int offset) : | |
tick_func(func), num_targets(num_targets), speed_adjust(speed_adjust), | |
offset(offset), targets(NULL) | |
{ | |
if ((targets = (rgb *)malloc(num_targets * 6))) { | |
memset(targets, 0, num_targets * 6); | |
} | |
} | |
Ticker::~Ticker() | |
{ | |
if (targets) free(targets); | |
} | |
void Ticker::Tick(uint16_t tick) | |
{ | |
this->tick_func(this, tick); | |
} |
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 "application.h" | |
#include "my_structs.h" | |
#ifndef Ticker_h | |
#define Ticker_h | |
class Ticker | |
{ | |
public: | |
Ticker(void (*func)(Ticker *t, uint16_t), int num_targets, int speed_adjust, int offset); | |
~Ticker(); | |
int | |
num_targets, | |
speed_adjust, | |
offset; | |
rgb current; | |
rgb *targets; | |
void Tick(uint16_t tick); | |
private: | |
void (*tick_func)(Ticker *t, uint16_t tick); | |
}; | |
#endif // Ticker_h |
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
/* | |
* WIP preparing for Galaxy Topper firmware. | |
* Uses ShiftBrite library to drive a string of NUMLEDS ShiftBrite pixels. | |
* Uses Ticker class to decouple behavior of each pixel from overall driving | |
* code. | |
* | |
* To control a pixel, create a new Ticker object with the desired | |
* configuration and put it into the Tickers array at the pixel's address. | |
* | |
* Each time Ticker.Tick() is called the Ticker calls the function passed in | |
* as tick_func: void tick_func(Ticker *t, uint16_t tick) which will operate | |
* on the Ticker object that it is passed. The updated RGB values are then | |
* stored in Ticker.current | |
* | |
* When writing a tick function pay careful attention to the number of | |
* "target" rgb values the ticker has -- the number of targets the tick | |
* function requires should be passed into the Ticker's constructor, which | |
* will allocate space for the required target rgb values. | |
* | |
* TO FLASH THIS TO A CORE: | |
* particle flash corename ticking.ino shiftbrite/shiftbrite.* ticker.* my_structs.h | |
*/ | |
#include "shiftbrite.h" | |
#include "ticker.h" | |
#include "math.h" // only used to get pow(...) for our skew(...) function | |
/* Constants */ | |
#define LATCHPIN D0 // replace with pin you use for the latch | |
#define NUMLEDS 6 // Number of LEDs in your chain | |
#define FPS 100 // number of times per second to update shiftbrites | |
#define TPS 100 // ticks per second | |
/* Predeclarations */ | |
// Necessary to avoid confusing particle's preprocessor | |
// see https://docs.particle.io/reference/firmware/core/#preprocessor | |
void colorwheel_tick(Ticker *t, uint16_t tick); | |
void cycling_tick(Ticker *t, uint16_t tick); | |
void fading_cycling_tick(Ticker *t, uint16_t tick); | |
void targeted_tick(Ticker *t, uint16_t tick); | |
rgb hsv2rgb(double hue, double sat, double value); | |
/* Define Objects */ | |
ShiftBrite sb(NUMLEDS, LATCHPIN); | |
Ticker Tickers[NUMLEDS] = { | |
// Careful with the second argument -- it allocates memory for the | |
// Ticker's targets, so make sure you give it at least as many targets | |
// as the tick_function uses. | |
/* | |
Ticker(&targeted_tick, 3, 0, 20), | |
Ticker(&targeted_tick, 3, 0, 20), | |
Ticker(&targeted_tick, 3, 0, 20), | |
Ticker(&targeted_tick, 3, 0, 20), | |
Ticker(&targeted_tick, 3, 0, 20), | |
Ticker(&targeted_tick, 3, 0, 20), | |
*/ | |
Ticker(&colorwheel_tick, 0, 0, 0), | |
Ticker(&colorwheel_tick, 0, 0, 15), | |
Ticker(&colorwheel_tick, 0, 0, 30), | |
Ticker(&colorwheel_tick, 0, 0, 45), | |
Ticker(&colorwheel_tick, 0, 0, 60), | |
Ticker(&colorwheel_tick, 0, 0, 75), | |
/* | |
Ticker(&cycling_tick, 8, 0, 0), | |
Ticker(&cycling_tick, 8, 0, 0), | |
Ticker(&cycling_tick, 8, 0, 0), | |
Ticker(&cycling_tick, 8, 0, 0), | |
Ticker(&cycling_tick, 8, 0, 0), | |
Ticker(&cycling_tick, 8, 0, 0), | |
Ticker(&fading_cycling_tick, 8, 0, 0), | |
Ticker(&fading_cycling_tick, 8, 0, 0), | |
Ticker(&fading_cycling_tick, 8, 0, 0), | |
Ticker(&fading_cycling_tick, 8, 0, 0), | |
Ticker(&fading_cycling_tick, 8, 0, 0), | |
Ticker(&fading_cycling_tick, 8, 0, 0), | |
*/ | |
}; | |
/* Timing */ | |
uint16_t frame_delay = 1000 / FPS; | |
uint16_t tick_delay = 1000 / TPS; | |
uint16_t tick = 0; | |
uint32_t last_tick, last_frame = 0; | |
void setup() | |
{ | |
// Initialize shiftbrite | |
sb.begin(); | |
sb.show(); | |
// Initialize tickers | |
for (int i = 0; i < NUMLEDS; ++i) { | |
// Targeted ticker targets | |
//Tickers[i].targets[1] = {red: 0, green: 0, blue: 511}; | |
//Tickers[i].targets[2] = {red: 1023, green: 1023, blue: 1023}; | |
// Cycling ticker targets | |
Tickers[i].targets[0] = {red: 0, green: 0, blue: 0}; | |
Tickers[i].targets[1] = {red: 1023, green: 0, blue: 0}; | |
Tickers[i].targets[2] = {red: 0, green: 1023, blue: 0}; | |
Tickers[i].targets[3] = {red: 0, green: 0, blue: 1023}; | |
Tickers[i].targets[4] = {red: 1023, green: 1023, blue: 0}; | |
Tickers[i].targets[5] = {red: 0, green: 1023, blue: 1023}; | |
Tickers[i].targets[6] = {red: 1023, green: 0, blue: 1023}; | |
Tickers[i].targets[7] = {red: 1023, green: 1023, blue: 1023}; | |
} | |
} | |
void loop() | |
{ | |
uint32_t now = millis(); | |
// Is it time to do another tick? | |
if (now - last_tick > tick_delay) { | |
last_tick = millis(); | |
for(int i = 0; i < NUMLEDS; ++i) { | |
Tickers[i].Tick(tick); | |
rgb color = Tickers[i].current; | |
sb.setPixelRGB(i, color.red, color.green, color.blue); | |
} | |
++tick; | |
} | |
// Is it time to refresh our shiftbrites? | |
if (millis() - last_frame > frame_delay) { | |
last_frame = millis(); | |
sb.show(); | |
} | |
} | |
/********************* | |
* TICKER FUNCTIONS * | |
*********************/ | |
/* | |
* Cycles around the color wheel by using tick to compute the hue (value and | |
* saturation are held constant at 1). | |
* | |
* Ticker's speed_adjust is used to slow the cycle by powers of 2 | |
* | |
* Ticker's offset is used to set the color *ahead* of the tick's base hue. | |
* This can be used to sync multiple colorwheel_tick Tickers into a ribbon. | |
* | |
* This tick function does not use any target colors. | |
*/ | |
void colorwheel_tick(Ticker *t, uint16_t tick) | |
{ | |
int16_t hue = (tick >> t->speed_adjust) % 360; | |
t->current = hsv2rgb((double)((hue + t->offset) % 360), 1.0, 1.0); | |
} | |
/* | |
* Cycles through a fixed list of target colors. | |
*/ | |
void cycling_tick(Ticker *t, uint16_t tick) | |
{ | |
uint16_t current_index = (tick / TPS) % t->num_targets; // Update target once per second. | |
t->current = t->targets[current_index]; | |
} | |
/* | |
* Cycles through a fixed list of target colors, fading between them. | |
*/ | |
void fading_cycling_tick(Ticker *t, uint16_t tick) | |
{ | |
uint16_t previous_index = (tick / TPS) % t->num_targets; // Update target once per second. | |
rgb previous_color = t->targets[previous_index]; | |
rgb next_color = t->targets[(previous_index + 1) % t->num_targets]; | |
int16_t red_delta = next_color.red - previous_color.red; | |
int16_t current_red = previous_color.red + ((red_delta * (tick % TPS)) / TPS); | |
int16_t green_delta = next_color.green - previous_color.green; | |
int16_t current_green = previous_color.green + ((green_delta * (tick % TPS)) / TPS); | |
int16_t blue_delta = next_color.blue - previous_color.blue; | |
int16_t current_blue = previous_color.blue + ((blue_delta * (tick % TPS)) / TPS); | |
t->current = {red: current_red, green: current_green, blue: current_blue}; | |
} | |
/* | |
* Fades to a target color. Once target color is reached, the target and fade | |
* speed are randomized. Target randomization is controllable within min and | |
* max values on each color channel. | |
* | |
* Ticker's offset is used as the step size to control how quickly the color | |
* moves towards the target. | |
* | |
* Ticker's speed_adjust is used to skip cycles by powers of 2: | |
* 0 executes every cycle | |
* 1 executes every other cycle | |
* 2 executes every fourth cycle... | |
* | |
* This tick function uses three "target" colors: | |
* 0: The color to fade towards | |
* 1: The minimum value for each color channel when randomizing | |
* 2: The maximum value for each color channel when randomizing | |
*/ | |
void targeted_tick(Ticker *t, uint16_t tick) | |
{ | |
// speed_adjust keeps us from ticking on certain cycles | |
if (tick % (1 << t->speed_adjust)) {return;} | |
rgb* current = &t->current; | |
rgb* target = &t->targets[0]; | |
rgb minima = t->targets[1]; | |
rgb maxima = t->targets[2]; | |
int16_t step_size = t->offset; | |
if ( current->red == target->red | |
&& current->green == target->green | |
&& current->blue == target->blue) | |
{ | |
// We've reached the target! Pick a new one. | |
target->red = random(minima.red, maxima.red); | |
target->green = random(minima.green, maxima.green); | |
target->blue = random(minima.blue, maxima.blue); | |
// And just for fun let's also randomize the fade speed! | |
t->offset = skew(random(1, 100), 5, 50, 100); | |
t->speed_adjust = random(0, 2); | |
} | |
// Still working towards the target. Take a step in the right direction | |
// TODO: Should we adjust the step sizes so that each channel reaches | |
// its target at the same time? | |
current->red += stepToward(target->red, current->red, step_size); | |
current->green += stepToward(target->green, current->green, step_size); | |
current->blue += stepToward(target->blue, current->blue, step_size); | |
} | |
/*** HELPER FUNCTIONS ***/ | |
/* | |
* Given a target value, current value, and step size, calculate the value to | |
* add to the current value to move it towards its target by the step size | |
* without going past the target. | |
*/ | |
int16_t stepToward(int16_t target, int16_t current, int step_size) | |
{ | |
int16_t delta = target - current; | |
delta = abs(delta); | |
int direction = 0; | |
if (target > current) {direction = 1;} | |
if (target < current) {direction = -1;} | |
return (delta > step_size ? step_size : delta) * direction; | |
} | |
/* | |
* This is the gamma correction function that I included a lookup table for in | |
* shiftbrite.h. It's used here to map a uniform distribution to something skewed | |
* heavily towards the low end. | |
* | |
* Basically I want my targeting Tickers to fade slowly most of the time but do a | |
* really quick flicker every once in a while. | |
*/ | |
int16_t skew(int16_t x, int16_t exponent, int16_t max_out, int16_t range) | |
{ | |
return (int16_t)(pow((float)x / (float)range, exponent) * max_out + 1); | |
} | |
/* | |
* This function converts an HSV value into an RGB value. | |
* Code taken from StackOverflow user DavidH: | |
* http://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both | |
*/ | |
rgb hsv2rgb(double hue, double sat, double value) | |
{ | |
double sextant, chroma, q, t, ff; | |
double red, blue, green; | |
long i; | |
rgb out; | |
if(sat <= 0.0) { | |
red = value; | |
green = value; | |
blue = value; | |
return out; | |
} | |
sextant = hue; | |
if(sextant >= 360.0) sextant = 0.0; | |
sextant /= 60.0; | |
i = (long)sextant; | |
ff = sextant - i; | |
chroma = value * (1.0 - sat); | |
q = value * (1.0 - (sat * ff)); | |
t = value * (1.0 - (sat * (1.0 - ff))); | |
switch(i) { | |
case 0: | |
red = value; | |
green = t; | |
blue = chroma; | |
break; | |
case 1: | |
red = q; | |
green = value; | |
blue = chroma; | |
break; | |
case 2: | |
red = chroma; | |
green = value; | |
blue = t; | |
break; | |
case 3: | |
red = chroma; | |
green = q; | |
blue = value; | |
break; | |
case 4: | |
red = t; | |
green = chroma; | |
blue = value; | |
break; | |
case 5: | |
default: | |
red = value; | |
green = chroma; | |
blue = q; | |
break; | |
} | |
out.red = (int16_t)(red * 1023); | |
out.green = (int16_t)(green * 1023); | |
out.blue = (int16_t)(blue * 1023); | |
return out; | |
} |
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 "shiftbrite.h" // See https://github.com/kylemarsh/particle_shiftbrite | |
#define latchpin D0 // replace with pin you use for the latch | |
#define numleds 4 // Number of LEDs in your chain | |
typedef struct { | |
uint16_t red; | |
uint16_t green; | |
uint16_t blue; | |
} rgb; | |
rgb pixels[numleds]; | |
void wanderPixel(int address, rgb minima, rgb maxima); | |
ShiftBrite sb(numleds, latchpin); | |
void setup() { | |
Serial.begin(9600); | |
Serial.println("Starting up"); | |
sb.begin(); | |
sb.show(); | |
for (int i = 0; i < numleds; ++i) { | |
pixels[i].red = random(0, 1023); | |
pixels[i].green = random(0, 1023); | |
pixels[i].blue = random(766, 0123); | |
Serial.printf(" Pixel %d:\n R: %d\n G: %d\n B: %d\n\n", i, pixels[i].red, pixels[i].green, pixels[i].blue); | |
} | |
} | |
void loop() { | |
wander(); | |
} | |
void wander() { | |
const rgb min = { | |
red: 0, | |
green: 0, | |
blue: 766 | |
}; | |
const rgb max = { | |
red: 1023, | |
green: 1023, | |
blue: 1023 | |
}; | |
for (int i = 0; i < numleds; ++i) { | |
Serial.printf("Wandering pixel %d\n", i); | |
wanderPixel(i, min, max); | |
sb.setPixelRGB(i, pixels[i].red, pixels[i].green, pixels[i].blue); | |
} | |
sb.show(); | |
delay(10); | |
} | |
void wanderPixel(int address, rgb minima, rgb maxima) { // FIXME: this trends to 0. Why? | |
Serial.printf(" Starting values:\n R: %d\n G: %d\n B: %d\n\n", pixels[address].red, pixels[address].green, pixels[address].blue); | |
rgb percents, deltas, newval; | |
percents.red = random(0, 20); | |
percents.green = random(0, 20); | |
percents.blue = random(0, 20); | |
Serial.printf(" Percentages:\n R: %d\n G: %d\n B: %d\n\n", percents.red, percents.green, percents.blue); | |
deltas.red = pixels[address].red * percents.red / 100; | |
deltas.green = pixels[address].green * percents.green / 100; | |
deltas.blue = pixels[address].blue * percents.blue / 100; | |
int red_sign = random(0, 2) ? 1 : -1; | |
int green_sign = random(0, 2) ? 1 : -1; | |
int blue_sign = random(0, 2) ? 1 : -1; | |
Serial.printf(" Deltas:\n R: %d\n G: %d\n B: %d\n\n", (long)deltas.red * red_sign, (long)deltas.green * green_sign, (long)deltas.blue * blue_sign); | |
//Serial.printf(" Deltas:\n R: %d\n G: %d\n B: %d\n\n", deltas.red, deltas.green, deltas.blue); | |
newval.red = constrain(pixels[address].red + (long)deltas.red * red_sign, minima.red, maxima.red); | |
newval.green = constrain(pixels[address].green + (long)deltas.green * green_sign, minima.green, maxima.green); | |
newval.blue = constrain(pixels[address].blue + (long)deltas.blue * blue_sign, minima.blue, maxima.blue); | |
pixels[address].red = newval.red; | |
pixels[address].green = newval.green; | |
pixels[address].blue = newval.blue; | |
Serial.printf(" New values:\n R: %d\n G: %d\n B: %d\n\n", pixels[address].red, pixels[address].green, pixels[address].blue); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment