I'm trying to make a battery operated bird feeder for a friend in Texas. I have the servo for the door/hatch working and the electronics are all doing what I want, the only issue I am running into is setting up the alarm on my ds3231 to actually go off at a specific time each day.
I recognize that there are some extraneous bits in there as I am basically just following various tutorials and it looks like a Frankenstein's monster but I hope I can get some help figuring out the last bit of code I need so I can package everything up and get it postmarked.
#include "Arduino_DS3231_Wakeup.h"
#include "Arduino.h"
#include <avr/sleep.h>
#include <config.h>
#include <ds3231.h>
#include <Wire.h>
#include <Servo.h>
#define sleepPin 4 // When low, makes 328P go to sleep
#define wakePin 3 // when low, makes 328P wake up, must be an interrupt pin (2 or 3 on ATMEGA328P)
#define ledPin 2 // output pin for the LED (to show it is awake)
int led = 13;
Servo myservo;// create servo object to control a servo
// twelve servo objects can be created on most boards
int pos = 0; // variable to store the servo position
int startPos = 80;
int openAngle = startPos-30;
// DS3231 alarm time
uint8_t wake_HOUR;
uint8_t wake_MINUTE;
uint8_t wake_SECOND;
uint8_t wake_DAY;
#define BUFF_MAX 256
///* A struct is a structure of logical variables used as a complete unit
// struct ts {
// uint8_t sec; /* seconds */
// uint8_t min; /* minutes */
// uint8_t hour; /* hours */
// uint8_t mday; /* day of the month */
// uint8_t mon; /* month */
// int16_t year; /* year */
// uint8_t wday; /* day of the week */
// uint8_t yday; /* day in the year */
// uint8_t isdst; /* daylight saving time */
// uint8_t year_s; /* year in short notation*/
//#ifdef CONFIG_UNIXTIME
// uint32_t unixtime; /* seconds since 01.01.1970 00:00:00 UTC*/
//#endif
//};
struct ts t;
void setup() {
Serial.begin(9600);
Serial.println("Setup started");
// Latch the power
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
//attach servo to its pin location
myservo.attach(9);
// Clear the current alarm (puts DS3231 INT high)
Wire.begin();
DS3231_init(DS3231_CONTROL_INTCN);
DS3231_clear_a1f();
// Set date/time if not already set
// DS3231_get(&t);
//
// if (t.year < 2021)
// {
// t.sec = 0;
// t.min = 32;
// t.hour = 11;
// t.mday = 1;
// t.mon = 12;
// t.year = 2020;
// DS3231_set(t);
// }
// Keep pins high until we ground them
pinMode(sleepPin, INPUT_PULLUP);
pinMode(wakePin, INPUT_PULLUP);
// Flashing LED just to show the µController is running
digitalWrite(ledPin, LOW);
pinMode(ledPin, OUTPUT);
pinMode(led,OUTPUT);
Serial.println("Setup completed.");
}
// The loop just blinks an LED when not in sleep mode
void loop() {
static uint8_t oldSec = 99;
char buff[BUFF_MAX];
// Just blink LED twice to show we're running
doBlink();
// Is the "go to sleep" pin now LOW?
if (digitalRead(sleepPin) == LOW) {
// Turn off L-LED
digitalWrite(led, LOW);
// Set the DS3231 alarm to wake up in X seconds
Serial.println("Setting alarm, switching off");
setNextAlarm();
delay(1000);
digitalWrite(13, LOW);
static byte prevADCSRA = ADCSRA;
ADCSRA = 0;
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
sleep_enable();
MCUCR = bit (BODS) | bit (BODSE);
// The BODS bit is automatically cleared after three clock cycles so we better get on with it
MCUCR = bit (BODS);
noInterrupts();
attachInterrupt(digitalPinToInterrupt(wakePin), sleepISR, LOW);
// Send a message just to show we are about to sleep
Serial.println("Good night!");
Serial.flush();
// Allow interrupts now
interrupts();
// And enter sleep mode as set above
sleep_cpu();
// --------------------------------------------------------
// µController is now asleep until woken up by an interrupt
// --------------------------------------------------------
// Wakes up at this point when wakePin is brought LOW - interrupt routine is run first
Serial.println("I'm awake!");
// Clear existing alarm so int pin goes high again
DS3231_clear_a1f();
// Re-enable ADC if it was previously running
ADCSRA = prevADCSRA;
//Turn back on L-LED
digitalWrite(led, HIGH);
DS3231_get(&t);
if (t.sec != oldSec)
{
// display current time
snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d\n", t.year,
t.mon, t.mday, t.hour, t.min, t.sec);
Serial.print(buff);
oldSec = t.sec;
}
//Write all the other code right here...
myservo.write(startPos);
delay(500);
for (pos = startPos; pos >= openAngle; pos -= 1) { // goes from 80 degrees to 50 degrees
// in steps of 1 degree
myservo.write(pos);
delay(10);
}
delay(400);
for (pos = openAngle; pos <= startPos; pos += 1)
{
myservo.write(pos);
delay(10);
}
delay(2000);
//delay(8000);
//digitalWrite(sleepPin, LOW);
}
else
{
//Get the time
DS3231_get(&t);
//If the seconds has changed, display the (new) time
if (t.sec != oldSec)
{
// display current time
snprintf(buff, BUFF_MAX, "%d.%02d.%02d %02d:%02d:%02d\n", t.year,
t.mon, t.mday, t.hour, t.min, t.sec);
Serial.print(buff);
oldSec = t.sec;
}
}
}
// When wakePin is brought LOW this interrupt is triggered FIRST (even in PWR_DOWN sleep)
void sleepISR() {
// Prevent sleep mode, so we don't enter it again, except deliberately, by code
sleep_disable();
// Detach the interrupt that brought us out of sleep
detachInterrupt(digitalPinToInterrupt(wakePin));
// Now we continue running the main Loop() just after we went to sleep
}
// Double blink just to show we are running. Note that we do NOT
// use the delay for final delay here, this is done by checking
// millis instead (non-blocking)
void doBlink() {
static unsigned long lastMillis = 0;
if (millis() > lastMillis + 2000) {
digitalWrite(ledPin, HIGH);
delay(10);
digitalWrite(ledPin, LOW);
delay(200);
digitalWrite(ledPin, HIGH);
delay(10);
digitalWrite(ledPin, LOW);
lastMillis = millis();
}
}
// Set the next alarm
void setNextAlarm(void)
{
// flags define what calendar component to be checked against the current time in order
// to trigger the alarm - see datasheet
// A1M1 (seconds) (0 to enable, 1 to disable)
// A1M2 (minutes) (0 to enable, 1 to disable)
// A1M3 (hour) (0 to enable, 1 to disable)
// A1M4 (day) (0 to enable, 1 to disable)
// DY/DT (dayofweek == 1/dayofmonth == 0)
uint8_t flags[5] = { 1, 0, 0, 0, 1 };
// get current time so we can calc the next alarm
DS3231_get(&t);
wake_SECOND = t.sec;
wake_MINUTE = t.min;
wake_HOUR = t.hour;
wake_DAY = t.mday;
// Add a some seconds to current time. If overflow increment minutes etc.
wake_SECOND = wake_SECOND + 10;
if (wake_SECOND > 59)
{
wake_MINUTE++;
wake_SECOND = wake_SECOND - 60;
if (wake_MINUTE > 59)
{
wake_HOUR++;
wake_MINUTE -= 60;
if (wake_HOUR > 23)
{
wake_DAY++;
wake_HOUR -= 24;
}
}
}
// Set the alarm time (but not yet activated)
DS3231_set_a1(wake_SECOND, wake_MINUTE, wake_HOUR, wake_DAY, flags);
// Turn the alarm on
DS3231_set_creg(DS3231_CONTROL_INTCN | DS3231_CONTROL_A1IE);
}