Über den Beitrag
Nach meinen Beiträgen über die 8-Bit Timer und den 16-Bit Timer des Arduinos bzw. des ATmega 328P möchte ich das Thema nun mit dem Watchdog Timer komplettieren. Darum geht es in diesem Beitrag:
- Was ist ein Watchdog Timer und wozu brauche ich ihn?
- Der Watchdog Timer des Arduino UNO (und anderer AVR MCUs)
- Das Problem mit dem Arduino Pro Mini
- Watchdog Timer des ESP8266
Was ist ein Watchdog Timer?
Unter bestimmten Bedingungen kann sich ein Microcontroller genau wie ein PC aufgrund unerwarteter Bedingungen oder Programmierfehlern „aufhängen“. Meistens machen sich Programmierfehler sofort bemerkbar, manchmal aber auch erst später unter speziellen Bedingungen, die man bei der Programmierung nicht berücksichtigt hat. Auch können Fehler in Peripherie, wie z.B. Kommunikationsleitungen oder Sensoren, dazu führen, dass der Sketch auf einmal in einer Programmschleife festhängt.
Einfach ausgedrückt wacht der Watchdog Timer über den Sketch, indem er regelmäßig Lebenszeichen von ihm erwartet. Bleiben diese aus, wird je nach Einstellung und Mikrocontroller, nach einer einstellbaren Zeit ein Reset durchgeführt, ein Interrupt ausgelöst oder beides. Etwas genauer ausgedrückt ist der Watchdog Timer ein automatischer Zähler, der die besagten Aktionen bei Erreichen seines Limits auslöst, wenn er nicht vorher zurückgesetzt wird.
Ein Interrupt vor dem Reset kann zum Beispiel dazu genutzt werden, um
- sichere Bedingungen bei der gesteuerten Anlage zu schaffen
- Parameter auf einem EEPROM zum Zwecke der Fehleranalyse zu speichern
- den Stand des Programmes zu speichern, damit es nach dem Reset an der richtigen Stelle seine Arbeit fortsetzt (Beispiel: Steuerung einer Waschmaschine)
Der Watchdog Timer des Arduino (UNO)
Die folgende Anleitung gilt für die ganze ATmega 48 / 88 / 168 / 328 / 328P Familie. Nachzulesen ist das im Datenblatt ab Seite 60. Prinzipiell gelten die Angaben auch für die anderen Vertreter der AVR Microcontroller. Nur ist nicht jeder Time-Out bei jedem Modell verfügbar. Weitere Angaben zu den Time-Outs gibt es hier.
Einstellungen
Der Watchdog Timer des Arduino UNO bzw. des ATmega 328P wird nicht wie die anderen, zuvor besprochenen Timer über den Systemtakt gespeist, sondern über einen separaten 128 kHz Oszillator. Dadurch sind die Sketche leichter übertragbar.
Die Einstellungen des Watchdog Timers nehmt ihr im Watchdog Timer Control Register WDTCSR vor:

- WDIF: Watchdog Interrupt Flag – das Bit wird bei Time-Out des Watchdog Timers gesetzt, wenn zuvor auch WDIE gesetzt wurde
- WDIE: Watchdog Interrupt Enable – setzt ihr dieses Bit, dann löst ein Time-Out des Watchdog Timers einen Interrupt aus
- WDPx: Watchdog Timer Prescaler – mit diesen Bits legt ihr die Periode des Watchdog Timers entsprechend der nachfolgenden Tabelle fest
- WDCE: Watchdog Change Enable – wollt ihr die Watchdog Timer Einstellungen ändern, dann müsst ihr zunächst dieses Bit setzen. Die Prozedur wird noch erklärt.
- WDE: Watchdog System Reset Enable – setzt Ihr dieses Bit, dann löst ein Time-Out des Watchdog Timers ein Reset des Microcontrollers aus.

