Arduino с прерываниями переходит в состояние блокировки

Я совершенно не разбираюсь в использовании прерываний на Arduino, и я столкнулся со странной проблемой. Я использую Arduino Pro Mini, датчик освещенности и модуль RTC (DS3231), который установил 2 будильника, один на восходе солнца и один на закате. Каждый раз, когда DST запускает сигнал тревоги, процедура прерывания (здесь onAlarm() ) блокирует состояние Arduino, и там ничего не происходит. Есть ли что-то неправильное в коде, который я пишу?

Приведенный ниже код немного упрощен, я просто разрешаю вызовы методов, а не их полные объявления.

#include <avr/sleep.h>//эта библиотека AVR содержит методы, управляющие режимами ожидания
#include <avr/power.h>
#include <DS3232RTC.h>  //Библиотеку RTC https://github.com/JChristensen/DS3232RTC

#define ldrInterruptPin  2
#define DS2331interruptPin 3

void setup() {

  Serial.begin(9600);//Начать последовательную связь
  Wire.begin();

  //_____________________ настройка прерываний DS3231_________
  pinMode(DS2331interruptPin, INPUT_PULLUP);
  digitalWrite(DS2331interruptPin, HIGH);
  attachInterrupt(digitalPinToInterrupt(DS2331interruptPin), onAlarm, FALLING);

  //_____________________ прерывания настройки LD235R_________
  pinMode(ldrInterruptPin, INPUT);
  digitalWrite(ldrInterruptPin, HIGH);
  attachInterrupt(digitalPinToInterrupt(ldrInterruptPin), irq1, RISING);

  resetDS3231Alarms();

  time_t t = RTC.get();
  setUpAlarms();
}

void loop() {
 //считывание показаний датчика освещенности vlaues 
}

Вопог это функция onAlarm:

  void onAlarm() {
  Serial.println("ALARM");
  formatTime(timestamp, RTC.get());
  if (RTC.alarm(ALARM_1))
  {
    Serial << F("SLEEP alarm at ") << timestamp << endl;
    goToSleep();
  }
  else if (RTC.alarm(ALARM_2))
  {
    Serial << F("WakeUP Alarm at ") << timestamp << endl;

    Serial.println("Time to Wake up......!");
    sleep_disable();
    Serial.println("I woke up!!!");
    attachInterrupt(digitalPinToInterrupt(ldrInterruptPin), irq1, RISING);
  }
  // обновить время сна и пробуждения на основе текущего дня
  setUpAlarms();
};

Сброс настроек ()

void resetDS3231Alarms() {
  // инициализируйте аварийные сигналы известными значениями, снимите флаги аварийных сигналов, снимите флаги прерывания аварийных сигналов
  RTC.setAlarm(ALM1_MATCH_DATE, 0, 0, 0, 1);
  RTC.setAlarm(ALM2_MATCH_DATE, 0, 0, 0, 1);
  RTC.alarm(ALARM_1);
  RTC.alarm(ALARM_2);
  RTC.alarmInterrupt(ALARM_1, false);
  RTC.alarmInterrupt(ALARM_2, false);
  RTC.squareWave(SQWAVE_NONE);
}

Каждый раз, когда возникает сигнал тревоги, код блокируется и выводит именно то, что указано в описании захвата последовательного монитора ниже: Он просто печатает "AL" из Serial.println("ALARM"); и оттуда ничего не происходит

Кто-нибудь знает, что вызывает эту проблему и как ее можно решить?

, 👍2

Обсуждение

Никогда не используйте Последовательный в прерывании. Он сам полагается на прерывание, чего не может произойти, потому что выполняется ваше прерывание., @Majenko

Я удалил все серийные отпечатки, и проблема все еще присутствует. В методе onAlarm() ничего не выполняется, и код зависает, @Emanuel Giurgiu

Возможно, вы вызываете функцию, которая сама вызывает delay(). Это тоже сломается. Прерывания должны быть абсолютным минимумом, с которым вы можете справиться - в идеале просто установите флаг, а затем проверьте этот флаг в loop (), чтобы выполнить свою реальную работу. Прерывание фиксирует событие, но не выполняет всю работу., @Majenko


1 ответ


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

2

Когда процессор AVR переходит в спящий режим, единственный способ, которым он может проснуться , - это прерывание. Если он перейдет в спящий режим с отключенными прерываниями, то он никогда не проснется.

Процедуры прерывания по умолчанию не прерываются: первое , что делает процессор при обслуживании прерывания, - это отключает дальнейшие прерывания. Таким образом, ваша функция onAlarm() выполняется с отключенными прерываниями. Если он перейдет в спящий режим, он заблокирует процессор.

Быстрым и грязным решением было бы вызвать функцию interrupts() прямо перед сном . Однако я бы не рекомендовал этого делать, так как в конечном итоге вы будете накладывать контексты прерывания один на другой. Правильным решением было бы сократить ваши процедуры обслуживания прерываний до минимума, который должен быть выполнен немедленно, и обрабатывать все остальное в обычном коде в пределах loop(). В данном конкретном случае установка volatile bool вполне может быть единственным, что вам действительно нужно сделать. Ваш цикл () проверит этот bool и позаботится обо всем остальном.

,

Такс, это работает с обоими вариантами, которые вы дали, но я выбрал тот, у которого есть bool, @Emanuel Giurgiu