Как получить время от RTC после пробуждения от сна?

У меня есть настройка с Arduino Pro Mini, DS1307 RTC, microSD shield и микропереключателем. Я установил прерывание на микропереключатель, так что он разбудит Arduino, когда он изменит состояние. Вот некоторый соответствующий код:

void setup() {
  rtc.begin();
  pinMode(button, INPUT);
  SD.begin(chipSelect);

  /*Опущена та же запись в файл, что и в 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);
}

Если я не вызову rtc.now () и опущу печать DateTime, код отлично запишет "OPEN" и "CLOSE" в txt. У меня есть такая же запись DateTime внутри setup(), с "START", и она отлично записывает текущую дату/время.

Что я упускаю? Как я могу получить время от RTC после пробуждения?

, 👍1

Обсуждение

Вы не должны спать в ISR. Вы также не должны писать в файл. На самом деле, лучшее, что вы можете сделать, это оставить ISR пустым и переместить все его содержимое сразу после sleep_cpu();., @Edgar Bonet

@EdgarBonet да, это было решение :) Если вы дадите мне ответ, я его приму. Спасибо!, @Rothens


1 ответ


Лучший ответ:

2

Вы не должны задерживаться в ISR по двум причинам:

  1. Прерывания отключаются во время работы ISR, а функция delay() полагается на прерывания.

  2. Прерывания используются для обработки критичных по времени задач. Чем дольше прерывания отключены, тем больше вероятность того, что одна из этих критичных по времени задач будет обработана слишком поздно. Таким образом, ISR должны выполняться как можно быстрее.

В данном конкретном случае, если мы попытаемся сделать ISR как можно короче, оптимальным вариантом будет следующий:

void button_ISR() {}

Поскольку прерывание предназначено для пробуждения Arduino, и ничего больше, все, что делает ISR, может быть сделано при пробуждении, сразу после sleep_cpu();.

Еще несколько замечаний и предложений:

  • set_sleep_mode(SLEEP_MODE_PWR_DOWN); может быть сделано раз и навсегда в setup()

  • вместо объединения sleep_enable(), sleep_cpu() и sleep_disable ()вы можете использовать один вызов sleep_mode ().

  • скорее всего, вам не нужно повторно инициализировать RTC и повторно открывать файл на каждой итерации цикла: сделайте это только один раз, в setup()

  • Строковые объекты не дружелюбны к памяти небольшого Arduino; в этом случае вы можете избавиться от них, просто заменив слово String с const char *

  • если вы используете RTClib, вы можете использовать Метод DateTime::toString(), который может сделать ваш код короче и проще.

,