Watch Dog

Impariamo a impostare la funzionalità di controllo WatchDog per resettare via codice Arduino

La funzionalità di WatchDog (cane da guardia) è utilizzata per resettare Arduino tramite software per evitare l’overflow della dev-board o per semplici esigenze di programmazione, quando, ad esempio, vogliamo che Arduino si resetti se il programma prevede dei “vicoli ciechi” o se, a causa di un malfunzionamento di un sensore o attuatore, il codice possa bloccarsi. Il WatchDog va impostato tramite l’apposita libreria e prevede la programmazione di un timer e il successivo reset.

Questo timer lavora su valori predefiniti, compresi in un intervallo compreso tra 15 millisecondi e 8 secondi. Di seguito la tabella dei valori di timer impostabili:

ValoreTempo
WDTO_15MS15 millisecondi
WDTO_32MS32 millisecondi
WDTO_64MS64 millisecondi
WDTO_125MS125 millisecondi
WDTO_250MS250 millisecondi
WDTO_500MS500 millisecondi
WDTO_1S1 secondo
WDTO_2S2 secondi
WDTO_4S4 secondi
WDTO_8S8 secondi

Componenti

Per impostare correttamente il WatchDog non servono particolari componenti. Tuttavia, nel caso utilizzassimo Arduino Mega, potremmo riscontrare difficoltà, pertanto vi consigliamo di adoperarlo principalmente su Arduino UNO. Nel nostro esempio, adopereremo il WatchDog su un Arduino UNO su cui è stata montata una Ethernet SHIELD.

Watch Dog

Programmeremo il codice affinché la scheda riavvolga il codice contenuto nel VOID SETUP per connettere Arduino UNO ad Internet. Vi lasciamo come sempre la lista delle componenti:



Codice

Applicare il WatchDog è molto semplice e prevede l’utilizzo di una libreria apposita già contenuta nella IDE di Arduino. Questa funzionalità consiste in solo 3 righe di codice da inserire poi correttamente nello sketch:

  1. Si parte includendo la libreria
    #include <avr/wdt.h>
    
  2. Si passa ad impostare il timer
    wtb_enalble(WDTO_15MS);              // timer di 15 millisecondi
    
  3. Resettarlo inserendo la seguente riga alla fine del blocco del codice da resettare (ad esempio, alla fine del VOID SETUP o del VOID LOOP)
    wdt_reset();
    

Applichiamo ora queste conoscenze ad un caso pratico. Partiamo dallo sketch di esempio della Ethernet Shield che prevede un blocco quando la scheda non riesce a connettersi ad Internet, perché il cavo di rete non è collegato o semplicemente il modem/router in quell’istante è spento o si sta riavviando. Per evitare di resettare la scheda manualmente, attiveremo il WatchDog solo quando la scheda non si collegherà. In tal modo, il codice si riavvierà finché non ci sarà connessione. Potete scaricare lo sketch di esempio da questo LINK.


#include <SPI.h>
#include <Ethernet.h>
#include <avr/wdt.h> //Libreria WatchDog

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

char server[] = "www.fattelodasolo.it";

IPAddress ip(192, 168, 1, 177);
IPAddress myDns(192, 168, 1, 1);

EthernetClient client;

unsigned long beginMicros, endMicros;
unsigned long byteCount = 0;
bool printWebData = true;

void setup() {

Serial.begin(9600);
while (!Serial) {
; }

Serial.println("Avvio connessione");


Ethernet.begin(mac, ip, myDns);
Serial.print("IP assegnato: ");
Serial.println(Ethernet.localIP());

delay(1000);
Serial.print("Connessione a ");
Serial.print(server);
Serial.println("...");

if (client.connect(server, 80)) {
Serial.print("connesso a ");
Serial.println(client.remoteIP());
client.println("GET / HTTP/1.1");
client.println("Host: www.fattelodasolo.it");
client.println("Connessione: chiusa");
client.println();
} else {

Serial.println("connessione fallita");
delay(500);
Serial.println("Riavvio...");
delay(1000);
wdt_enable(WDTO_30MS); //Timer di 30 millisecondi
}
beginMicros = micros();

wdt_reset(); // Reset timer
}

void loop() {
int len = client.available();
if (len > 0) {
byte buffer[80];
if (len > 80) len = 80;
client.read(buffer, len);
if (printWebData) {
Serial.write(buffer, len); // show in the serial monitor (slows some boards)
}
byteCount = byteCount + len;
}

if (!client.connected()) {
endMicros = micros();
Serial.println();
Serial.println("disconnesso.");
client.stop();
Serial.print("Received ");
Serial.print(byteCount);
Serial.print(" bytes in ");
float seconds = (float)(endMicros - beginMicros) / 1000000.0;
Serial.print(seconds, 4);
float rate = (float)byteCount / seconds / 1000.0;
Serial.print(", rate = ");
Serial.print(rate);
Serial.print(" kbytes/second");
Serial.println();

while (true) {
delay(1);
}
}

}

Una volta caricato il codice, se non ci sarà connessione, Arduino riproverà all’infinito a riconnettersi finché la connessione non andrà a buon fine. Aggiungiamo, poi, che potrebbe essere in taluni casi necessario proprio evitare il reset perpetuo della scheda. In tali circostanze, sarebbe buona misura inserire all’inizio del VOID SETUP la seguente riga:


wdt_disable();