Go Down

Topic: Efficiently carry out an action ever x seconds. (Read 683 times) previous topic - next topic

mrjonny2

Hi,
I need to carry out a WDT reset every 5 seconds but I want to put in a delay of 10 minutes.
I am unsure of how to use the millis function as I think that is what I need to accomplish it.
I am sure that millis would be better instead of:
Code: [Select]

delay(5000);
wdt_reset();
delay(5000);
wdt_reset();
delay(5000);
wdt_reset();


for 10 minutes.

Thanks

oric_dan

#1
Sep 07, 2012, 12:31 am Last Edit: Sep 07, 2012, 12:33 am by oric_dan(333) Reason: 1
Take a look at the IDE "File > Examples > 2.Digital > BlinkWithoutDelay"
sketch.

millis() BTW uses a long varible that takes something like 49.5 days before it
rollsover to zero.


PeterH

The cheap and nasty hack would be to replace your ten minute delay with a loop that delays for five seconds and then calls the watchdog, and exit the loop when the ten minutes has elapsed. This avoids any major restructuring to your code.

A far better and more general approach IMO is to restructure your code so that instead of executing the actions and delays in a single pass through loop(), it checks whether any action needs to be taken each time loop() runs. So in pseudocode, your logic in loop() becomes:

If watchdog interval has elapsed since the last watchdog reset
    reset the watchdog
endif

If waiting and ten minutes has elapsed
   do whatever needs to be done next
endif

and so on.
I only provide help via the forum - please do not contact me for private consultancy.

WizenedEE

#3
Sep 07, 2012, 08:14 am Last Edit: Sep 09, 2012, 06:10 am by WizenedEE Reason: 1
Why use delay at all?
Code: [Select]

for (unsigned long starttime = millis(); millis() - starttime < 60UL*10; ) {
 wdt_reset();
}


EDIT: or this
Code: [Select]

for (unsigned long starttime = millis(); millis() - starttime < 60UL*10; wdt_reset());

mrjonny2

Thanks guys,
Went with this in the end.

Code: [Select]
unsigned long currentMillis = millis();
                       while((currentMillis - previousMillis < interval))
                       {
                              // save the last time you reset the watchdog
                              previousMillis = currentMillis;   
                              wdt_reset();
                       }

PeterH

It doesn't matter in this case, but if there was more going on in that loop and you wanted to maintain an accurate interval rather than allow the intervals to drift slightly, you'd want to do the increment like this, instead:

Thanks guys,
Went with this in the end.

Code: [Select]

                       unsigned long currentMillis = millis();
                       while((currentMillis - previousMillis < interval))
                       {
                              // save the last time you reset the watchdog
                              previousMillis = currentMillis;   
                              wdt_reset();
                       }



Firstly, that won't work because you aren't updating currentMillis inside the loop. Just call millis() directly instead of using that variable and it will work OK.

Secondly, it doesn't matter in this case but if there was more going on in that loop and you wanted your intervals to be maintained accurately then you would be better to update previousMillis like this:

Code: [Select]

previousMillis += interval;


The reason is that the result of millis() may be greater than (previousMillis + interval) by the time your sketch executes this code since the processor isn't infinitely fast. In effect, you are scheduling the next event based on the time this event was due, not the time your sketch handled it.
I only provide help via the forum - please do not contact me for private consultancy.

mrjonny2

Oh ok so from what I understood I need to do this?

Code: [Select]
unsigned long currentMillis = millis();
                       while((currentMillis - previousMillis < interval))
                       {
                              // save the last time you reset the watchdog
                              previousMillis += interval;   
                              wdt_reset();
                       }

wildbill

Quote
I need to carry out a WDT reset every 5 seconds


Why do you need to do this?

PeterH


Oh ok so from what I understood I need to do this?


No, you need to call millis() within the loop. I suggest you simply get rid of currentMillis completely and replace any reference with a call to millis().
I only provide help via the forum - please do not contact me for private consultancy.

Go Up