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:
Valore | Tempo |
---|---|
WDTO_15MS | 15 millisecondi |
WDTO_32MS | 32 millisecondi |
WDTO_64MS | 64 millisecondi |
WDTO_125MS | 125 millisecondi |
WDTO_250MS | 250 millisecondi |
WDTO_500MS | 500 millisecondi |
WDTO_1S | 1 secondo |
WDTO_2S | 2 secondi |
WDTO_4S | 4 secondi |
WDTO_8S | 8 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.
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:
- Arduino UNO: https://amzn.to/3shiBJL
- Ethernet Shield: https://amzn.to/3sj9xEq
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:
- Si parte includendo la libreria
#include <avr/wdt.h>
- Si passa ad impostare il timer
wtb_enalble(WDTO_15MS); // timer di 15 millisecondi
- 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();