Created
April 9, 2016 01:30
-
-
Save mikedotalmond/d5fdd7110fa4114b54f1dfc5c5d73b95 to your computer and use it in GitHub Desktop.
PIR audio trigger
This file contains 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 <WaveHC.h> | |
#include <WaveUtil.h> | |
const int minimumSoundInterval = 2000; | |
const int soundIntervalRange = 8000; | |
boolean playingSound = false; | |
int lastPlayed = 0; | |
SdReader card; // This object holds the information for the card | |
FatVolume vol; // This holds the information for the partition on the card | |
FatReader root; // This holds the information for the volumes root directory | |
FatReader file; // This object represent the WAV file | |
WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time | |
/* | |
* Define macro to put error messages in flash memory | |
*/ | |
#define error(msg) error_P(PSTR(msg)) | |
#define FILE_COUNT 29 | |
#define PIR_CALIBRATION_TIME 20000 | |
#define DEBUG false | |
// PIR Sensor | |
int calibrationTime = PIR_CALIBRATION_TIME; | |
const int PIRPin = 6; | |
const int LEDPin = 7; | |
boolean takeLowTime; | |
boolean pirReady = false; | |
boolean motionDetected = false; | |
// | |
uint32_t lastT = 0; | |
//////////////////////////////////// SETUP | |
void setup() { | |
#if DEBUG | |
Serial.begin(9600); | |
#endif | |
randomSeed(analogRead(0)); | |
pinMode(PIRPin, INPUT); | |
pinMode(LEDPin, OUTPUT); | |
calibratePIR(); | |
setupAudio(); | |
} | |
// call to (re)calibrate | |
void calibratePIR(){ | |
digitalWrite(PIRPin, LOW); | |
digitalWrite(LEDPin, LOW); | |
calibrationTime = PIR_CALIBRATION_TIME; | |
pirReady = false; | |
} | |
void setupAudio(){ | |
if (!card.init()) error("card.init"); | |
// enable optimized read - some cards may timeout | |
card.partialBlockRead(true); | |
if (!vol.init(card)) error("vol.init"); | |
if (!root.openRoot(vol)) error("openRoot"); | |
indexFiles(); | |
// | |
playByIndex(0); | |
} | |
//////////////////////////////////// LOOP | |
void loop() { | |
uint32_t t = millis(); | |
uint32_t dt = t - lastT; | |
lastT = t; | |
bool hadMotion = motionDetected; | |
checkPIR(t, dt); | |
if(playingSound && !wave.isplaying) { | |
// playback ended | |
playingSound = false; | |
lastPlayed = 0; | |
wave.stop(); | |
// check for play errors | |
sdErrorCheck(); | |
} else { | |
lastPlayed += dt; | |
} | |
if(!playingSound && /* not playing? */ | |
((!hadMotion && motionDetected) || /* new motion started */ | |
(motionDetected && lastPlayed > minimumSoundInterval + random(soundIntervalRange)) /* old motion continued for a while */ | |
)){ | |
playByIndex(random(FILE_COUNT-1)); | |
} | |
} | |
// | |
void checkPIR(uint32_t t, int dt) { | |
if(pirReady){ | |
if(digitalRead(PIRPin) == HIGH){ // detected | |
digitalWrite(LEDPin, HIGH); | |
if(!motionDetected){ | |
motionDetected = true; | |
#if DEBUG | |
Serial.println("---"); | |
Serial.print("motion detected at "); | |
Serial.print(t/1000); | |
Serial.println(" sec"); | |
#endif | |
} | |
} else { | |
if(motionDetected){ | |
digitalWrite(LEDPin, LOW); | |
motionDetected = false; | |
#if DEBUG | |
Serial.print("motion ended at "); | |
Serial.print(millis()/1000); | |
Serial.println(" sec"); | |
#endif | |
} | |
} | |
} else { | |
calibrationTime -= dt; | |
if(calibrationTime <= 0){ | |
pirReady = true; | |
digitalWrite(LEDPin, LOW); | |
#if DEBUG | |
Serial.println("PIR Calibration complete"); | |
#endif | |
} | |
} | |
} | |
/////////////////////////////////// HELPERS | |
/* | |
* print error message and halt | |
*/ | |
void error_P(const char *str) { | |
#if DEBUG | |
PgmPrint("Error: "); | |
SerialPrint_P(str); | |
#endif | |
sdErrorCheck(); | |
while(1); | |
} | |
/* | |
* print error message and halt if SD I/O error, great for debugging! | |
*/ | |
void sdErrorCheck(void) { | |
if (!card.errorCode()) return; | |
#if DEBUG | |
PgmPrint("\r\nSD I/O error: "); | |
Serial.print(card.errorCode(), HEX); | |
PgmPrint(", "); | |
Serial.println(card.errorData(), HEX); | |
#endif | |
while(1); | |
} | |
char fileLetter[] = { | |
'0','1','2','3','4','5','6','7','8','9', | |
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s' | |
}; | |
// index of files in the root directory | |
uint16_t fileIndex[FILE_COUNT]; | |
/* | |
* Find files and save file index. A file's index is is the | |
* index of it's directory entry in it's directory file. | |
*/ | |
void indexFiles(void) { | |
char name[10]; | |
// copy flash string to RAM | |
strcpy_P(name, PSTR("gary-x.wav")); | |
for (uint8_t i = 0; i < FILE_COUNT; i++) { | |
// Make file name | |
name[5] = fileLetter[i]; | |
#if DEBUG | |
Serial.println(name); | |
#endif | |
// Open file by name | |
if (!file.open(root, name)) error("open by name"); | |
// Save file's index (byte offset of directory entry divided by entry size) | |
// Current position is just after entry so subtract one. | |
fileIndex[i] = root.readPosition()/32 - 1; | |
} | |
#if DEBUG | |
PgmPrintln("Done"); | |
#endif | |
} | |
/* | |
* Play file by index and print latency in ms | |
*/ | |
void playByIndex(int i) { | |
if (!file.open(root, fileIndex[i])) error("open by index"); | |
if (!wave.create(file)) error("wave.create"); | |
wave.play(); | |
playingSound = true; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment