Skip to content

Instantly share code, notes, and snippets.

@unixunion
Last active August 29, 2015 14:17
Show Gist options
  • Save unixunion/ee6451da44a56a5f9959 to your computer and use it in GitHub Desktop.
Save unixunion/ee6451da44a56a5f9959 to your computer and use it in GitHub Desktop.
Jeremy Cricket Day / Night edition
/*
_____ _ _ _ ____ _____
/ ____| (_) | | | | / __ \ / ____|
| | _ __ _ ___| | _____| |_| | | | (___
| | | '__| |/ __| |/ / _ \ __| | | |\___ \
| |____| | | | (__| < __/ |_| |__| |____) |
\_____|_| |_|\___|_|\_\___|\__|\____/|_____/ 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