Delay() a good way to wait several minutes?

I'm making a device that has to do something every 8+minutes, and it has to be pretty precise. At first I thought that delay would be the easiest way to do this, but I wasn't sure.

So basically I:

DoSomething() //not much, just fire a few LEDs
delay(~8mins)
DoNextthing() //again, just some LEDs
delay(~8mins)
DoSomething()
delay(~8mins)
DoNextThing()
etc for like 8 times and then wait another hour and repeat.

I thought about looping on millis(), but I was a little worried about the overflow, because my device will be on for long periods of time. I need about 1/2s to 1/4s resolution that has to be pretty exact as far as the delay goes. Using Delay would introduce some slip, but I guess the micro really is running pretty fast, so 1ms in arduino time is really long.

Also, how accurate is delay compared to wall-clock time. I'm using a maxim-ic clock to handle most of my time-keeping, but I'm wondering how much slip would be introduced by a 8min delay?

Delay() achieves its delay by looping on millis(), and I'm not sure if it handles the millis() overflow properly (you'd have to check the code in wiring.c). You could consider making your own delay that loops on millis() and correctly handles the overflow by noting when the new value of millis() is less than the previous value of millis(). If your delay loop is tight enough (and it should be), only a millisecond will have elapsed by the time you notice the overflow. Or maybe delay() does this already?

  • Ben

I think I saw your thread talking about the millis() overflow issue.

Since I do have a clock with alarm-interrupt capability, I think i might just try and use that. Like, alarm a second before I need and then delay for the small time increment I need so that I don't loose too much.

Just gotta figure out the second alarm on the clock.

Some clocks, like the DS1307, have a "Clock Out" pin that can be set to 1 pulse / sec. You could use that to trigger an ISR and count until you have 8 min.

You may have a DS1306 though. If so, I think the slowest Clock Out is 1Hz.

That seems like total overkill for a microcontroller that already has three timers that are clocked off of an incredibly accurate external crystal. Why not just use the one of the timers the mega168 has? Overcoming the millis() overflow bug is simple enough, but if you don't want to do that, can't you set up your own version of millis() that is adequate for your needs?

  • Ben

Sorry, just thought I'd mention it as an option. I thought he already had a clock in circuit, so it would only mean adding 1 wire. For me there is also something appealing about a nice slow interrupt that only happens once per second. It seems it would give more programming options than waiting on a delay. Just my opinion.

This won't drift at all within an hour if doSomething and doNextThing take less than 8 minutes. You can subtract a milliseconds or so from hour to account for the instructions at the top of loop too.

//pre arduino 12 only
extern volatile unsigned long timer0_overflow_count;    
void setup(){}

#define eight 480000  //milliseconds in eight minutes
#define hour 3600000  //milliseconds in an hour

void loop(){
  timer0_overflow_count=0;  //reset millis to 0 at top of each loop so no overflow issues
  unsigned long loopstart=millis();
  unsigned long nextEvent=loopstart+eight;
  for(int x = 0;x<8;x++){
    doSomething();
    while(millis()<nextEvent);
    nextEvent+=eight;
    doNextThing();
    while(millis()<nextEvent);
    nextEvent+=eight;
  }
  nextEvent+=hour;
  while(millis()<nextEvent);
}
  
void doSomething(){}  
void doNextThing(){}

Sorry, just thought I'd mention it as an option. I thought he already had a clock in circuit, so it would only mean adding 1 wire. For me there is also something appealing about a nice slow interrupt that only happens once per second. It seems it would give more programming options than waiting on a delay. Just my opinion.

You don't need to apologize (I didn't mean to come off as overly critical), it's good to get all possible solutions to a problem. In this case, it just seems to me like it's an unnecessary one given what the mega168 can already do and the simple application. Now if maximilian is already using all of the timers for some other tasks, using an external clock source might be the ideal solution. If not, when using a system clock of 16 MHz, you can get an interrupt once per second by using a timer1 overflow interrupt with timer1 set to the system clock / 1024 and the TOP value set to 15624 (just make sure it's running in CTC mode or fast PWM mode and not phase-correct PWM mode as the Arduino software initializes it to be). If you are using a system clock of 8 MHz, you would use timer1 with a prescaler of 256 and a TOP value of 31249.

You could even get an interrupt less often: once every 4 seconds with timer1 using a clock of 16 MHz / 1024 and a TOP of 62499 or once every 8 seconds with timer1 using a clock of 8 MHz / 1024 and a TOP of 62499. If you use timer1 in a mode where it counts up to TOP and then back down to BOTTOM, you could effectively halve this interrupt rate by adjusting these TOP values very slightly.

  • Ben

This:

  timer0_overflow_count=0;  //reset millis to 0 at top of each loop so no overflow issues

Will reset the millis() timer?! Cool. I like that code up above. I'm gonna try it out. I think a combo of that and my alarm will work nicely.

Thanks for the help.

Hello I've been using this method for quite some time now but when I use this for long periods something goes off I left my logger to log every 30 seconds and now when I checked the SD card it was empty.
I tried reformatting the card and do a sample testing and what happened was it was logging at random intervals, about milli-seconds apart from each other, so I think the reason why the SD card was empty was because of an overflow...

The best way of knowing the answer for such questions is to try it.

Everyone can have their own opinion: But if it works, it works!

If it doesn't, just make a function called delay_8min(). Check the millis time when you start the function and stay there until millis equals:

Start time + 8 minutes

and...
8 min = 8 min * 60 sec/min * 1000 msec/sec = 480,000msec

Too easy!

Thank you invalid apple. It was indeed easy. I have a new problem now I think I found already what's crippling my code... Turns out that I still get the 9 hour rollover issue...
I'm really new to this but I've tested my code up to 8 hours. But when we tried logging for more than 8 hours my SD card ended up being empty. Is this code still crippled by the 9 hour rollover? Odd thing is that the code above used unsigned long which has a max count of more than 4,000,000,000...
Thanks in advance

For me there is also something appealing about a nice slow interrupt that only happens once per second. It seems it would give more programming options than waiting on a delay. Just my opinion.

There is also a very simple to use timer library called MsTimer2 in the playground that allows you to have interrupts generated at a programmable time frame you define.

http://www.arduino.cc/playground/Main/MsTimer2

Lefty

Thanks I'll try this out asap