Arduino365 part 1: Watchdog

By:
Posted: 6th July 2019
Category: Arduino
Comments: 0

UPDATE (06/12/2019): After quite a bit of testing it seems like the good old and tested wire connected to the reset pin does the job amazingly well. You can safely ignore my relay idea despite how much fun it would actually be (the cost outweighs the benefits). I will write a short post with a demo showing the difference between "hard" and soft reset.

This is for anyone who is serious about keeping their project(s) running 24/7/365 on the Arduino platform. Part 1 is going to cover the watchdog capabilities and use case scenarios. Most of the ideas I found on google are quite old, repetitive and not original (personal opinion). So I have decided to take some of those ideas and spiced them up a notch (and make some up myself as well). 
Before we dive any deeper below is a source code that will be used as a base sketch for all of the examples:

#include <avr/wdt.h>

unsigned long time;

// When watchdog kicks in it will run whatever is in here + do a normal watchdog reset
ISR(WDT_vect)
{
}

void setup()
{
cli(); // disable all interrupts
wdt_reset(); // reset the WDT timer
MCUSR &= ~(1<<WDRF);
// Enter Watchdog Configuration mode:
WDTCSR = (1<<WDCE) | (1<<WDE);
// Set Watchdog settings: interrupt enable, 8 second timeout !
// To enable an interrupt and reset mode just add this " | (1<<WDE) "
WDTCSR = (1<<WDIE) | 1<<WDP0 | 1<<WDP3 | (1<<WDE);
sei();
Serial.begin(9600);
Serial.println("Finished watchdog setup"); // just here for testing
}

// the loop routine runs over and over again forever:
void loop() {
Serial.print("Time: ");
time = millis();
Serial.println(time); //prints time since program started
delay(1000); // wait a second so as not to send massive amounts of data
}

So the above code will just run for 8 seconds => jump into the ISR(WDT_vect) function and after it executes all that is inside it (nothing so far) => restart. There will be a video demonstrating all of the described "solutions".

On the Cheap
This is the box standard idea using one of the digital pins and the RESET pin. I will trigger pin 12 (low state) from the ISR function when the watchdog timer runs out (8 seconds). Please notice that when doing the standard watchdog reset the Arduino does not behave in the same way when using the pin RESET method or pressing the physical reset button (there are 3 quick led flashes - you will notice this in the video). All you really need for this "option" is a simple wire - job done. Source code and image:

#include <avr/wdt.h>

int resetPin = 12;
unsigned long time;

// When watchdog kicks in it will run whatever is in here + do a normal watchdog reset
ISR(WDT_vect)
{
digitalWrite(resetPin, LOW); // hit the reset pin hard !
}

void setup()
{

digitalWrite(resetPin, HIGH); // so we don't end up in an ever lasting loop
pinMode(resetPin, OUTPUT);

cli(); // disable all interrupts
wdt_reset(); // reset the WDT timer
MCUSR &= ~(1<<WDRF);
// Enter Watchdog Configuration mode:
WDTCSR = (1<<WDCE) | (1<<WDE);
// Set Watchdog settings: interrupt enable, 8 second timeout !
// To enable an interrupt and reset mode just add this " | (1<<WDE) "
WDTCSR = (1<<WDIE) | 1<<WDP0 | 1<<WDP3 | (1<<WDE);
sei();
Serial.begin(9600);
Serial.println("Finished watchdog setup"); // just here for testing
}

// the loop routine runs over and over again forever:
void loop() {
Serial.print("Time: ");
time = millis();
Serial.println(time); //prints time since program started
delay(1000); // wait a second so as not to send massive amounts of data
}


The power cutter
For this "version" I will be using two different relays.  One will be a box standard coil variant and the second one a coiled variant but with a timer. The general idea is to control the delivery of power to the Arduino (this will be triggered only when the watchdog timer expires). Similar idea as the one above (on the cheap) but in this case I will be energising a relay for it to trigger the timer on the second relay which surprisingly enough will disconnect the arduino itself from its power source for about two seconds = a proper off and on of the entire unit. What can go wrong? :) Code and image:

#include <avr/wdt.h>

unsigned long time;
int Pin8 = 8;

// When watchdog kicks it will run whatever is in here + do a
// normal watchdog reset just to be sure
ISR(WDT_vect)
{
digitalWrite(Pin8, HIGH); // so we don't end up in an ever lasting loop
}

void setup()
{
digitalWrite(Pin8, LOW); // so we don't end up in an ever lasting loop
pinMode(Pin8, OUTPUT); // sets the digital pin 13 as output

pinMode(LED_BUILTIN, OUTPUT);

for (int x = 0; x <= 2; x++)
{
digitalWrite(LED_BUILTIN, HIGH); // on
delay(1500);
digitalWrite(LED_BUILTIN, LOW); // off
delay(1500);
}

cli(); // disable all interrupts
wdt_reset(); // reset the WDT timer
MCUSR &= ~(1<<WDRF);
// Enter Watchdog Configuration mode:
WDTCSR = (1<<WDCE) | (1<<WDE);
// Set Watchdog settings: interrupt enable, 8 second timeout !
// To enable an interrupt and reset mode just add this " | (1<<WDE) "
WDTCSR = (1<<WDIE) | 1<<WDP0 | 1<<WDP3 | (1<<WDE);
sei();
Serial.begin(9600);
Serial.println("Finished watchdog setup"); // just here for testing
}

// the loop routine runs over and over again forever:
void loop() {

digitalWrite(LED_BUILTIN, HIGH); // on
delay(100);
digitalWrite(LED_BUILTIN, LOW); // off
delay(100);

Serial.print("Time: ");
time = millis();
Serial.println(time); //prints time since program started
delay(1000); // wait a second so as not to send massive amounts of data

}

Hey, like this? Why not share it with a buddy?