Watchdog


Néha megtörténik, hogy külső érintkező hibára vagy éppen valamelyik változónk túlcsordulására mikrovezérlőnk megakad, lefagy. Ilyenkor egy újraindítás helyre állítja a rendet a működésében, de mi van akkor ha ez a vezérlő valamilyen fontos dolgot üzemeltet. Például a nyaraláskor otthon hagyott virágok vízellátását, a lakás hőmérséklet beállításait, vagy egy beteg szívmonitorát figyeli éppen.
Ebben az esetben egy lefagyás óriás károkat okozhat, de mint más mikrovezérlőknél úgy itt is van rá megoldás.
Az Arduinonál is elérhető az avr-eknél és pic-eknél már régóta használatos
watchdog, ami állandóan figyeli és lefagyás esetén újraindítja eszközünket.
A watchdog figyeli a mikrovezérlőnk működését, ha elakadást észlel a parancsok végrehajtásában akkor újraindítja a rendszert, resetet végrehajtva.

Nézzük mind ezt a gyakorlatban:

#include<avr/wdt.h>
int i=0;

void setup() {
pinMode(13,OUTPUT);
Serial.begin(9600);
wdt_enable (WDTO_2S);// az állási idő behatárolása
}

void loop() {
Serial.println(i);
digitalWrite(13,HIGH);
delay(1000);
digitalWrite(13,LOW);
delay(1000);
i++;
wdt_reset();
}


Az #include<avr/wdt.h> beilleszti nekünk a watchdog könyvtárat, ez egy alapértelmezett könyvtár az IDE-nkben megtalálható. A wdt_enable (WDTO_2S); sorral állítjuk be, hogy mennyi idő múlva induljon újra a programunk ha valami miatt leakad. A WDTO_2S egy konstans érték ami 2 sec várakozási időt biztosít.

A táblázatban megtalálható a többi érték is:

Várakozási idő                    hozzá tartozó konstans

    15ms                                   WDTO_15MS

    30ms                                   WDTO_30MS

    60ms                                   WDTO_60MS

   120ms                                  WDTO_120MS

    250ms                                 WDTO_250MS

    500ms                                 WDTO_500MS

       1s                                        WDTO_1S

       2s                                        WDTO_2S

       4s                                        WDTO_4S

       8s                                        WDTO_8S


A wdt_reset(); nulláza a watchdog számlálóját( timer-ét), ezt majd mindjárt elmagyarázom. Először is nézzük a progit: ez csak egy sima led villogtatás beépített watchdoggal. Ha bekapcsoljuk a soros monitort szépen látjuk, hogy az értékek 2sec-enként eggyel növekszenek, szóval nem történik újra indulás. A watchdognak nincs munkája.

Most írjuk át a második delay() értékét 1500ms-re, töltsük fel és indítsuk el a soros monitort. A számláló nem képes elhagyni a nullát, a vezérlő újra indul a watchdog jóvoltából. Mért van ez, hisz az elején 2sec-os értéket adtunk meg és itt ezt sehol se éri el a várakozási idő. Azért van mert a watchdog összeszámolja a várakozási időket a wdt_reset() utasításig, és ha ez az érték meghaladja a beállítottat akkor újra indítja az eszközt. Tehát a wdt_reset() nullázza a timert.

Ilyen esetben ha nem tudunk az időzítőn többet emelni (max 8sec), akkor több wdt_reset()-et is elhelyezhetünk a programunkban.

void loop() {
Serial.println(i);
digitalWrite(13,HIGH);
delay(1000);
wdt_reset();
digitalWrite(13,LOW);
delay(1500);
i++;
wdt_reset();
}


Ez egy-egy szakasz várakozási idejét (WDT timer álltal számolt időt) lenullázza.


Van olyan eset is amikkor kell a WDT de bizonyos program részek futását meg akasztja, ilyenkor van mód a WDT kikapcsolására is:

void loop() {
Serial.println(i);
digitalWrite(13,HIGH);
delay(1000);
wdt_disable();
digitalWrite(13,LOW);
delay(1500);
i++;
wdt_reset();
}


A WDT kikapcsolását a wdt_disable(); függvény végzi, ez után nem működik a a watchdog számlálója. Újra bekapcsolást a wdt_enable(WDTO_2S); függvénnyel érhető el.


Most nézünk meg egy ciklust, abban hogy működik a WDT:

#include<avr/wdt.h>
int i=0;

void setup() {
pinMode(13,OUTPUT);
Serial.begin(9600);
wdt_enable (WDTO_2S);
}

void loop(){
while(1){
i++;
delay(500);
Serial.println(i);
}
}


A while(1) egy végtelenített ciklus, ha feltöltjük és elindítjuk akkor a soros monitoron nyomon követhető a WDT működése. Az 500sec delay miatt elszámol 4-ig aztán újraindítja a rendszert, megint 4, megint indítás, és ez így a végtelenségig.

Ha nem teszünk be delay()-t akkor is egy bizonyos idő után újra indul a rendszerünk, mert a ciklus pörgeti a WDT számlálóját.

Milyen lehetőségek vannak? Megpróbálkozhatunk wdt_reset() alkalmazásával a cikluson belül, így nullázza a WDT timerét és nem okoz újraindítást:

void setup() {
pinMode(13,OUTPUT);
Serial.begin(9600);
wdt_enable (WDTO_2S);
}

void loop(){
while(1){
wdt_reset();
i++;
Serial.println(i);
}
}


A másik lehetőség - ha nincs mód az adott programrészben wdt_reset()-et elhelyezni – a watchdog kikapcsolása a wdt_disble() utasítással. Vigyázat ez a rész védtelen marad!


void setup() {
pinMode(13,OUTPUT);
Serial.begin(9600);
wdt_enable (WDTO_2S);
}

void loop(){
wdt_disable();
while(1){
i++;
Serial.println(i);
}
wdt_enable(WDTO_2S);
}


Tehát a watchdog egy hatékony segítség a vezérlők üzembiztos működésében, de egyben a kódban több hibalehetőséget okozó tényező is.