Как отключить, а затем снова включить прерывание сторожевого таймера для Arduino?

Я пытаюсь использовать прерывание сторожевого таймера в качестве таймера для сна в течение определенного времени с моим Arduino. Моя проблема заключается в том, что при пробуждении мне нужно проводить операции, которые занимают более 8 секунд.

В настоящее время мой Arduino будет спать в течение 1 минуты, используя последовательные прерывания сторожевого таймера, чтобы разбудить его и вернуть в сон. Однако через 1 минуту я начинаю проводить операции, которые занимают более 8 секунд, и время ожидания сторожевого таймера истекает.

Я хочу отключить сторожевой таймер, провести операции, затем снова включить его и вернуться в спящий режим.

Вот мой код:

#include "Adafruit_FONA.h"
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>

#define FONA_RX 10
#define FONA_TX 9
#define FONA_RST 4
#define LED_PIN 8

// this is a large buffer for replies
char replybuffer[255];
char *SMSnumber = "6015962842";
char stack[128] = {'c'};

//Value for watchdog timer interrupt.
volatile int f_wdt = 1;
int seconds = 0;
int minutes = 1;
int hours = 0;
int interval = ((hours*60*60) + (minutes*60) + (seconds))/8;
int timerCounter = 0;

//Setup for pulse sensor.
volatile int Signal;                // holds the incoming raw data
int pulsePin = 0;                   //Pin to read at analog 0 for the pulse.
volatile int IBI = 600;             // int that holds the time interval between beats! Must be seeded!
volatile boolean Pulse = false;     // "True" when User's live heartbeat is detected. "False" when not a "live beat".
volatile int BPM;                   // int that holds raw Analog in 0. updated every 2mS
volatile boolean QS = false;        // becomes true when Arduoino finds a beat.
unsigned long lastTime; // used to time the Pulse Sensor samples
unsigned long thisTime; // used to time the Pulse Sensor samples

//ISR for watchdog timer.
ISR(WDT_vect)
{
  if(f_wdt == 0)
  {
    f_wdt=1;
    timerCounter++;
  }
  else
  {
    Serial.println("WDT Overrun!!!");
  }
}

// We default to using software serial. If you want to use hardware serial
// (because softserial isnt supported) comment out the following three lines 
// and uncomment the HardwareSerial line
#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;

// Hardware serial is also possible!
//HardwareSerial *fonaSerial = &Serial;

// Use this for FONA 800 and 808s
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);

void setup() {
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);
  delay(3000);
  digitalWrite(LED_PIN, LOW);
  while (!Serial);
  Serial.begin(115200);
  setupGsm();
  setupWdt();
}

void loop()
{
  if(f_wdt == 1)
  {
    if (timerCounter == interval)
    {
      WDTCSR |= _BV(WDTON);
      Serial.println(F("Tried to stop the watchdog."));
      delay(20000);

      //Reset timer.
      timerCounter = 0;
      WDTCSR |= _BV(WDIE);
      Serial.println(F("Tried to re-enable watchdog."));
    }

    /* Don't forget to clear the flag. */
    f_wdt = 0;

    /* Re-enter sleep mode. */
    enterSleep();
  }
  else
  {
    /* Do nothing. */
  }
}

void setupGsm()
{
  fonaSerial->begin(4800);
  while (! fona.begin(*fonaSerial)) {
    Serial.println(F("Couldn't find FONA"));
    delay(1000);
  }
  digitalWrite(LED_PIN, HIGH);
  delay(500);
  digitalWrite(LED_PIN, LOW);
  delay(500);
  digitalWrite(LED_PIN, HIGH);
  delay(500);
  digitalWrite(LED_PIN, LOW);
  delay(500);
  digitalWrite(LED_PIN, HIGH);
}

void enterSleep(void)
{
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();

  /* Now enter sleep mode. */
  sleep_mode();

  /* The program will continue from here after the WDT timeout*/
  sleep_disable(); /* First thing to do is disable sleep. */

  /* Re-enable the peripherals. */
  power_all_enable();
}

void setupWdt()
{
  /*** Setup the WDT ***/

  /* Clear the reset flag. */
  MCUSR &= ~(1<<WDRF);

  /* In order to change WDE or the prescaler, we need to
   * set WDCE (This will allow updates for 4 clock cycles).
   */
  WDTCSR |= (1<<WDCE) | (1<<WDE);

  /* set new watchdog timeout prescaler value */
  WDTCSR = 1<<WDP0 | 1<<WDP3; /* 8.0 seconds */

  /* Enable the WD interrupt (note no reset). */
  WDTCSR |= _BV(WDIE);
}

в void loop() функция, я пытаюсь выключить сторожевой таймер с помощью WDTCSR |= _BV(WDTON); однако мой компилятор жалуется, что WDTON не декалярируется в своей области видимости.

1 ответ

Решение

Вместо прямого доступа к регистрам контроллера из вашего кода, используйте wdt_enable() а также wdt_disable() от avr/wdt.h библиотека для запуска и остановки сторожевого таймера.

Кроме того, ради надежности системы, возможно, было бы лучше фактически сохранить сторожевой таймер (не отключая его) и добавлять периодические вызовы в wdt_reset() внутри длинные петли и функции, чтобы предотвратить неуместные перезагрузки системы.

Например, вы можете заменить delay(20000); строка в вашем коде с циклом, который 20 раз повторяет операторы: delay(1000); wdt_reset();

Другие вопросы по тегам