I have a setup with an Arduino Pro Mini, a DS1307 RTC, a microSD shield and a microswitch. I've set an interrupt to the microswitch, so it'll wake up the Arduino when it changes status. Here is some relevant code:
void setup() {
rtc.begin();
pinMode(button, INPUT);
SD.begin(chipSelect);
/*Omitted the same write to file as in button_ISR()*/
}
void loop() {
delay(5000);
goToSleep();
}
void goToSleep() {
sleep_enable();
attachInterrupt(digitalPinToInterrupt(button), button_ISR, CHANGE);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
delay(500);
sleep_cpu();
}
void button_ISR() {
sleep_disable();
detachInterrupt(0);
rtc.begin();
String data = (digitalRead(button))?"OPEN":"CLOSE";
File dataFile = SD.open("datalog.txt", FILE_WRITE);
if(dataFile) {
DateTime now = rtc.now();
dataFile.print(now.year(), DEC);
dataFile.print('.');
dataFile.print(now.month(), DEC);
dataFile.print('.');
dataFile.print(now.day(), DEC);
dataFile.print(". (");
dataFile.print(daysOfTheWeek[now.dayOfTheWeek()]);
dataFile.print(") ");
dataFile.print(now.hour(), DEC);
dataFile.print(":");
dataFile.print(now.minute(), DEC);
dataFile.print(":");
dataFile.print(now.second(), DEC);
dataFile.print(";");
dataFile.println(data);
dataFile.close();
}
delay(1000);
}
If I don't call rtc.now(), and omit the DateTime prints, the code perfectly writes "OPEN" and "CLOSE" in the txt. I have the same dateTime writing inside the setup(), with "START", and it perfectly writes the current date/time.
What am I missing? How could I get the time from RTC after wake up?
1 Answer 1
You should not delay in an ISR, for two reasons:
Interrupts are disabled while the ISR runs, and
delay()
relies on interrupts.Interrupts are used to handle time-critical tasks. The longer the interrupts are disabled, the larger the chances that one of those time-critical tasks is handled too late. Thus, ISRs should execute as fast as possible.
In this particular case, if we try to make the ISR as short as possible, the optimal version is this:
void button_ISR() {}
Since the interrupt is meant to wake up the Arduino, and nothing more,
everything the ISR does can be done at wake-up, right after
sleep_cpu();
.
A few more comments and suggestions:
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
can be done once and for all insetup()
instead combining
sleep_enable()
,sleep_cpu()
andsleep_disable()
, you can use a single call tosleep_mode()
you most probably do not need to reinitialize the RTC and re-open the file at every loop iteration: do this only once, in
setup()
String
objects are not friendly to a small Arduino's memory; in this case you can get rid of them by simply replacing the wordString
withconst char *
if you are using RTClib, you may want to use the
DateTime::toString()
method, which can make your code shorter and simpler.
sleep_cpu();
.