Last active
August 29, 2015 14:17
-
-
Save unixunion/ee6451da44a56a5f9959 to your computer and use it in GitHub Desktop.
Jeremy Cricket Day / Night edition
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
/* | |
_____ _ _ _ ____ _____ | |
/ ____| (_) | | | | / __ \ / ____| | |
| | _ __ _ ___| | _____| |_| | | | (___ | |
| | | '__| |/ __| |/ / _ \ __| | | |\___ \ | |
| |____| | | | (__| < __/ |_| |__| |____) | | |
\_____|_| |_|\___|_|\_\___|\__|\____/|_____/ 2.0 | |
CricketOS chirps at configured day/night/day transitions for a certain amount of songs, then waits until | |
the next transistion. Prank your firends, they will have a hard time locating it. | |
* Shuts down the MCU to save power | |
* Can detect day / night / day transitions using only a LED and 100ohm resistor | |
* Can use power / passive piezo plates. ( NOT a buzzer, a buzzer has no controlable tones ) | |
LED | |
use a regular LED to measure light levels by exploiting change in charge bleedoff. connect a LED and | |
a 100ohm resistor to pins 0 and 2 e.g PIN0 --> 100ohm --> LED_NEGATIVE ---> LED_POSITIVE ---> PIN2 | |
PIEZO | |
Connect you PIEZO ( not a buzzer ) to PIN4 and GND. It must be the kind that takes a square wave in. | |
If it's a powered piezo, make sure to check if the transistor requires HIGH or LOW in order to turn OFF the speaker, | |
and then ensure that SPEAKER_OFF is set to which ever is the correct OFF state. This is usually HIGH for piezo's | |
with a transistor. Set to LOW for a unpowered piezo. | |
DEBUG / UPDATING | |
If debug is enabled, the arduino will NOT powerdown, but instead just sleep. Since a arduino in powerdown cannot be flashed, there is a | |
5 second bootup delay in setup() in order to allow you to flash the unit quickly before naptime. Debug also enables serial debugging. | |
*/ | |
//#define DEBUG | |
#ifdef DEBUG | |
#define DEBUG_PRINT(x) Serial.print (x) | |
#else | |
#define DEBUG_PRINT(x) | |
#endif | |
#include <LowPower.h> | |
#define SPEAKER_OFF LOW // what determines speaker off, PNP / NPN transitor on powered PIEZO's | |
#define LED_N_SIDE 0 // negative terminal of LED | |
#define LED_P_SIDE 2 // positive terminal of LED | |
#define SPEAKER 4 // speaker pin | |
#define CHIRPFREQ 128 // chirp freq of square wave | |
#define LEDPIN 13 | |
// tunables | |
#define SONGMIN 3 // 3 seconds | |
#define SONGMAX 5 // 5 seconds | |
// time between songs | |
#define SLEEPMIN 450 // seconds to sleep divided by 8 | |
#define SLEEPMAX 675 // seconds to sleep divided by 8 | |
unsigned long MIN_REST_BETWEEN_CHIRPS = SLEEPMIN * 8 * 1000; // over-chirp protection | |
#define NIGHTSONG true // sing at night | |
#define DAYSONG true // sing at day | |
#define NUMSONGS 3 // number of songs before shutting up for the night / day | |
// some vars | |
long sleepTime; //place to store nap time between songs | |
unsigned long lastSongTime = 0; // just so we remember when we last sang | |
int songsSung = 0; // counter for songs sung since last transition | |
int x = 0; | |
bool daytime = false; // set the initial mode to night | |
// A chirp chip is composed of a few mS of 2.9kHz carrier. | |
void pulse(int duration) | |
{ | |
unsigned long term = millis() + duration; | |
while ( millis() < term) | |
{ | |
pinMode( SPEAKER, OUTPUT); | |
digitalWrite( SPEAKER, HIGH ); | |
delayMicroseconds( CHIRPFREQ ); | |
pinMode( SPEAKER, INPUT); | |
digitalWrite( SPEAKER, LOW ); | |
delayMicroseconds( CHIRPFREQ ); | |
} | |
} | |
// chipA is a two-pulse construct. | |
void chipA() | |
{ | |
pulse( 10 ); | |
delay( 6 ); | |
pulse( 13 ); // last pulse in a chip is longer than other pulses | |
delay( 9 ); // include a few extra mS for delay between chips | |
} | |
// chipB is a three-pulse construct. | |
void chipB() | |
{ | |
pulse( 10 ); | |
delay( 6 ); | |
pulse( 10 ); | |
delay( 6 ); | |
pulse( 13 ); // last pulse in a chip is longer than other pulses | |
delay( 9 ); // include a few extra mS for delay between chips | |
} | |
// chirp1 is a chip sequence of A,B | |
void chirp1() | |
{ | |
DEBUG_PRINT("chirp1\n"); | |
chipA(); | |
chipB(); | |
} | |
// chirp2 is a chip sequence of A,B,B | |
void chirp2() | |
{ | |
DEBUG_PRINT("chirp2\n"); | |
chipA(); | |
// return early once in a while | |
if (random(100)>2) | |
{ | |
chipB(); | |
chipB(); | |
} | |
} | |
// The chirp rate depends on temperature. The temperature in | |
// degees F is equal to the number of chirps in 13 seconds, plus 40. | |
// Chirp rate variation can be approximated by adjusting the delay | |
// between chirps. | |
int findChirpDelay( int temp) | |
{ | |
int temp_delay[] = { // temperature to delay map | |
50, 1300, 52, 1083, 54, 929, 56, 812, 58, 722, | |
60, 650, 62, 590, 64, 541, 66, 500, 68, 464, | |
70, 433, 72, 406, 74, 382, 76, 361, 78, 342, | |
80, 325, 82, 309, 84, 295, 86, 282, 88, 271, | |
90, 260, 92, 250, 94, 241, 96, 232, 98, 224, | |
}; | |
int i; | |
for (i=0; i<48; i+=2) | |
{ | |
if (temp <= temp_delay[i]) | |
break; | |
} | |
return temp_delay[i+1]; | |
} | |
// A song is a long sequence of chirps, about a minute. | |
// The number of chirps will vary depending on the chirpDelay | |
// and the length of the song. | |
void song(long songLength) | |
{ | |
// if we havnt sung for at least SLEEPMIN | |
DEBUG_PRINT("\nMIN_REST_BETWEEN_CHIRPS: "); | |
DEBUG_PRINT(MIN_REST_BETWEEN_CHIRPS); | |
if ( millis() >= (lastSongTime + MIN_REST_BETWEEN_CHIRPS) && (songsSung <= NUMSONGS) || (lastSongTime == 0)) { | |
DEBUG_PRINT("\nSinging. lastSongTime: "); | |
DEBUG_PRINT(lastSongTime); | |
DEBUG_PRINT(" and songsSung: "); | |
DEBUG_PRINT(songsSung); | |
DEBUG_PRINT(" and MIN_REST_BETWEEN_CHIRPS = "); | |
DEBUG_PRINT(MIN_REST_BETWEEN_CHIRPS); | |
lastSongTime = millis(); | |
songsSung++; | |
int chirpDelay = findChirpDelay(random(50,98)); | |
DEBUG_PRINT("\nchirp delay: "); | |
DEBUG_PRINT(chirpDelay); | |
int chirpCount = songLength / ( chirpDelay + 50 ); | |
for (int i=0; i < chirpCount; i++) | |
{ | |
if (random(100) < 5) | |
chirp1(); | |
else | |
chirp2(); | |
delay( chirpDelay ); | |
} | |
} else { | |
DEBUG_PRINT("\nNOT singing. lastSongTime: "); | |
DEBUG_PRINT(lastSongTime); | |
DEBUG_PRINT(" and songsSung: "); | |
DEBUG_PRINT(songsSung); | |
DEBUG_PRINT(" and next singtime should be after "); | |
DEBUG_PRINT(millis() + MIN_REST_BETWEEN_CHIRPS); | |
} | |
} | |
void setup () | |
{ | |
#ifdef DEBUG | |
Serial.begin(9600); | |
#endif | |
randomSeed(analogRead(9)); | |
pinMode(SPEAKER, OUTPUT); | |
digitalWrite(SPEAKER, LOW); | |
delay(5000); | |
} | |
void primeLightSensor() { | |
// charges the LED so we can monitor the power drain in loop() | |
pinMode(LED_N_SIDE,OUTPUT); | |
pinMode(LED_P_SIDE,OUTPUT); | |
digitalWrite(LED_N_SIDE,HIGH); | |
digitalWrite(LED_P_SIDE,LOW); | |
// Isolate the pin 2 end of the diode | |
pinMode(LED_N_SIDE,INPUT); | |
digitalWrite(LED_N_SIDE,LOW); // turn off internal pull-up resistor | |
} | |
void shutdownSpeaker() { | |
digitalWrite(SPEAKER, SPEAKER_OFF); // shut off speaker | |
} | |
void loop () | |
{ | |
// sing a song! | |
if (!daytime && NIGHTSONG) { | |
song ( random(SONGMIN, SONGMAX) * 1000 ); | |
} | |
if (daytime && DAYSONG) { | |
song ( random(SONGMIN, SONGMAX) * 1000 ); | |
} | |
shutdownSpeaker(); | |
sleepTime = random(SLEEPMIN, SLEEPMAX); // 1h to 1h30 sleep | |
DEBUG_PRINT("\nSleeping: "); | |
DEBUG_PRINT(sleepTime*8*1000); | |
// charge the LED cap | |
primeLightSensor(); | |
// powernap | |
for (x = 0; x < sleepTime; x++) { | |
primeLightSensor(); // always prime before nap | |
#ifdef DEBUG | |
delay(8000); | |
#else | |
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); | |
#endif | |
// save old state to determine if transition has occured | |
bool oldDaytime = daytime; | |
// the LED cap will be drained ifs "day", so if its NOT drained, it means its dark! | |
if ( !digitalRead(LED_N_SIDE)==0) { | |
daytime = false; | |
} else { | |
daytime = true; | |
} | |
if (daytime) { | |
digitalWrite(LEDPIN, LOW); | |
if (DAYSONG) { | |
if (oldDaytime != daytime) { | |
DEBUG_PRINT("\na transistion to DAY has occured"); | |
songsSung=0; // reset songsSung | |
break; | |
} | |
} | |
} else { | |
digitalWrite(LEDPIN, HIGH); | |
if (NIGHTSONG) { | |
// sing a song on transition | |
if (oldDaytime != daytime) { | |
DEBUG_PRINT("\na transistion to NIGHT has occured"); | |
songsSung=0; // reset songsSung | |
break; | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment