Ten post chciałbym poświęcić na przedstawienie konfiguracji Watchdoga w mikrokontrolerze ATmega328p.
Watchdog taktowany jest oddzielnym zegarem 128kHz. Pozwala na generowanie przerwań czy reset mikrokontrolera.
Rejestry konfiguracyjne zostały opisane w dokumentacji na stronie 54.
W rejestrze konfiguracyjnym można ustawić takie parametry jak:
- WDIF - flaga ustawiana gdy licznik się zapełni
- WDIE - włączenie przerwania
- WDCE - dostęp do prescalera
- WDE - odpowiada WDRF z rejestru MCUSR. Ustawiany gdy wystąpi reset
- WDP[3-0] - ustawie dzielnika dla czasu potrzebnego na zapełnienie licznika
Poniższy przykład przedstawia konfigurację watchdoga w włączonymi przerwaniami. Przerwanie jest wywoływane gdy licznik timera się przepełni i nie zostanie zresetowany.
Cały plik nagłówkowy, w którym zawarłem też potrzebne funkcje wygląda następująco:
- #ifndef WATCHDOG_LIBRARY_H_
- #define WATCHDOG_LIBRARY_H_
- #define WDT_TIME_TAKE 10
- //===============================================================================================
- #if WDT_TIME_TAKE==1
- #define WDT_16ms() WDTCSR = (1<<WDIE)|(1<<WDE) //1
- #elif WDT_TIME_TAKE==2
- #define WDT_32ms() WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP0) //2
- #elif WDT_TIME_TAKE==3
- #define WDT_64ms() WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP1) //3
- #elif WDT_TIME_TAKE==4
- #define WDT_0125s() WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP1)|(1<<WDP0) //4
- #elif WDT_TIME_TAKE==5
- #define WDT_025s() WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP2) //5
- #elif WDT_TIME_TAKE==6
- #define WDT_05s() WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP2)|(1<<WDP0) //6
- #elif WDT_TIME_TAKE==7
- #define WDT_1s() WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP2)|(1<<WDP1) //7
- #elif WDT_TIME_TAKE==8
- #define WDT_2s() WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP2)|(1<<WDP1)|(1<<WDP0) //8
- #elif WDT_TIME_TAKE==9
- #define WDT_4s() WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP3) //9
- #elif WDT_TIME_TAKE==10
- #define WDT_8s() WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP3)|(1<<WDP0) //10
- #endif
- //===============================================================================================
- #define WDT_Inter_ENABLE() WDTCSR = (1<<WDCE)|(1<<WDE)
- //===============================================================================================
- void WDT_init(void)
- {
- cli(); //wylaczenie przerwan
- MCUSR = 0;
- wdt_disable();
- wdt_reset();
- WDT_Inter_ENABLE();
- #if WDT_TIME_TAKE==1
- WDT_16ms();
- #elif WDT_TIME_TAKE==2
- WDT_32ms();
- #elif WDT_TIME_TAKE==3
- WDT_64ms();
- #elif WDT_TIME_TAKE==4
- WDT_0125s();
- #elif WDT_TIME_TAKE==5
- WDT_025s();
- #elif WDT_TIME_TAKE==6
- WDT_05s();
- #elif WDT_TIME_TAKE==7
- WDT_1s();
- #elif WDT_TIME_TAKE==8
- WDT_2s();
- #elif WDT_TIME_TAKE==9
- WDT_4s();
- #elif WDT_TIME_TAKE==10
- WDT_8s();
- #endif
- sei(); //Wlaczenie przerwan
- }
- //===============================================================================================
- ISR(WDT_vect)
- {
- //Mruganie dioda, komunikat, usart, czy cokolwiek innego
- USART_SEND(COM0,"Watchdog RESET",RX_END_CRLF);;
- }
- #endif /* WATCHDOG_LIBRARY_H_ */
Jak widać powyżej uruchomienie wachdoga jest mało skomplikowane. Na samym początku wybierana jest instrukcja inicjalizacji czasu dla watchdoga. W zależności od wprowadzonego numeru następuje wykonanie odpowiedniej instrukcji.
W głównej funkcji przerwania na początku zostają wyłączone, po czym następuje wyczyszczenie rejestru MCUSR oraz wyłączenie i zresetowanie watchdoga. Kolejny krok włącza przerwania po czym następuje wgranie odpowiednich ustawień do mikrokontorlera. Na samym końcu przerwania zostają ponownie właczone.
W programie głównym należy wywołać funkcje inicjalizującą z odpowiednimi parametrami, które zostały zdefiniowane jako typy wyliczeniowe. Następnie cyklicznie np. w pętli while bądź w przerwaniach od timera należy wywoływać funkcje, a dokładniej makro wdt_reset();. Została ona zdefiniowana w bibliotece wdt.h.
W głównej funkcji przerwania na początku zostają wyłączone, po czym następuje wyczyszczenie rejestru MCUSR oraz wyłączenie i zresetowanie watchdoga. Kolejny krok włącza przerwania po czym następuje wgranie odpowiednich ustawień do mikrokontorlera. Na samym końcu przerwania zostają ponownie właczone.
W programie głównym należy wywołać funkcje inicjalizującą z odpowiednimi parametrami, które zostały zdefiniowane jako typy wyliczeniowe. Następnie cyklicznie np. w pętli while bądź w przerwaniach od timera należy wywoływać funkcje, a dokładniej makro wdt_reset();. Została ona zdefiniowana w bibliotece wdt.h.