part one:
/*------------------------------------------------------------------------
Gemma "Firewalker Lite" sneakers sketch.
Uses the following Adafruit parts (X2 for two shoes):
- Gemma 3V microcontroller (adafruit.com/product/1222 or 2470)
- 150 mAh LiPoly battery (#1317) or larger
- Medium vibration sensor switch (#2384)
- 60/m NeoPixel RGB LED strip (#1138 or #1461)
- LiPoly charger such as #1304 (only one is required, unless you want
to charge both shoes at the same time)
Needs Adafruit_NeoPixel library: github.com/adafruit/Adafruit_NeoPixel
THIS CODE USES FEATURES SPECIFIC TO THE GEMMA MICROCONTROLLER BOARD AND
WILL NOT COMPILE OR RUN ON MOST OTHERS. OK on basic Trinket but NOT
Pro Trinket nor anything else. VERY specific to the Gemma!
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Phil Burgess / Paint Your Dragon for Adafruit Industries.
MIT license, all text above must be included in any redistribution.
See 'COPYING' file for additional notes.
------------------------------------------------------------------------*/
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
#include <avr/power.h>
#include <avr/sleep.h>
// CONFIGURABLE STUFF ------------------------------------------------------
#define NUM_LEDS 40 // Actual number of LEDs in NeoPixel strip
#define CIRCUMFERENCE 40 // Shoe circumference, in pixels, may be > NUM_LEDS
#define FPS 50 // Animation frames per second
#define LED_DATA_PIN 1 // NeoPixels are connected here
#define MOTION_PIN 0 // 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.
// The following features are OPTIONAL and require ADDITIONAL COMPONENTS.
// Only ONE of these may be enabled due to limited pins on Gemma:
// BATTERY LEVEL graph on power-up: requires two resistors of same value,
// 10K or higher, connected to pin D2 -- one goes to Vout pin, other to GND.
//#define BATT_LVL_PIN 2 // Un-comment this line to enable battery level.
// Pin number cannot be changed, this is the only AREF pin on ATtiny85.
// Empty and full thresholds (millivolts) used for battery level display:
#define BATT_MIN_MV 3350 // Some headroom over battery cutoff near 2.9V
#define BATT_MAX_MV 4000 // And little below fresh-charged battery near 4.1V
// Graph works only on battery power; USB power will always show 100% full.
// POWER DOWN NeoPixels when idle to prolong battery: requires P-channel
// power MOSFET + 220 Ohm resistor, is a 'high side' switch to NeoPixel +V.
// DO NOT do this w/N-channel on GND side, could DESTROY strip!
//#define LED_PWR_PIN 2 // Un-comment this for NeoPixel power-down.
// Could be moved to other pin on Trinket to allow both options together.
// GLOBAL STUFF ------------------------------------------------------------
Adafruit_NeoPixel strip(NUM_LEDS, LED_DATA_PIN);
void sleep(void); // Power-down function
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]))