I am currently trying to develop code for a Mayfly Datalogger. I’d like the unit to (1) Wake up every X minutes, check the time and record data if the time is a particular multiple; and (2) have a ‘watchdog’ that where the unit will reset if no reading has been taken in Y minutes, for example.
I’ve gotten both of these pieces of code to work individually, but they don’t seem to work when I combine them. If I comment out the Watchdogsetup() (line 40), the timer works fine. But I can’t get them to work together. I suspect it has something to do with conflicted settings.
This is Frankenstein code, so I don’t know 100% of what is going on for each. Any advice on getting this to work. A second issue I’m having is that the code will only awake every 1 minute, not every X minutes as defined by RTC_INT_PERIOD (line 12), but this is less important.
#include <avr/sleep.h> //
#include <avr/wdt.h>
#include <RTCTimer.h>
#include <Sodaq_DS3231.h>
#include <Sodaq_PcInt.h>
#define DEBUG // comment out after debugging is complete to disable DEBUG SERIAL
//RTC Interrupt pin
#define RTC_INT_PIN A7
#define RTC_INT_UNITS EveryMinute // wake up every X seconds
#define RTC_INT_PERIOD 2 // wake up every 20 seconds
//Initalize RTC
RTCTimer timer; // Real-time clock
int frequency = 2; // Take measurements every 2 minutes, upon waking
unsigned long TIMEOUT_PERIOD = 90000; // in milliseconds, must be <49 days
int currentminute;
long currentepochtime = 0;
unsigned long resetTime = 0;
#define doggieTickle() resetTime = millis(); // This macro will reset the timer
// Setup debug-specific Serial printing, these functions only compiles if DEBUG is defined, above
#ifdef DEBUG
#define DEBUG_PRINTLN(x) Serial.println (x)
#define DEBUG_PRINT(x) Serial.print (x)
#else
#define DEBUG_PRINTLN(x)
#define DEBUG_PRINT(x)
#endif
void setup()
{
//Initialize real time clock and I2C connection
Serial.begin(9600);
rtc.begin(); // real time clock
watchdogSetup();
setupTimer(); //Setup timer events
setupSleep(); //Setup sleep mode
}
void loop()
{
//Update the timer
timer.update();
DEBUG_PRINTLN("Waking up, checking time.");
String wakeup_time = getDateTime();
DEBUG_PRINTLN(wakeup_time);
if (currentminute % frequency == 0) // wake up at intervals of frequency minutes
{
//Script to capture and record data will happen here.
DEBUG_PRINTLN("* Data recording will occur here: ");
//If readings are good, then reset watchdog timer
//doggieTickle(); // keeping commented away so force reset.
}
//Sleep
DEBUG_PRINTLN("Going to sleep minute.");
systemSleep();
}
void showTime(uint32_t ts)
{
//Retrieve and display the current date/time
String dateTime = getDateTime();
}
//Timer wakes up every period to check time
void setupTimer()
{
//Schedule the wakeup every minute
timer.every(RTC_INT_PERIOD, showTime);
//Instruct the RTCTimer how to get the current time reading
timer.setNowCallback(getNow);
}
void wakeISR()
{
//Leave this blank
}
void setupSleep()
{
pinMode(RTC_INT_PIN, INPUT_PULLUP);
PcInt::attachInterrupt(A7, wakeISR);
//Setup the RTC in interrupt mode
rtc.enableInterrupts(RTC_INT_UNITS);
//Set the sleep mode
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
}
void systemSleep()
{
//Wait until the serial ports have finished transmitting
Serial.flush();
//The next timed interrupt will not be sent until this is cleared
rtc.clearINTStatus();
//Disable ADC
ADCSRA &= ~_BV(ADEN);
//Sleep time
noInterrupts();
sleep_enable();
interrupts();
sleep_cpu();
sleep_disable();
//Enbale ADC
ADCSRA |= _BV(ADEN);
}
String getDateTime()
{
String dateTimeStr;
//Create a DateTime object from the current time
DateTime dt(rtc.makeDateTime(rtc.now().getEpoch()));
currentepochtime = (dt.get()); //Unix time in seconds
currentminute = (dt.minute());
//Convert it to a String
dt.addToString(dateTimeStr);
return dateTimeStr;
}
uint32_t getNow()
{
currentepochtime = rtc.now().getEpoch();
return currentepochtime;
}
void(* resetFunc) (void) = 0; //declare reset function @ address 0
void watchdogSetup()
{
cli(); // disable all interrupts
wdt_reset(); // reset the WDT timer
MCUSR &= ~(1 << WDRF); // because the data sheet said to
/*
WDTCSR configuration:
WDIE = 1 :Interrupt Enable
WDE = 1 :Reset Enable - I won't be using this on the 2560
WDP3 = 0 :For 1000ms Time-out
WDP2 = 1 :bit pattern is
WDP1 = 1 :0110 change this for a different
WDP0 = 0 :timeout period.
*/
// Enter Watchdog Configuration mode:
WDTCSR = (1 << WDCE) | (1 << WDE);
// Set Watchdog settings: interrupte enable, 0110 for timer
WDTCSR = (1 << WDIE) | (0 << WDP3) | (1 << WDP2) | (1 << WDP1) | (0 << WDP0);
sei();
}
ISR(WDT_vect) // Watchdog timer interrupt.
{
if (millis() - resetTime > TIMEOUT_PERIOD) {
DEBUG_PRINTLN("REBOOTING");
resetFunc(); // This will call location zero and cause a reboot.
}
}