/* * Open and close the door on the chicken house depending on the * ambient light levels. * Copyright Alex Tucker 2013 * */ // Enable deep sleep with wake on watchdog interrupt. // Based on Donal Morrissey's code at http://donalmorrissey.blogspot.co.uk/2010/04/sleeping-arduino-part-5-wake-up-via.html #include <avr/sleep.h> #include <avr/power.h> #include <avr/wdt.h> volatile int f_wdt=1; ISR(WDT_vect) { if (f_wdt == 0) { f_wdt=1; } } void enterSleep(void) { set_sleep_mode(SLEEP_MODE_PWR_DOWN); /* PWR_SAVE or PWR_DOWN */ sleep_enable(); sleep_mode(); /* The program will continue from here after the WDT timeout*/ sleep_disable(); /* First thing to do is disable sleep. */ /* Re-enable the peripherals. */ power_all_enable(); // delay(8000); // f_wdt = 1; } #define ONOFF_PIN 5 #define FWREV_PIN 3 #define DOOR_CONTACT_PIN 4 #define BUTTON_PIN 2 #define PHOTOCELL_PIN 0 #define INITIALIZE 0 #define WAIT_FOR_LIGHT 1 #define LOWER_DOOR 2 #define WAIT_FOR_DARK 3 #define RAISE_DOOR 4 #define BRIGHTNESS_SIZE 3 #define BRIGHT_THRESHOLD 800 #define OPEN_DELAY 6250 word brightness[BRIGHTNESS_SIZE]; int state = WAIT_FOR_LIGHT; void setupWDT() { /* Clear the reset flag. */ MCUSR &= ~(1<<WDRF); /* In order to change WDE or the prescaler, we need to * set WDCE (This will allow updates for 4 clock cycles). */ WDTCSR |= (1<<WDCE) | (1<<WDE); /* set new watchdog timeout prescaler value */ WDTCSR = 1<<WDP0 | 1<<WDP3; /* 8.0 seconds */ /* Enable the WD interrupt (note no reset). */ WDTCSR |= _BV(WDIE); } void setup() { pinMode(ONOFF_PIN, OUTPUT); pinMode(FWREV_PIN, OUTPUT); pinMode(DOOR_CONTACT_PIN, INPUT); pinMode(BUTTON_PIN, INPUT); digitalWrite(ONOFF_PIN, LOW); digitalWrite(FWREV_PIN, LOW); // Serial.begin(9600); state = INITIALIZE; word currentBrightness = analogRead(PHOTOCELL_PIN); for (int i = 0; i < BRIGHTNESS_SIZE; i++) { brightness[i] = currentBrightness; } setupWDT(); } void raiseDoor() { digitalWrite(FWREV_PIN, LOW); delay(10); digitalWrite(ONOFF_PIN, HIGH); while (digitalRead(DOOR_CONTACT_PIN) == LOW) { delay(100); } digitalWrite(ONOFF_PIN, LOW); delay(10); } void lowerDoor() { digitalWrite(FWREV_PIN, HIGH); delay(10); digitalWrite(ONOFF_PIN, HIGH); delay(OPEN_DELAY); digitalWrite(ONOFF_PIN, LOW); delay(10); digitalWrite(FWREV_PIN, LOW); } word readBrightness() { word currentBrightness = analogRead(PHOTOCELL_PIN); unsigned long total = brightness[0]; for (int i = 0; i < BRIGHTNESS_SIZE; i++) { if (i == (BRIGHTNESS_SIZE - 1)) { brightness[i] = analogRead(PHOTOCELL_PIN); } else { brightness[i] = brightness[i+1]; } total += brightness[i]; } word avg = total / (BRIGHTNESS_SIZE + 1); /* Serial.begin(9600); Serial.print("Brightness, avg: "); Serial.print(avg); Serial.print(", current: "); Serial.print(currentBrightness); Serial.print("\n"); */ return avg; } void loop() { if (f_wdt == 1) { f_wdt = 0; switch (state) { case INITIALIZE: if (digitalRead(DOOR_CONTACT_PIN) == LOW) { raiseDoor(); } state = WAIT_FOR_LIGHT; break; case WAIT_FOR_LIGHT: if (readBrightness() > BRIGHT_THRESHOLD) { state = LOWER_DOOR; } break; case LOWER_DOOR: lowerDoor(); state = WAIT_FOR_DARK; break; case WAIT_FOR_DARK: if (readBrightness() < BRIGHT_THRESHOLD) { state = RAISE_DOOR; } break; case RAISE_DOOR: raiseDoor(); state = WAIT_FOR_LIGHT; break; } enterSleep(); } }