In this tutorial I am using a Attiny85 microcontroller and I want a LED to blink at approximately 1 second interval.
Usually with Arduino and other blink tutorials you just use a delay of 1 second or 1000 milliseconds to turn it on and off. In this tutorial we are going to use a special function of the MCU that rarely get the attention it deserve.
Now who let the dog out you might say, and I laugh.. haha..
The watchdog is normally used as a safety measure, for if the MCU is in an unreachable place and it hangs up for some reason, you have no way of resetting it and get it working again. So the watchdog is an almost separate part of the MCU, it has a clock of its own (normally a RC circuit) and a prescaler of this clock, now what it doesn’t have is a timer compare or a way to set a precise timing. There's only the overflow.
Now for a ATtiny85 there are 10 different prescaling settings to use, from 16ms to 8 seconds ( see datasheet p.46 for details). Normally the watchdog is used to reset the MCU but it can also be set to run a interrupt.
First off, let’s start with setting up the watchdog.
// Disable all interrupts cli(); /* Clear MCU Status Register. Not really needed here as we don't need to know why the MCU got reset. page 44 of datasheet */ MCUSR = 0; /* Disable and clear all Watchdog settings. Nice to get a clean slate when dealing with interrupts */ WDTCR = (1<<WDCE)|(1<<WDE);
WDTCR = 0; // Setup Watchdog for interrupt and not reset, and a approximately 500ms timeout P.45
WDTCR = (1<<WDIE) | (1<<WDP2) | (1<<WDP0); // Enable all interrupts.
This is the safe way of setting it up, the reason why we do some “cleaning” in the beginning is to make sure we get what we want. static and who knows what can mess up a MCU so it’s a good thing to do it right, if you don’t want to be safe, all you need is this line
WDTCR = (1<<WDIE) | (1<<WDP2) | (1<<WDP1);
Now we have the watchdog set up and doing nothing, well not really, as the watchdog is a safety measure it does have some intricate moves. In this case we are telling it to run a ISR every 500ms (approximately) but we haven’t made a ISR for it yet, and as I said this function have some intricate ways of functioning so when the ISR is run, the watchdog automatically switches from interrupt mode to reset mode !!!!
Unless the interrupt mode is re-enabled in the ISR.
So, let's make a blinky ISR
// Flip bit 3 of PORTB PORTB ^= (1<<3); /* ReEnable the watchdog interrupt, as this gets reset when entering this ISR and automatically enables the WDE signal that resets the MCU the next time the timer overflows */
WDTCR |= (1<<WDIE); }
Now we have a ISR that flips the LED you have connected to PORTB3 on and off every 1/2 second and re-enables the interrupt.
Wasn't this easy?
Here is the full MrBlinky c file.