I have some code I messed with last night that compiled correctly. gonna give it a shot when i get home. fingers crossed that it works!
part 1 of 2
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
// CONFIGURABLE STUFF ------------------------------------------------------
#define NUM_LEDS 23 // Actual number of LEDs in NeoPixel strip
#define CIRCUMFERENCE 23 // Shoe circumference, in pixels, may be > NUM_LEDS
#define FPS 50 // Animation frames per second
#define LED_DATA_PIN 6 // NeoPixels are connected here
#define MOTION_PIN 13 // Vibration switch from here to GND
// CIRCUMFERENCE is distinct from NUM_LEDS to allow a gap (if desired) in
// LED strip around perimeter of shoe (might not want any on inside egde)
// so animation is spatially coherent (doesn't jump across gap, but moves
// as if pixels were in that space). CIRCUMFERENCE can be equal or larger
// than NUM_LEDS, but not less.
// GLOBAL STUFF ------------------------------------------------------------
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_DATA_PIN, NEO_GRB + NEO_KHZ800);
extern const uint8_t gamma[]; // Table at the bottom of this code
// INTERMISSION explaining the animation code. This works procedurally --
// using mathematical functions -- rather than moving discrete pixels left
// or right incrementally. This sometimes confuses people because they go
// looking for some "setpixel(x+1, color)" type of code and can't find it.
// Also makes extensive use of fixed-point math, where discrete integer
// values are used to represent fractions (0.0 to 1.0) without relying on
// floating-point math, which just wouldn't even fit in Gemma's limited
// code space, RAM or speed. The reason the animation's done this way is
// to produce smoother, more organic motion...when pixels are the smallest
// discrete unit, animation tends to have a stuttery, 1980s quality to it.
// We can do better!
// Picture the perimeter of the shoe in two different coordinate spaces:
// One is "pixel space," each pixel spans exactly one integer unit, from
// zero to N-1 when there are N pixels. This is how NeoPixels are normally
// addressed. Now, overlaid on this, imagine another coordinate space,
// spanning the same physical width (the perimeter of the shoe, or length
// of the LED strip), but this one has 256 discrete steps (8 bits)...finer
// resolution than the pixel steps...and we do most of the math using
// these units rather than pixel units. It's then possible to move things
// by fractions of a pixel, but render each whole pixel by taking a sample
// at its approximate center in the alternate coordinate space.
// More explanation further in the code.
//
// |Pixel|Pixel|Pixel| ... |Pixel|Pixel|Pixel|<- end of strip
// | 0 | 1 | 2 | | 3 | 4 | N-1 |
// |0... ... ...255|<- fixed-point space
//
// So, inspired by the mothership in Close Encounters of the Third Kind,
// the animation in this sketch is a series of waves moving around the
// perimeter and interacting as they cross. They're triangle waves,
// height proportional to LED brightness, determined by the time since
// motion was last detected.
//
// <- /\ /\ -> <- /\ Pretend these are triangle waves
// ____/ \_____/ \_____/ \____ <- moving in 8-bit coordinate space.
struct {
uint8_t center; // Center point of wave in fixed-point space (0 - 255)
int8_t speed; // Distance to move between frames (-128 - +127)
uint8_t width; // Width from peak to bottom of triangle wave (0 - 128)
uint8_t hue; // Current wave hue (color) see comments later
uint8_t hueTarget; // Final hue we're aiming for
uint8_t r, g, b; // LED RGB color calculated from hue
} wave[] = {
{ 0, 3, 60 }, // Gemma can animate 3 of these on 40 LEDs at 50 FPS
{ 0, -5, 45 }, // More LEDs and/or more waves will need lower FPS
{ 0, 7, 30 }
};
// Note that the speeds of each wave are different prime numbers. This
// avoids repetition as the waves move around the perimeter...if they were
// even numbers or multiples of each other, there'd be obvious repetition
// in the pattern of motion...beat frequencies.
#define N_WAVES (sizeof(wave) / sizeof(wave[0]))
// ONE-TIME INITIALIZATION -------------------------------------------------
void setup() {
strip.begin(); // Allocate NeoPixel buffer
strip.clear(); // Make sure strip is clear
strip.show(); // before measuring battery
// Assign random starting colors to waves
for(uint8_t w=0; w<N_WAVES; w++) {
wave[w].hue = wave[w].hueTarget = 90 + random(90);
wave[w].r = h2rgb(wave[w].hue - 30);
wave[w].g = h2rgb(wave[w].hue);
wave[w].b = h2rgb(wave[w].hue + 30);
}
// Configure motion pin for change detect & interrupt
pinMode(MOTION_PIN, INPUT_PULLUP);
}
// MAIN LOOP ---------------------------------------------------------------
uint32_t prevFrameTime = 0L; // Used for animation timing
uint8_t brightness = 0; // Current wave height
boolean rampingUp = false; // If true, brightness is increasing
void loop() {
uint32_t t;
uint16_t r, g, b, m, n;
uint8_t i, x, w, d1, d2, y;
// Pause until suitable interval since prior frame has elapsed.
// This is preferable to delay(), as the time to render each frame
// can vary.
while(((t = micros()) - prevFrameTime) < (1000000L / FPS));
// Immediately show results calculated on -prior- pass,
// so frame-to-frame timing is consistent. Then render next frame.
strip.show();
prevFrameTime = t; // Save frame update time for next pass
if(MOTION_PIN == LOW) { // Pin change detected?
rampingUp = true; // Set brightness-ramping flag
} else {
rampingUp = false;
}
// Okay, here's where the animation starts to happen...
// First, check the 'rampingUp' flag. If set, this indicates that
// the vibration switch was activated recently, and the LEDs should
// increase in brightness. If clear, the LEDs ramp down.
if(rampingUp) {
// But it's not just a straight shot that it ramps up. This is a
// low-pass filter...it makes the brightness value decelerate as it
// approaches a target (200 in this case). 207 is used here because
// integers round down on division and we'd never reach the target;
// it's an ersatz ceil() function: ((199*7)+200+7)/8 = 200;
brightness = ((brightness * 7) + 207) / 8;
// Once max brightness is reached, switch off the rampingUp flag.
if(brightness >= 200) rampingUp = false;
} else {
// If not ramping up, we're ramping down. This too uses a low-pass
// filter so it eases out, but with different constants so it's a
// slower fade. Also, no addition here because we want it rounding
// down toward zero...
if(!(brightness = (brightness * 15) / 16)) { // Hit zero?
return; // Start over at top of loop() on wake
}
}