#include <DS3232RTC.h> //http://github.com/JChristensen/DS3232RTC #include <Time.h> //http://playground.arduino.cc/Code/Time #include <TinyWireM.h> //https://github.com/adafruit/TinyWireM #include <Narcoleptic.h> //https://code.google.com/p/narcoleptic/ //The library was modified for ATTiny85 as described here: //http://www.willowdesign.info/blog/digistump-cricket-generator/ const int Note_D = 213; const int Note_G = 159; const int Note_A = 142; const int Note_B = 127; const int Speaker = 1; const int feedPin = 1; const int RTCPowerPin = 4; const int motorPin = 3; const int MAX_FEED_TURN = 2; //Dispenced food volume int feedCounter = 0; // counter for the number of feed revolution int feedState = HIGH; // current state of the feed contacts int lastFeedState = HIGH; // previous state of the feed contacts int reading = HIGH; long lastDebounceTime = 0; // the last time the output pin was toggled long debounceDelay = 20; // the debounce time; increase if the output flickers void setup(void) { pinMode(RTCPowerPin, OUTPUT); digitalWrite(RTCPowerPin, HIGH); RTC.squareWave(SQWAVE_NONE); setSyncProvider(RTC.get); //set the system time to 17h 35m on 22 March 2015 //setTime(17, 35, 0, 22, 3, 2015); //RTC.set(now()); pinMode(motorPin, OUTPUT); digitalWrite(motorPin, LOW); // initialize the feed contact pin as a input: pinMode(feedPin, INPUT); } void loop(void) { digitalWrite(motorPin, LOW); digitalWrite(RTCPowerPin, HIGH); //Turn RTC power ON delay(50); //ensure RTC is stable after powering it ON RTC.setAlarm(ALM1_MATCH_HOURS, 0, 0, 7, 0); //morning feed alarm RTC.setAlarm(ALM2_MATCH_HOURS, 0, 0, 19, 0); //evening feed alarm digitalWrite(RTCPowerPin, LOW); //Turn RTC power OFF digitalWrite(Speaker, LOW); Narcoleptic.delay(20000); // During this time power consumption is minimized digitalWrite(RTCPowerPin, HIGH); if (readVcc() < 3500) { playBatteryLow(); } delay(50); //ensure RTC is stable after powering it ON if (RTC.alarm(ALARM_1) || RTC.alarm(ALARM_2)) { //has any of 2 Alarm1s triggered? //yes, act on the alarm // Wake up CPU. feedCounter = 0; // Wake up the CAT - play some music playTune(); // Turn ON food dispenser motor digitalWrite(motorPin, HIGH); while (feedCounter < MAX_FEED_TURN) { // read the feed input pin: reading = digitalRead(feedPin); // compare the feedState to its previous state if (reading != lastFeedState) { // reset the debouncing timer lastDebounceTime = millis(); } if ((millis() - lastDebounceTime) > debounceDelay) { if (reading != feedState) { feedState = reading; // if the state has changed, increment the counter if (feedState == HIGH) { // if the current state is HIGH then the feed contacts // went from on to off feedCounter++; } else { // if the current state is HIGH then the feed contact // went from on to off: } } } // save the current state as the last state, //for next time through the loop lastFeedState = reading; } } } void TinyTone(unsigned char divisor, unsigned char octave, unsigned long duration) { //http://www.technoblogy.com/show?KVO //TCCR1 = 0x90 | (8-octave); // for 1MHz clock TCCR1 = 0x90 | (11 - octave); // for 8MHz clock OCR1C = divisor - 1; // set the OCR delay(duration); TCCR1 = 0x90; // stop the counter delay(duration * 1.30); // pause between notes } void playTune(void) { pinMode(Speaker, OUTPUT); TinyTone(Note_D, 4, 125); TinyTone(Note_D, 4, 125); TinyTone(Note_G, 4, 250); TinyTone(Note_G, 4, 200); TinyTone(Note_G, 4, 62); TinyTone(Note_A, 4, 250); TinyTone(Note_A, 4, 200); TinyTone(Note_A, 4, 62); TinyTone(Note_D, 5, 350); TinyTone(Note_B, 4, 150); TinyTone(Note_G, 4, 300); delay(350); TinyTone(Note_D, 5, 500); delay(200); TinyTone(Note_D, 5, 500); delay(200); TinyTone(Note_D, 5, 500); delay(200); TinyTone(Note_D, 6, 1000); TCCR1 = 0; // stop the timer pinMode(Speaker, INPUT); } void playBatteryLow(void) { pinMode(Speaker, OUTPUT); TinyTone(Note_D, 4, 125); TinyTone(Note_D, 6, 250); TCCR1 = 0; // stop the timer pinMode(Speaker, INPUT); } long readVcc() { //http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/ // Read 1.1V reference against AVcc // set the reference to Vcc and the measurement to the internal 1.1V reference // #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) // ADMUX = _BV(MUX5) | _BV(MUX0); // #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) ADMUX = _BV(MUX3) | _BV(MUX2); // #else // ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // #endif delay(2); // Wait for Vref to settle ADCSRA |= _BV(ADSC); // Start conversion while (bit_is_set(ADCSRA, ADSC)); // measuring uint8_t low = ADCL; // must read ADCL first - it then locks ADCH uint8_t high = ADCH; // unlocks both long result = (high << 8) | low; result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 return result; // Vcc in millivolts }