Pages: [1]   Go Down
Author Topic: Delay() a good way to wait several minutes?  (Read 3234 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 7
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
« Last Edit: July 09, 2008, 02:20:43 pm by maximilian » Logged

Las Vegas, NV
Offline Offline
God Member
*****
Karma: 0
Posts: 507
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged


0
Offline Offline
Newbie
*
Karma: 0
Posts: 7
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Denver
Offline Offline
God Member
*****
Karma: 20
Posts: 779
Inactive - PM
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

Las Vegas, NV
Offline Offline
God Member
*****
Karma: 0
Posts: 507
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged


Denver
Offline Offline
God Member
*****
Karma: 20
Posts: 779
Inactive - PM
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
« Last Edit: July 09, 2008, 07:43:25 pm by BroHogan » Logged

"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

0
Offline Offline
God Member
*****
Karma: 1
Posts: 513
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

Code:
//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(){}  

Logged

Las Vegas, NV
Offline Offline
God Member
*****
Karma: 0
Posts: 507
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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
Logged


0
Offline Offline
Newbie
*
Karma: 0
Posts: 7
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This:
Code:
 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.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 14
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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...
Logged

Melbourne, Australia
Offline Offline
Full Member
***
Karma: 0
Posts: 219
Have you tried turning it off and on again?
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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!
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 14
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17263
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 14
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks I'll try this out asap
Logged

Pages: [1]   Go Up
Jump to: