I'm working on a project that uses a watchdog timer that times out after 4 s. After it times out, I would like to blink an LED at 2 Hz for 5 s, and then reset the board.
My approach is to use the watchdog time out interrupt to blink the LED and then reset the board. However, the only methods that I know to blink an LED (delay(), millis(), and Timer0/1/2) all require interrupts, so I can't use them within an interrupt. I think the resolution of micros() would be too fine to blink at 2 Hz.
Is there actually a way to do this or do I need to take a different approach?
Reset the timer for 500ms, set a counter to 0, then toggle the LED state and increment the counter every time the ISR executes. After the counter reaches 10 then reset the board.
littleB:
I'm working on a project that uses a watchdog timer that times out after 4 s. After it times out, I would like to blink an LED at 2 Hz for 5 s, and then reset the board.
My approach is to use the watchdog time out interrupt to blink the LED and then reset the board. However, the only methods that I know to blink an LED (delay(), millis(), and Timer0/1/2) all require interrupts, so I can't use them within an interrupt. I think the resolution of micros() would be too fine to blink at 2 Hz.
Is there actually a way to do this or do I need to take a different approach?
One can create a delay out of a spin loop (e.g. for (long int k=0; k < big_number; k++) { nop ; }), but spending a long time in an interrupt routine is generally considered bad practice because it blocks any background tasks the processor is performing.
TheMemberFormerlyKnownAsAWOL, I originally thought of using micros() to replace Millis(), but micros() only goes up to 4 ms. I guess I could scale it by 125 to get a 500 ms delay.
littleB:
I'm working on a project that uses a watchdog timer that times out after 4 s. After it times out, I would like to blink an LED at 2 Hz for 5 s, and then reset the board.
Your question is a bit ambiguous. You are asking about a watchdog timer. Is it for the Arduino or another board. I get the impression the Arduino is the watchdog monitoring another board. If this is correct you do not need to use an ISR, it can all be done in the program loop. If you want to reset the Arduino create a function that does nothing and does not return. This will cause the watchdog to time out resetting the Arduino if you enabled it earlier, if not it just appears to stop forever until reset. More information will get a better answer. You have the advantage the problem is in front of you we cannot see it. This response is to help you get started in solving your problem, not solve it for you.
Good Luck & Have Fun!
Gil
TheMemberFormerlyKnownAsAWOL, I just realized I completely misread the info on the micros() function.
Paul__B, yes the watchdog timer resets the board if you have that enabled, which I do. You can enable an interrupt to happen just before the board reset, which is where I'm trying to blink the LED.
gilshultz, the watchdog timer is for the Arduino. I'm not using any other boards with it.
what's the best way to reset the timer to a new configuration? I can't really do it within the interrupt because the 500 ms watchdog timer will also use the same interrupt function, so it would just be reset to the same configuration every time
Here is my attempt using Nicolas Larsen's watchdog timer tutorial. However, using this code the LED only blinks for 4s instead of 5s. Is this due to the nature of the watchdog timer reset? Is there a way to ensure that the LED completes the full 5s before the reset?
I also tried disabling the reset on the watchdog timer and then using resetFunc() in the ISR after the blink loop. But the board never resets, the LED just continually blinks. I'm guessing that resetFunc() won't work within an ISR for some reason...
#include <avr/wdt.h>
#define LED 12
// setup function to be run once
void setup()
{
Serial.begin(9600);
Serial.println("Starting up...");
pinMode(12, OUTPUT);
watchdogTimeOut();
}
// setup watchdog timer
void watchdogTimeOut(void)
{
cli(); // disable all interrupts
wdt_reset();
// Enter Watchdog Configuration mode:
WDTCSR |= (1 << WDCE) | (1 << WDE);
// Set Watchdog settings:
WDTCSR = (1 << WDIE) | (1 << WDE) | (1 << WDP3) | (0 << WDP2) | (0 << WDP1) | (0 << WDP0);
sei();
}
// loop to be run continuously
void loop()
{
}
ISR(WDT_vect) // Watchdog timer interrupt.
{
for (int i = 1; i <= 5; i++)
{
digitalWrite(LED, HIGH);
for (int i = 1; i <= 1000; i++)
{
delayMicroseconds(500); // keep delay short to retain accuracy
}
digitalWrite(LED, LOW);
for (int i = 1; i <= 1000; i++)
{
delayMicroseconds(500);
}
}
}
Do it the normal/proper way.
In your ISR set a flag (bool variable), and let the loop() function deal with it. E.g. a variable timeout, set to true when timeout occurs, and then have loop() call the appropriate function to blink or whatever you want to do.
wvmarle:
Do it the normal/proper way.
In your ISR set a flag (bool variable), and let the loop() function deal with it. E.g. a variable timeout, set to true when timeout occurs, and then have loop() call the appropriate function to blink or whatever you want to do.
Normal/proper way is to never let the WDT trigger. If it triggers it means something is terribly wrong. Returning to the loop and hoping it will start executing properly is risky. It may be done with the reset-after-interrupt mode of the WDT but you must be very careful the loop cannot bypass the WDT if you implement this.
littleB:
Here is my attempt using Nicolas Larsen's watchdog timer tutorial.
ISR(WDT_vect) // Watchdog timer interrupt.
{
for (int i = 1; i <= 5; i++)
{
digitalWrite(LED, HIGH);
for (int i = 1; i <= 1000; i++)
{
delayMicroseconds(500); // keep delay short to retain accuracy
}
digitalWrite(LED, LOW);
for (int i = 1; i <= 1000; i++)
{
delayMicroseconds(500);
}
}
}
When an ISR runs it turns off interrupts. That is okay for a few microseconds but your sketch isn't the only thing using interrupts, you can screw Serial all to hell for example and throw millis() off with a long ISR.
for (int i = 1; i <= 1000; i++)
{
delayMicroseconds(500); // keep delay short to retain accuracy
}
Retain accuracy? Just the opposite, you include the time to run the loop in your delay of delays.
delay() and delayMicroseconds() take unsigned long args. They can count to over 4 BILLION.
delayMicroseconds() can time over 71 minute intervals using unsigned long values.
delayMicroseconds() can time over 65 ms using unsigned int, max value is 65535 usecs = 65.535 msecs.
The usual thing is to have a Status Led blink while the sketch runs which requires NO interrupt. If the sketch crashes the status led stops blinking, if the sketch is sick the blink will not be on time.
To do that your code needs to be non-blocking... no delays or wait-loops to step on the status blink.
This is not only possible but preferable and in this forum it's the lesson du jour every day.
Smajdalf:
Normal/proper way is to never let the WDT trigger.
Maybe the OP should explain in more detail what their 4-second watchdog timer is.
I interpret it as some kind of external signal, not the built-in WDT (I'm all too familiar with the WDT of the ESP8266, actually didn't realise the ATmega also has one - it seems you have to actively enable it).