Watchdog w Arduino to niezwykle przydatna funkcja, zwłaszcza po zakończeniu testów programu i przygotowaniu go do użycia w warunkach rzeczywistych. Weźmy na przykład układ zamka szyfrowego do mieszkania, który zaprogramowaliśmy i zainstalowaliśmy na drzwiach wejściowych. Co jednak, jeśli z jakiegoś powodu procesor na płytce Arduino zawiesi się? Może to być spowodowane zakłóceniami elektromagnetycznymi lub nieprzewidzianym błędem w kodzie.
W takim przypadku nie będziemy w stanie dostać się do mieszkania…
Aby temu zapobiec, włączamy funkcję watchdog w kodzie programu. Watchdog monitoruje działanie programu i, jeśli wykryje zawieszenie systemu, automatycznie resetuje Arduino, przywracając jego normalną pracę.
Użycie wachdog jest bardzo proste, co zademonstrowano na poniższym przykładzie.
Przykład 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// Włączamy bibliotekę watchdog do programu: #include <avr/wdt.h> void setup() { // Aktywujemy watchdog z argumentem czasu - w tej sytuacji 1 sekunda wdt_enable(WDTO_1S); // Wstawiamy w dowolnym miejscu w setup... // Od tego momentu watchdog już działa ;) } void loop() { // Reset zegara watchdog wdt_reset(); // Jeśli w ciągu jednej sekundy program nie wywoła funkcji wdt_reset(), // Arduino zresetuje się automatycznie. } |
Użycie funkcji wdt_reset()
musi być dokładnie przemyślane. W powyższym przykładzie reset zegara watchdog, wywołany funkcją wdt_reset()
, musi nastąpić w ciągu maksymalnie jednej sekundy. Jeśli to się nie wydarzy, płytka Arduino zostanie zresetowana (tak, jakbyśmy nacisnęli przycisk „reset”). Dlatego nie możemy wprowadzać w tym konkretnym przykładowym programie komend takich jak delay(2000)
, ponieważ watchdog wykryje brak resetu i zresetuje płytkę, zanim program odczeka te 2000 ms.
Należy również zachować ostrożność przy używaniu pętli for
i while
, ponieważ program może utknąć w jednej z tych pętli na dłużej. W takim przypadku warto wielokrotnie wywoływać wdt_reset()
w kodzie, zwłaszcza wewnątrz pętli, aby zapewnić, że watchdog będzie resetowany na czas.
Jeśli jednak z jakiegoś powodu Arduino zawiesi się, a program nie wywoła funkcji wdt_reset()
w ciągu jednej sekundy, nastąpi automatyczny reset.
Aby śledzić liczbę resetów wywołanych przez watchdog, można zapisać je w pamięci EEPROM. Dzięki temu, po dłuższym czasie użytkowania urządzenia, będzie można sprawdzić, czy program lub układ elektroniczny jest stabilny, odczytując dane z pamięci EEPROM.
Tabela dostępnych argumentów funkcji wdt_enable
, określających czas, w którym funkcja sprawdza, czy Arduino się nie zawiesiło:
Czas oczekiwania | Argument funkcji wdt_enable |
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 |
Na przykład, jeśli chcemy sprawdzać stan Arduino co ćwierć sekundy, w sekcji setup
wpisujemy:wdt_enable(WDTO_250MS);
Uwaga praktyczna: Czasami watchdog może być w konflikcie z bootloaderem płytki, szczególnie na płytce Nano. W takim przypadku, aby poprawnie wykorzystać watchdog, należy zaprogramować płytkę przez SPI, a nie przez USB. Wtedy wszystko działa prawidłowo.
Szybki generator watchdog:
Wybrany watchdog resetuje się co 2 sekundy.
Kod dla wybranego czasu:
1 2 3 4 5 6 7 8 9 10 11 |
#include <avr/wdt.h> void setup() { // Włącz watchdog z wybranym czasem: wdt_enable(WDTO_2S); } void loop() { // Reset Watchdog w każdej iteracji: wdt_reset(); } |
Przykład 2
Poniższy przykład demonstruje zastosowanie funkcji watchdog w praktyce. Celem programu jest miganie diody na płytce co 1 sekundę. Zdefiniowaliśmy, że watchdog będzie sprawdzał, czy płytka prawidłowo wykonuje kod co 0,25 sekundy. Gdybyśmy zdecydowali się na podejście z użyciem polecenia delay(1000)
, program nie działałby poprawnie. Zamiast tego, program został zaimplementowany przy użyciu funkcji millis()
, co zapewnia prawidłowe działanie watchdog.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include <avr/wdt.h>//włączamy bibliotekę do programu const int nr_pinu = 13; //definicja numer pinu do którego podłączona jest dioda int stan_diody = LOW; //definicja zmiennej stanu diody (HIGH-świeci, LOW-nie świeci) unsigned long ostatni_czas = 0; //definicja zmiennej pomocniczej, do której przypisana będzie ostatnia wartość czasu zmiany staniu diody const long okres_czasu = 1000; //definicja okresu migania diody (500 to znaczy 0,5s) void setup() { pinMode(nr_pinu, OUTPUT); digitalWrite(nr_pinu, LOW); ostatni_czas = millis(); // przypisanie aktualnej wartości czasu do zmiennej wdt_enable(WDTO_250MS);//od tego miejsca watchdog sprawdza co 0,25 sekundy czy arduino nie zawiesiło się } void loop() { if (millis() - ostatni_czas >= okres_czasu) { stan_diody =!stan_diody ;//zmiana stanu zmiennej diody na przeciwny digitalWrite(nr_pinu, stan_diody); ostatni_czas = millis(); // przypisanie aktualnej wartości czasu do zmiennej } wdt_reset(); //reset zegara watchdog } |
Resetowanie zegara watchdog, można również wykonać za pomocą przerwań zegara.
Asystent Arduinowo_AI
Dziękujemy za przeczytanie naszego artykułu. Jeśli doceniasz naszą pracę, prosimy o zapisanie się do bezpłatnego newslettera.
Więcej informacji o watchdog można uzyskać na oficjalnej stronie Arduino: link do strony
Przetestuj nasz generator przerwań typu PCINT (https://arduinowo.pl/generatory/pin_int/)