234 lines
4.9 KiB
Arduino
234 lines
4.9 KiB
Arduino
|
#include <NeoPixelBus.h>
|
||
|
|
||
|
#define DOUBLE_SIDE 0
|
||
|
#define DOUBLE_SIDE_MIRROR 0
|
||
|
#define IMAGE_HEIGHT (7)
|
||
|
#define IMAGE_WIDTH (48)
|
||
|
#define N_ROT_SLICES (48)
|
||
|
#define WS_PIN (8)
|
||
|
#define WS_VCC (9)
|
||
|
#define WS_GND (7)
|
||
|
#define HALL_PIN (2)
|
||
|
|
||
|
static const RgbColor off(0,0,0);
|
||
|
|
||
|
|
||
|
#if DOUBLE_SIDE
|
||
|
#define WS_PIXEL_COUNT (2*IMAGE_HEIGHT)
|
||
|
#else
|
||
|
#define WS_PIXEL_COUNT (IMAGE_HEIGHT)
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#define IMAGE_FAIRYDUST
|
||
|
//#define IMAGE_CYBER
|
||
|
|
||
|
#ifdef IMAGE_CYBER
|
||
|
|
||
|
#define SKEW_RATE (0)
|
||
|
|
||
|
static const __restrict__ RgbColor PALETTE[] = {
|
||
|
RgbColor(0,0,0), // black
|
||
|
RgbColor(20,20,0) // yellow
|
||
|
};
|
||
|
|
||
|
static const __restrict__ uint8_t IMAGE[IMAGE_WIDTH][IMAGE_HEIGHT] = {
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,0,1,0,0,1},
|
||
|
{1,0,1,0,1,1,1},
|
||
|
{1,0,0,0,0,0,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,0,1,0,1,0,1},
|
||
|
{1,0,1,0,1,0,1},
|
||
|
{1,0,0,0,0,0,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,0,1,0,1,1},
|
||
|
{1,0,1,0,1,0,1},
|
||
|
{1,0,0,0,0,0,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,0,0,1,1,1,1},
|
||
|
{1,1,1,0,0,0,1},
|
||
|
{1,0,0,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,0,1,1,1,0,1},
|
||
|
{1,0,1,1,1,0,1},
|
||
|
{1,1,0,0,0,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1},
|
||
|
{1,1,1,1,1,1,1}
|
||
|
};
|
||
|
|
||
|
#elif defined(IMAGE_FAIRYDUST)
|
||
|
|
||
|
#define SKEW_RATE (100)
|
||
|
|
||
|
static const RgbColor PALETTE[] = {
|
||
|
RgbColor(0,0,0), // black
|
||
|
RgbColor(0,128,0), // green
|
||
|
RgbColor(255,180,0), // orange
|
||
|
RgbColor(255,0,0) // red
|
||
|
};
|
||
|
|
||
|
static const __restrict__ uint8_t IMAGE[IMAGE_WIDTH][IMAGE_HEIGHT] = {
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,1,0,0,0},
|
||
|
{0,0,1,2,1,0,0},
|
||
|
{0,1,2,1,1,1,0},
|
||
|
{0,1,2,1,1,1,0},
|
||
|
{1,2,2,2,1,1,1},
|
||
|
{1,2,2,2,1,1,1},
|
||
|
{0,1,2,1,1,1,0},
|
||
|
{0,1,2,1,1,1,0},
|
||
|
{0,0,1,2,1,0,0},
|
||
|
{0,1,0,1,0,1,0},
|
||
|
{1,1,0,3,0,1,1},
|
||
|
{1,1,3,3,3,1,1},
|
||
|
{1,0,3,3,3,0,1},
|
||
|
{0,0,0,3,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0},
|
||
|
{0,0,0,0,0,0,0}
|
||
|
};
|
||
|
|
||
|
#endif
|
||
|
|
||
|
static NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> ws2812(WS_PIXEL_COUNT, WS_PIN);
|
||
|
|
||
|
static volatile uint32_t last_hall = 0UL;
|
||
|
static volatile uint32_t last_hall_diff = 1000UL;
|
||
|
|
||
|
#if SKEW_RATE
|
||
|
static uint16_t skew = 0U;
|
||
|
static uint32_t last_skew = 0UL;
|
||
|
#endif
|
||
|
|
||
|
void update_hall_timestamp() {
|
||
|
uint32_t now = millis();
|
||
|
last_hall_diff = now - last_hall;
|
||
|
last_hall = now;
|
||
|
}
|
||
|
|
||
|
void setup() {
|
||
|
// Setup output pins
|
||
|
pinMode(WS_PIN, OUTPUT);
|
||
|
pinMode(HALL_PIN, INPUT);
|
||
|
// Setup power supply for WS2812 strip
|
||
|
// (Yes, I know I shouldn't supply power from the Arduino I/O pins,
|
||
|
// but I'm running the LEDs at a fraction of their max power draw)
|
||
|
pinMode(WS_VCC, OUTPUT);
|
||
|
pinMode(WS_GND, OUTPUT);
|
||
|
digitalWrite(WS_VCC, HIGH);
|
||
|
digitalWrite(WS_GND, LOW);
|
||
|
// Setup WS2812 strup
|
||
|
ws2812.Begin();
|
||
|
ws2812.Show();
|
||
|
// Setup hall sensor interrupt
|
||
|
attachInterrupt(
|
||
|
digitalPinToInterrupt(HALL_PIN),
|
||
|
update_hall_timestamp,
|
||
|
FALLING
|
||
|
);
|
||
|
}
|
||
|
|
||
|
void loop() {
|
||
|
// Get the current time
|
||
|
uint32_t now = millis();
|
||
|
// Turn the LEDs off if no sensor input was received for 3s
|
||
|
if ((now - last_hall) > 3000UL) {
|
||
|
for (size_t i = 0; i < IMAGE_HEIGHT; ++i) {
|
||
|
ws2812.SetPixelColor(i, off);
|
||
|
#if DOUBLE_SIDE
|
||
|
ws2812.SetPixelColor(IMAGE_HEIGHT + i, off);
|
||
|
#endif
|
||
|
}
|
||
|
ws2812.Show();
|
||
|
// Only re-check after a second
|
||
|
delay(1000);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Get the slice to show at the current time, based on the time between the last two sensor events
|
||
|
uint16_t slice = (uint16_t) (((now - last_hall) * N_ROT_SLICES / last_hall_diff) % N_ROT_SLICES);
|
||
|
#if SKEW_RATE
|
||
|
// Increment the skew offset when it's time for the next skew step
|
||
|
if (now - last_skew > SKEW_RATE) {
|
||
|
skew = (skew + 1) % N_ROT_SLICES;
|
||
|
last_skew = now;
|
||
|
}
|
||
|
// Add the current skew offset to the slice index
|
||
|
slice = (uint16_t) ((slice + skew) % N_ROT_SLICES);
|
||
|
#endif
|
||
|
|
||
|
// Display the current slice (row) of the image
|
||
|
for (size_t i = 0; i < IMAGE_HEIGHT; ++i) {
|
||
|
ws2812.SetPixelColor(i, PALETTE[IMAGE[slice][i]]);
|
||
|
#if DOUBLE_SIDE
|
||
|
#if DOUBLE_SIDE_MIRROR
|
||
|
ws2812.SetPixelColor(IMAGE_HEIGHT+i, PALETTE[IMAGE[N_ROT_SLICES-slice][i]]);
|
||
|
#else
|
||
|
ws2812.SetPixelColor(IMAGE_HEIGHT+i, PALETTE[IMAGE[slice][i]]);
|
||
|
#endif
|
||
|
#endif
|
||
|
}
|
||
|
ws2812.Show();
|
||
|
}
|