Created
January 30, 2019 09:30
-
-
Save asaaki/b3613343cb68528b3f46f51900132349 to your computer and use it in GitHub Desktop.
motion sensor / interrupt triggered neopixel light controller
This file contains hidden or 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 <Adafruit_NeoPixel.h> | |
#include <avr/power.h> | |
#include <avr/interrupt.h> | |
#include <avr/sleep.h> | |
#define STRIP_PIN 6 | |
#define TRIGGER_PIN 2 | |
#define CONTROL_LED 13 | |
// Note: this duration should be also longer than the HIGH time of the PIR | |
const uint32_t lightDuration = 9 * 1000L; // ms | |
Adafruit_NeoPixel strip = Adafruit_NeoPixel(1, STRIP_PIN, NEO_GRB + NEO_KHZ800); | |
void setup() { | |
digitalWrite(TRIGGER_PIN, LOW); | |
digitalWrite(CONTROL_LED, LOW); | |
pinMode(TRIGGER_PIN, INPUT); | |
pinMode(CONTROL_LED, OUTPUT); | |
// warm up phase for the PIR sensor | |
for(int i = 1; i <= 120; i++) { | |
digitalWrite(CONTROL_LED, HIGH); delay(100); | |
digitalWrite(CONTROL_LED, LOW); delay(100); | |
} | |
} | |
void loop() { | |
interrupts(); | |
lightshow(); | |
hibernate(); | |
} | |
// ISR; set state only, never do heavy lifting here | |
// noop - we only need to resume from where we left off; see further down in hibernate() | |
void wakeup() {} | |
void lightshow() { | |
// I don't trust the sleep mode state, so I re-init the strip with each wake up call, works fine | |
strip.begin(); | |
strip.setBrightness(100); | |
strip.show(); | |
for(uint32_t tStart = millis(); (millis() - tStart) < lightDuration; /**/) { | |
// short tasks (less than max duration time ideally) | |
rainbow(10); | |
} | |
strip.clear(); | |
strip.show(); | |
digitalWrite(CONTROL_LED, HIGH); | |
delay(500); | |
digitalWrite(CONTROL_LED, LOW); | |
} | |
void hibernate() { | |
// set all pins (except our control LED) to inputs (considered best practice for sleep mode) | |
for(int pin = 0; pin < 20; pin++) { if(pin != CONTROL_LED) { pinMode(pin, INPUT); } }; | |
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // saves a lot of power, other modes are maybe less effective | |
ADCSRA &= ~(1 << 7); // disable ADC (saves some power) | |
sleep_bod_disable(); // disable BOD (saves power, maybe?) | |
// where and how do we want to be awaken? | |
attachInterrupt(digitalPinToInterrupt(TRIGGER_PIN), wakeup, CHANGE); | |
sleep_mode(); | |
// ... sleep and wait for interrupt to happen ... | |
// interrupt fired; resume ... | |
sleep_disable(); | |
detachInterrupt(digitalPinToInterrupt(TRIGGER_PIN)); | |
} | |
// stolen from the neopixel example | |
void rainbow(uint8_t wait) { | |
uint16_t i, j; | |
for(j=0; j<256; j++) { | |
for(i=0; i<strip.numPixels(); i++) { | |
strip.setPixelColor(i, Wheel((i+j) & 255)); | |
} | |
strip.show(); | |
delay(wait); | |
} | |
} | |
uint32_t Wheel(byte WheelPos) { | |
WheelPos = 255 - WheelPos; | |
if(WheelPos < 85) { | |
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); | |
} | |
if(WheelPos < 170) { | |
WheelPos -= 85; | |
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); | |
} | |
WheelPos -= 170; | |
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Keep in mind: the continuation point after wake-up depends on the microcontrollers. Arduinos/AVRs resume where they stopped, so after the
sleep_mode();
line.But others like ESP handle sleep/wake-ups a bit different (starting with
setup()
again), so you have to check how the controller was reset.Check the docs for the sleep mode of your µC.