Einrichten des Watchdog Timers – Schritt für Schritt
Wir fangen ganz einfach an. Der folgende Sketch bleibt in einer while-Schleife hängen, da ich das Inkrementieren meines Zählers i „vergessen“ habe.
void setup(){ Serial.begin(9600); Serial.println("Program with endless loop..."); Serial.println("Sketch starts..."); } void loop(){ endlessLoop(); Serial.println("I will never print this..."); } void endlessLoop(){ int i = 0; while(i < 5){ //do nothing } }
Watchdog Timer mit System Reset
Nun soll ein Watchdog eingerichtet werden, der den Sketch aus der Schleife befreit und den Microcontroller neu startet:
void setup(){ Serial.begin(9600); Serial.println("Watchdog Timer Test"); Serial.println("Sketch starts..."); watchdogSetup(); } void loop(){ endlessLoop(); Serial.println("I will never print this..."); asm("WDR"); // this will not be executed } void watchdogSetup(void){ cli(); // disable all interrupts asm("WDR"); // watchdog reset WDTCSR |= (1<<WDCE) | (1<<WDE); WDTCSR = (1<<WDE) | (1<<WDP3); // 4s / no interrupt, system reset sei(); } void endlessLoop(){ static int seconds = 0; int i = 0; while(i < 5){ Serial.print(seconds); Serial.println(" Sekunden"); delay(1000); seconds++; } }
Die Einrichtung des Watchdog Timers läuft nach dem folgenden Schema:
cli()
schaltet alle Interrupts ab. Das ist notwendig, da die Einrichtung des Watchdog Timers gestört werden könnteasm("WDR");
ist eine Assembler Anweisung für den Watchdog Reset; wir werden bald sehen, wie man eine weniger kryptische Funktion einsetzen kann.WDTCSR |= (1<<WDCE) | (1<<WDE);
leitet die Änderung der Watchdog Parameter ein. Es ist wichtig, dass „|=“ und nicht „=“ verwendet wird. Nach dieser Initialisierung muss die eigentliche Änderung innerhalb der nächsten 4 Taktzyklen erfolgen.WDTCSR = (1<<WDE) | (1<<WDP3);
bedeutet: Reset ist aktiviert und der Watchdog Timer ist auf vier Sekunden eingestellt (siehe Einstellungstabelle).sei();
lässt Interrupts wieder zu.
Der Watchdog Reset am Ende der Loop-Schleife (Zeile 11) würde den System Reset verhindern. Diese Anweisung ist aber unerreichbar.
Und so sieht die Ausgabe am seriellen Monitor aus:

Der Watchdog funktioniert – alle vier Sekunden startet der Arduino neu. Theoretisch dürfte der Sketch „4 Sekunden“ schon gar nicht mehr ausgeben. Der Watchdog Timer ist aber weniger exakt als die anderen Timer. So gibt das Datenblatt die Time-Out Werte auch nur als „typisch“ an.
Watchdog Timer mit System Reset und Interrupt
Der folgende Sketch enthält immer noch die Endlos-Schleife, die zum Watchdog Time-Out führt. Hier führt der Time-Out aber nicht nur zum Reset, sondern vorher wird noch ein Interrupt ausgelöst. Dieser wiederum ruft die ISR (Interrupt Service Routine) auf. Dazu muss ihr „WDT_vect“ übergeben werden.
void setup(){ Serial.begin(9600); Serial.println("*******************"); Serial.println("Watchdog Timer Test"); Serial.println("Sketch starts..."); watchdogSetup(); } void loop(){ endlessLoop(); Serial.println("I will never print this..."); asm("WDR"); // Watchdog Reset will not happen } void watchdogSetup(void){ cli(); // disable all interrupts asm("WDR"); WDTCSR |= (1<<WDCE) | (1<<WDE); WDTCSR = (1<<WDIE) | (1<<WDE) | (1<<WDP3); // 4s / interrupt, system reset sei(); } void endlessLoop(){ static int seconds = 0; int i = 0; while(i < 5){ Serial.print(seconds); Serial.println(" Sekunden"); delay(1000); seconds++; } } ISR(WDT_vect){ Serial.println("....but I will print this before I reset soon"); }
Und so sieht dann die Ausgabe aus:

Wie ihr erkennt, läuft der Sketch noch vier Sekunden weiter, bevor der Reset ausgelöst wird. Der Interrupt gewährt einen Aufschub um eine Watchdog Periode. Bei der Auswahl der Watchdog Timer Periode müsst ihr also darauf achten, dass die vor dem Reset auszuführenden Aktionen auch in eine Periode „hineinpassen“.
Vereinfachte Schreibweise mit wdt.h
Die kryptische Einrichtung des Watchdog Timers könnt ihr durch Einbinden der Bibliothek „avr/wdt.h“ etwas angenehmer gestalten:
- Um das Abschalten der Interrupts durch
cli();
braucht ihr euch nicht mehr zu kümmern. - Aus
asm("WDR");
wirdwdt_reset();
. - Die Initialisierung durch das Setzen von WDCE und die nachfolgende Prescale Festlegung wird ersetzt durch
wdt_enable(WDTO_XYZ);
, wobei ihr WDTO_XYZ der Tabelle 1 entnehmt. - Einzig für das Aktivieren des Watchdog Interrupts hat man komischerweise keine Funktion vorgesehen. Dafür müsst ihr immer noch die Binäroperation
WDTCSR = (1<<WDIE);
verwenden. - Der Watchdog Interrupt ohne Systemreset lässt sich nicht mit den wdt.h Funktionen einrichten.
#include <avr/wdt.h> void setup(){ Serial.begin(9600); Serial.println("*******************"); Serial.println("Watchdog Timer Test"); Serial.println("Sketch starts..."); watchdogSetup(); } void loop(){ endlessLoop(); Serial.println("I will never print this..."); wdt_reset(); // Watchdog Reset will not happen } void watchdogSetup(void){ wdt_reset(); wdt_enable(WDTO_4S); // 4s / System Reset WDTCSR = (1<<WDIE); // interrupt } void endlessLoop(){ static int seconds = 0; int i = 0; while(i < 5){ Serial.print(seconds); Serial.println(" Sekunden"); delay(1000); seconds++; } } ISR(WDT_vect){ Serial.println("....but I will print this before I reset"); }
Ein „OK“-Sketch
Der Vollständigkeit halber hier noch ein Sketch mit einer Schleife, die rechtzeitig beendet wird. Dazu habe ich in Zeile 30 ein i++
eingefügt und i<4
als Abbruchbedingung für die while-Schleife.
#include <avr/wdt.h> void setup(){ Serial.begin(9600); Serial.println("*******************"); Serial.println("Watchdog Timer Test"); Serial.println("Sketch starts..."); watchdogSetup(); } void loop(){ finiteLoop(); Serial.println("Now I will print this..."); wdt_reset(); } void watchdogSetup(void){ wdt_reset(); wdt_enable(WDTO_4S); //wdt_enable(WDTO_2S); WDTCSR = (1<<WDIE); } void finiteLoop(){ static int seconds = 0; int i = 0; while(i < 4){ Serial.print(seconds); Serial.println(" Sekunden"); delay(1000); i++; seconds++; } } ISR(WDT_vect){ Serial.println("....but not this - as long there's no failure"); }
So sieht dann die Ausgabe aus:

Spaßeshalber könnt ihr mal Zeile 18 aus- und Zeile 19 entkommentieren und schauen, wie sich die Ausgabe verändert.
Abschalten des Watchdog Timers
Wenn ihr avr/wdt.h eingebunden habt, dann könnt ihr den Watchdog Timer einfach mit wdt_disable();
abschalten. „Zu Fuß“ geht das so:
void watchdogOff(){ cli(); asm("WDR"); MCUSR &= ~(1<<WDRF); WDTCSR |= (1<<WDCE) | (1<<WDE); WDTCSR = 0x00; sei(); }
Was euch dabei vielleicht auffällt, ist die Anweisung MCUSR &= ~(1<<WDRF);
. MCUSR ist das Microcontroller Status Register und WDRF ist das Watchdog System Reset Flag Bit. Letzteres überschreibt das WDE Bit in WDTCSR und muss deswegen zwingender Maßen zuerst gelöscht werden.
Watchdog Timer „immer an“ mit dem Fuse Bit WDTON
Ihr könnt – sofern ihr ein Programm wie Atmel Studio mit zugehörigem Programmer habt – den Watchdog Timer auch dauerhaft aktivieren, indem ihr das Fuse Bit WDTON setzt. In diesem Fall ist der reine Reset Modus ohne Watchdog Interrupt aktiviert. Ihr könnt also nur den Time-Out ändern.

Watchdog Timer mit Interrupt und ohne Reset
Die Variante mit Watchdog Interrupt, aber ohne System Reset, lässt sich, wie schon zuvor erwähnt, nicht in Verbindung mit wdt_enable();
realisieren. Hier müsst ihr deshalb wieder die binären Operationen verwenden. Dazu folgendes Beispiel:
#include <avr/wdt.h> void setup(){ Serial.begin(9600); watchdogSetup(); } void loop(){ Serial.println("Here's the loop!"); delay(1000); } void watchdogSetup(void){ cli(); wdt_reset(); WDTCSR |= (1<<WDCE) | (1<<WDE); WDTCSR = (1<<WDIE) | (1<<WDP3); // 4s / interrupt, no system reset sei(); } ISR(WDT_vect){ Serial.println("Greetings from the ISR!"); }

Diese Einstellung des Watchdog Timers ist sinnvoll um periodisch Dinge erledigen zu lassen, ohne dabei auf zeitabhängige Vorgänge in der loop-Schleife Rücksicht nehmen zu müssen. Vielleicht wartet z.B. in der loop-Schleife ein Taster auf Betätigung und über den Watchdog wird parallel regelmäßig ein Sensor ausgelesen. Dinge der Art eben, die sonst schnell komplex werden können, wenn man sie nebeneinander in der loop-Schleife unterbringen möchte.
Aufwecken mit dem Watchdog Timer
Der Watchdog Timer kann auch verwendet werden, um den Microcontroller aus dem Schlaf zu wecken. Eine mögliche Anwendung wäre zum Beispiel die Ansteuerung eines Sensors, der alle paar Sekunden eine Messung durchführen soll. Ist zwischendurch nichts zu tun, kann man den Microcontroller auch gerne in den Schlaf schicken, um (Batterie-) Strom zu sparen. Wie das prinzipiell geht, seht ihr im folgenden Sketch:
#include <avr/wdt.h> #include <avr/sleep.h> const int ledPin = 12; void setup(){ pinMode(ledPin,OUTPUT); watchdogSetup(); } void loop(){ digitalWrite(ledPin,HIGH); delay(500); digitalWrite(ledPin,LOW); set_sleep_mode(SLEEP_MODE_PWR_DOWN); // chose power down modus sleep_mode(); // sleep now! sleep_disable(); // disable sleep after wake up } void watchdogSetup(void){ cli(); wdt_reset(); WDTCSR |= (1<<WDCE) | (1<<WDE); WDTCSR = (1<<WDIE) | (0<<WDE) | (1<<WDP3) | (1<<WDP0); // 8s / interrupt, no system reset sei(); } ISR(WDT_vect){//put in additional code here }
Länger als 8 Sekunden Schlaf geht mit der Methode nicht. Bei Bedarf könntet ihr aber noch einen Zähler einbauen, der dafür sorgt, dass die gewünschte Aktion erst nach dem x-ten Aufwachen ausgelöst wird. Ansonsten geht es wieder in den Schlaf.
Watchdog am Arduino Pro Mini
Die Problematik mit dem Reset
Der folgende Sketch funktioniert am Arduino Uno ohne Probleme. Alle vier Sekunden löst der Watchdog Timer einen Reset aus. Probiert ihr denselben Sketch auf dem Arduino Pro Mini, dann stellt ihr fest, dass der Sketch nur einmal durchläuft und dann hängt.
#include <avr/wdt.h> const int ledPin = 12; void setup(){ pinMode(ledPin,OUTPUT); watchdogSetup(); } void loop(){ digitalWrite(ledPin,HIGH); delay(1000); digitalWrite(ledPin,LOW); delay(500); endlessLoop(); wdt_reset(); // will not happen } void watchdogSetup(void){ cli(); // disable all interrupts wdt_reset(); WDTCSR |= (1<<WDCE) | (1<<WDE); WDTCSR = (1<<WDE) | (1<<WDP3); // 4s / no interrupt, system reset sei(); } void endlessLoop(){ int i = 0; while(i < 5){ delay(1000); } }
Ein Reset durch den Watchdog Timer ist auf dem Arduino Pro Mini nicht möglich. Das Problem ist dabei der Bootloader. Wie man das Problem durch einen Wechsel des Bootloaders löst, ist hier beschrieben. Es gibt aber auch zwei andere, simple Alternativen, die ich im Folgenden beschreiben werde. Beide beruhen darauf, dass der Watchdog mit Interrupt, aber ohne Reset eingestellt wird. Der Reset erfolgt dann „manuell“ in der ISR.
Workaround 1: Interrupt mit Hardware Reset
Ein LOW Signal am Reset Pin des Arduino Pro Mini initiiert einen Hardware Reset. Dazu könnt Ihr folgende Schaltung und folgenden Sketch verwenden:

#include <avr/wdt.h> const int ledPin = 12; const int resetPin = 9; void setup(){ pinMode(ledPin,OUTPUT); pinMode(resetPin,OUTPUT); digitalWrite(resetPin,HIGH); watchdogSetup(); } void loop(){ digitalWrite(ledPin,HIGH); delay(1000); digitalWrite(ledPin,LOW); delay(500); endlessLoop(); wdt_reset(); // will not happen } void watchdogSetup(void){ cli(); // disable all interrupts wdt_reset(); WDTCSR |= (1<<WDCE) | (1<<WDE); WDTCSR = (1<<WDIE) | (0<<WDE) | (1<<WDP3); // 4s / no interrupt, system reset sei(); } void hardwareReset(){ digitalWrite(resetPin,LOW); } void endlessLoop(){ int i = 0; while(i < 5){ delay(1000); } } ISR(WDT_vect){ hardwareReset(); }
Vertauscht ihr in dem Sketch Zeile 7 und Zeile 8, dann könnt ihr auf den 1 kOhm Widerstand zwischen Pin 9 und RESET verzichten. Ohne das Vertauschen reicht die kurze Zeit, in der Pin 9 auf OUTPUT steht und noch nicht HIGH ist aus, um ein Reset Signal zu geben.
Workaround 2: Interrupt mit Software Reset
Für den zweiten Workaround ersetzt ihr die Funktion hardwareReset() durch eine Software Resetfunktion: void (*resetFunc)() = 0
. Dann ruft ihr die Funktion resetFunc();
in der ISR auf. Oder ihr schreibt lediglich direkt in die ISR: asm volatile ("jmp 0");
. Dafür ist dann keine weitere Verdrahtung notwendig.
Der Nachteil an dieser Methode ist jedoch, dass kein echter Reboot stattfindet, sondern lediglich ein Programmneustart. Der Microcontroller springt auf die Adresse Null. Alle Registerinhalte, Pinstatus, usw. bleiben erhalten, wie sie sind und können so für unerwünschte Effekte sorgen. Gegebenenfalls müsst ihr also noch eine Funktion ins Setup einfügen, die für einen sicheren Ausgangszustand sorgt.
Der Watchdog am ESP8266

Im Vergleich zu den AVR Microcontrollern ist der Watchdog Timer des ESP8266 grundsätzlich anders konzipiert. Zunächst einmal verfügt er über einen Hardware- und einen Software Watchdog Timer. Ohne weiteres Zutun ist der Software Watchdog Timer automatisch aktiviert. Ladet den folgenden Sketch auf euren ESP8266 und schaut auf dem seriellen Monitor (115200 Baud einstellen!) was passiert.
void setup() { //ESP.wdtDisable(); } void loop() { while(1){} }

Wie ihr seht, startet der ESP8266 ca. alle drei Sekunden neu. Bildlich gesprochen „füttert“ der Software Watchdog den Hardware Watchdog, damit dieser nicht „beißt“. Um den Software Watchdog auszuschalten, entkommentiert die Funktion ESP.wdDisable();
und schaut was passiert:

Nun gibt es ca. alle acht Sekunden einen Reset und auf dem seriellen Monitor erscheint „wdt reset“. Das war der Hardware Watchdog. Um zu verhindern, dass der Watchdog beißt, könnt ihr ihn füttern, indem ihr in die while Schleife ein ESP.wdtFeed();
einfügt. Ihr könntet allerdings genauso gut ein delay(x ms);
oder irgendeine andere Funktion einfügen.
Limitierte Einstellungen
Möglichkeiten, Hardware und Software Watchdog Timer am ESP8266 zu konfigurieren, gibt es praktisch nicht. Im Grunde könnt ihr lediglich zwischen den beiden Watchdog Varianten wählen. Habt ihr den Software Watchdog ausgeschaltet, dann könnt ihr ihn mit ESP.wdtEnable(x);
wieder aktivieren. x ist dabei ein Integerwert, der zwingender Maßen übergeben werden muss. Das weckt die Hoffnung, dass man damit Time-Out Periode wählen könnte. Das ist leider nicht der Fall. Egal, ob ihr z.B. ESP.wdtEnable(0);
oder ESP.wdtEnable(4000);
oder ESP.wdtEnable(WDTO_4S);
wählt, der Effekt ist immer derselbe.
Einen komfortablen Watchdog Timer selber kreieren
Wenn ihr einen Watchdog Timer braucht, der ähnliche Funktionen wie die AVR Watchdog Timer besitzt, dann könnt ihr ihn mithilfe der Library Ticker.h mit wenigen Programmzeilen selbst erzeugen. Wie das geht, ist hier kurz und knapp beschrieben.
Danksagung
Den Wachhund im Beitragsbild habe ich von Manfred Richter auf Pixabay, die Stoppuhr stammt von OpenClipart-Vectors, auch Pixabay.
Hallo, danke sieht fast so aus wie ich es bräuchte?
Timer, der eine Relais nach einer bestimmten Zeit ausschaltet und damit den gewählen Vorgang stoppt.
Zeiteinstellung binär mit 8 Bits
7,5 Minten = Jumper 1
15 Minuten= Jumper 2
30 Minuten=Jumper 3
1 Stunde = Jumper 4
2 Stunden= Jumper 5
4 Stunden= Jumper 6
8 Stunden = Jumper 7
16 Stunden = Jumper 8
Mit den obersten 2 Bits kann ich die Wahlzeit dann genügend genau voreinstellen-z.B. 24 Stunden = Jumper 7+8 gesetzt.
Die abgelaufene Zeit könnte man ja per BCD-LED’s anzeigen, alle 7,5 Minuten ändert sich die Anzeige.
Verzeihung, wenn das hier nicht ganz hereinpasst!
Hallo, theoretisch kannst du natürlich den Watchdog-Timer x-mal auslösen lassen und dann dein Relais schalten. Ist nicht unbedingt im Sinne des Erfinders des Watchdog Timers, aber würde gehen. Alternativ könntest du die anderen Timer des ATmega328P in ähnlicher Form nutzen:
https://wolles-elektronikkiste.de/timer-und-pwm-teil-2-16-bit-timer1
Aber alle Timer lösen maximal in wenigen Sekunden aus und nicht in Stunden. Du müsstest immer wieder zusammenstückeln.
Weitere Möglichkeiten zur Zeitmessung:
1) Zeitabfrage über millis()
2) Externe Timer, die für lange Zeiträume konzipiert sind, z.B: https://wolles-elektronikkiste.de/ltc6995-long-timer-low-frequency-oscillator
3) Ein RTC Modul: https://wolles-elektronikkiste.de/ds3231-echtzeituhr
4) Die Zeit über ein DCF77 Modul ermitteln: https://wolles-elektronikkiste.de/dcf77-funkuhr
Vielleicht kommt ja irgendetwas davon in Frage.
VG, Wolfgang
Kleine Ergänzung zum ATTiny85 von Digispark in Verbindung mit der Arduino IDE :
Wenn man den Watchdog benutzen möchte kann man nach obigen Rezepten verfahren, muss aber am Programm Anfang folgende Definition ergänzen:
#define WDTCSR _SFR_MEM8(0x21) // 0x21 ist die Position des WDT im Speicher des ATTiny85.
Dann erst klappt das Kompilieren.
Grund: Über den Boardverwalter wird die Bibliothek von Digistump eingebunden.
Dort existiert leider keine Definition des WDTCSR Registers.
Das zu finden hat echt Zeit gekostet…..
Hallo, vielen Dank, dass du die Erfahrung teilst und so anderen die Fehlersuche ersparst!
Hi, danke für das Tutorial, hätte ich früher lesen sollen, inkl. Kommentare 😉
Vielleicht noch als Ergänzung zu Detlef, beim ATTiny heißt das Register WDTCR (ohne das S). Zu finden im Datenblatt Kapitel 7.9.1.
Grüße
Marius
Schönes Tutorial, jetzt bin ich endlich mal kurz davor das zu verstehen.
WDTCSR |= (1<<WDCE) | (1<<WDE);
WDTCSR = (1<<WDE) | (1<<WDP3); // 4s / no interrupt, system reset
Warum muss hier WDE zweimal aufgerufen werden? und könnte man beide Zeilen auch in einer Schreiben?
Eine Frage hätte ich noch, wo sind die Werte, die hinter zB WDCE stehen definiert? Soweit ich das verstehe wird das Bit ja an einer entsprechenden Stelle gesetzt/geshiftet und zwar am Wert WDCE, oder?
Zur ersten Frage: Man muss diese Sequenz einhalten. Das führt in die tiefen der Register des ATmega328P. Im Datenblatt ist das beschrieben. Es würde hier etwas zu weit führen, das zu erklären.
Zur zweiten Frage:
Es gibt diverse Dateien, die automatisch mit eingebunden werden ohne dass man es merkt, z.B. bei Verwendung des ATmega328P:
C:\Program Files (x86)\Arduino\hardware\tools\avr\avr\include\avr\iom328p.h
Und da finden sich die ganzen Definitionen, z.B.:
#define WDP0 0
#define WDP1 1
#define WDP2 2
#define WDE 3
#define WDCE 4
#define WDP3 5
#define WDIE 6
#define WDIF 7
Das heißt ein (1<<WDCE) heißt schlicht: (1<<4), sprich setze das Bit 4.
Klasse Tutorial, aber in Tabelle 1 mit den Prescaler-Einstellungen befindet sich ein Fehler. Bei 16000 Oszillatorzyklen beträgt der timeout 125 ms oder 0.125 s, aber nicht 0.125 ms.
Gut gesehen! Vielen Dank. Geändert.