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> void
setup() { void
loop() { |
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.