Skip to content

Instantly share code, notes, and snippets.

@telent
Created December 15, 2017 13:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save telent/cdf46a31c036ab69250fa43ff281ebbc to your computer and use it in GitHub Desktop.
Save telent/cdf46a31c036ab69250fa43ff281ebbc to your computer and use it in GitHub Desktop.
#include <Adafruit_NeoPixel.h>
#define CW_PIN 5
#define CCW_PIN 6
#define FUNCTION_PIN 9
#define HUE (A1)
#define BRIGHTNESS_POT (A2)
#define STRIP_PIN 2
#define NUM_LEDS 144
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, STRIP_PIN, NEO_GRB + NEO_KHZ800);
/* 80% brightness is at about 20% power (appparently) and diminishing returns
* thereafter, so scale the 0-1023 analog value from the pot to between
* about 0 and about 64
*/
#define BRIGHTNESS_SCALE(c) ((c) >> 4)
/*
mode of operation: we animate a number of colour splotches going around a ring
led 0 and led NUM_LEDS are at the bottom of the ring
pressing CW (or CCW) introduces a new splotch travelling clockwise (or
counterclockwise respectively)
adjusting HUE changes the colour that is painted
pressing CW or CCW while FUNCTION_PIN is held down changes the animation speed
adjusting BRIGHTNESS_POT changes the brightness of the whole strip
we need to cap the number of splotches to keep total power consumption down,
so when you exceed NUM_SPLOTCHES it drops the oldest one
splotches are (birth_time, direction, hue)
a splotch with birth_time t0, at time t1, will be at offset (t1-t0)*direction
on each step we clear the strip then paint each splotch onto the strip
at the calculated offset
*/
struct splotch {
uint8_t born_at; /* these times are mod NUM_LEDS */
int8_t direction;
uint16_t hue; /* 10 bits will do, really */
};
#define NUM_SPLOTCHES (4)
struct splotch splotches[NUM_SPLOTCHES];
struct splotch *next_splotch = splotches;
void set_next_splotch(uint8_t born_at, int8_t dir, uint16_t hue) {
struct splotch *s=next_splotch;
s->born_at = born_at;
s->direction = dir;
s->hue = hue;
next_splotch++;
if((next_splotch - splotches) >= NUM_SPLOTCHES) next_splotch = splotches;
Serial.println(s-splotches);
Serial.println(next_splotch-splotches);
}
int8_t speed = 5;
uint16_t time_now = 0;
/* C % operator doesn't treat -ve values the way we want */
uint8_t mod_length(int32_t value) {
while(value < 0) value+=NUM_LEDS;
return (uint8_t) (value % NUM_LEDS);
}
/* This code stolen from https://stackoverflow.com/a/9493060 */
/* Converts an HSL color value to RGB. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes h, s, and l are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 255].
*
* @param {number} h The hue
* @param {number} s The saturation
* @param {number} l The lightness
*/
float hue_to_color_helper(float p, float q, float t) {
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1.0/6) return p + (q - p) * 6 * t;
if(t < 1.0/2) return q;
if(t < 2.0/3) return p + (q - p) * (2.0/3 - t) * 6;
return p;
}
uint32_t hue_to_color(uint16_t hue, int scale){
float r, g, b;
float h = hue/1024.0;
float s = 1.0;
float l = 0.4;
float q = l < 0.5 ? l * (1 + s) : l + s - l * s;
float p = 2 * l - q;
r = hue_to_color_helper(p, q, h + 1.0/3);
g = hue_to_color_helper(p, q, h);
b = hue_to_color_helper(p, q, h - 1.0/3);
uint32_t c = strip.Color((int) (r*scale),
(int) (g*scale),
(int) (b*scale));
return c;
}
void paint_splotches(int brightness) {
strip.clear();
for(struct splotch * s = splotches;
s < (splotches + NUM_SPLOTCHES);
s++) {
if(s->direction) {
int dir = s->direction;
int offset = mod_length( ((int32_t) (time_now - s->born_at)) * dir);
uint32_t color = hue_to_color(s->hue, brightness);
strip.setPixelColor(offset, color);
strip.setPixelColor(offset - dir,
hue_to_color(s->hue, brightness/2));
strip.setPixelColor(offset - dir - dir,
hue_to_color(s->hue, brightness/6));
strip.setPixelColor(offset - dir - dir - dir,
hue_to_color(s->hue, brightness/12));
}
}
strip.show();
}
void setup() {
// put your setup code here, to run once:
strip.begin();
strip.show();
pinMode(LED_BUILTIN, OUTPUT);
pinMode(CW_PIN, INPUT_PULLUP);
pinMode(CCW_PIN, INPUT_PULLUP);
pinMode(FUNCTION_PIN, INPUT_PULLUP);
pinMode(HUE, INPUT);
pinMode(BRIGHTNESS_POT, INPUT);
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
int b = analogRead(BRIGHTNESS_POT);
int brightness = BRIGHTNESS_SCALE(b);
time_now++; // mod_length(time_now + 1);
if(LOW == digitalRead(FUNCTION_PIN)) {
if(LOW == digitalRead(CW_PIN)) speed++;
if((speed > 1) && (LOW == digitalRead(CCW_PIN))) speed--;
} else {
int8_t direction=0;
if(LOW == digitalRead(CW_PIN)) direction = 1;
if(LOW == digitalRead(CCW_PIN)) direction = -1;
if(direction) {
uint16_t hue = analogRead(HUE);
set_next_splotch(mod_length(time_now), direction, hue);
}
}
paint_splotches(brightness);
digitalWrite(LED_BUILTIN, HIGH);
delay(10);
digitalWrite(LED_BUILTIN, LOW);
delay(500/speed);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment