简体   繁体   中英

How to disable then re-enable a watchdog interrupt for Arduino?

I'm attempting to use a watchdog interrupt as a timer to sleep for a certain period of time with my Arduino. My problem lies in the fact that, on wake-up, I need to conduct operations that will take longer than 8 seconds.

Currently, my Arduino will sleep for 1 minute, using successive interrupts by the watchdog to wake it up and place it back into sleep. After 1 minute, however, I begin to conduct operations that take longer than 8 seconds and the watchdog interrupt times out.

I want to shut off the watchdog timer, conduct operations, then re-enable it and return to sleeping.

Here is my code:

#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);
}

In the void loop() function, I'm attempting to turn off the watchdog using WDTCSR |= _BV(WDTON); however my compiler complains that WDTON is not decalared in its scope.

Rather than directly accessing the controller's registers from your code, use wdt_enable() and wdt_disable() from the avr/wdt.h library to start and stop the watchdog timer.

Also, for the sake of system reliability, it might be better to actually keep the watchdog timer running (not disabling it), and add periodic calls to wdt_reset() inside long loops and functions to prevent inappropriate system resets.

For instance, you can replace the delay(20000); line in your code with a loop that repeats 20 times the statements: delay(1000); wdt_reset(); delay(1000); wdt_reset();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM