1

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?

2
  • 2
    You should not sleep in an ISR. You should not write to a file either. Actually, the best you can do is leave the ISR empty, and move all its contents to right after sleep_cpu();. Jun 17 at 9:36
  • 1
    @EdgarBonet yup, this was the solution :) If you make it an answer, I'll accept it. Thanks!
    – Rothens
    Jun 17 at 9:59
2

You should not delay in an ISR, for two reasons:

  1. Interrupts are disabled while the ISR runs, and delay() relies on interrupts.

  2. 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 in setup()

  • instead combining sleep_enable(), sleep_cpu() and sleep_disable(), you can use a single call to sleep_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 word String with const char *

  • if you are using RTClib, you may want to use the DateTime::toString() method, which can make your code shorter and simpler.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.