Timing question

Hi there, kinda random question. So I built a timer that runs off of the millis command, over the course of 4 weeks it gets off by 15 seconds so its A ok in my book (the interval for millis is 997 actually) But so now I'm wondering. If I wanted to make a sketch that won't lock up after 49-50 days because the millis() overflows. How would one internally to the arduino, reset the millis command after say 25 days? I know I can probably get an external timer and then just reset it "manually" off of a digital pin or something after a few days. But can you do something like this internally.

Also while I'm already here. I know that unsigned long gets you an unsigned 32bit number right. How do you tell the arduino to work with somethign larger then that, 64 bits or so?

Gosh! How to prevent roll over? I don't think this has ever been mentioned before.

64 bits? "long long"

just long long

really, its that simple... (makes something overly complected now by using, byte byte to be an int)

So noone's tried to prevent rollover before. Is there any way then, to tell millis() to be a specific number? Then handle the rest of the switch with obscure code?

Do you seriously think the question has not come up before, debated and solved?

I dont know what timing you are doing. Do you need to measure something that lasts longer than 49 days? Or is that you use the wrong algorithm when measuring with millis() ?

unsigned long Timer ;
:
if ( millis() - Timer > Interval ) { /* ... */ }

that works accross a rollover (the magic of unsigned integer math)

Do you seriously think the question has not come up before, debated and solved?

No I do not seriously think. Just like you responded to my question in sarcasm, I responded with my own idiocity. However as it stands, looking through about 8 pages (had to leave because i have to go to school now) I couldn't find an explination of how to do it. Lots of "millis() making a blink without delay, do other stuff" no countering rollover.

Now odds are if what Msquare said

I dont know what timing you are doing. Do you need to measure something that lasts longer than 49 days? Or is that you use the wrong algorithm when measuring with millis() ?

Code:

unsigned long Timer ; : if ( millis() - Timer > Interval ) { /* ... */ }

that works accross a rollover (the magic of unsigned integer math)

holds true, I probably have something random in my code else thats making it lockup at rollover. Which I'll find later. but whatever.

This should help you get started. For convenience I defined

typedef unsigned long long time_t;     /* Define the time_t data type         */

and then wrote

/*----------------------------------------------------------------------------*/
/* Define a translation unit scope variable to hold latest RESET time         */
/*----------------------------------------------------------------------------*/
static time_t rst_time = 0-0;          /* Epochal time of latest RESET (msec) */
/*----------------------------------------------------------------------------*/
/* Extend micros() for 64-bit up-time                                      TU */
/*----------------------------------------------------------------------------*/
static time_t u64(void)
{  static union                        /* Definitions to allow accessing time */
   {  time_t hl;                       /* As a whole, or as...                */
      struct                           /* Anonymous struct container          */
      {  unsigned long l;              /* Lower half and...                   */
         unsigned long h;              /* Upper half                          */
      };                               /*  end: (anonymous) {}                */
   }  u = { 0 };                       /* Initialize to zero                  */
   static unsigned long t;             /* Variable to hold micros() value     */
   if (u.l > (t = micros())) ++u.h;    /* If micros() wrapped, adjust         */
   u.l = t;                            /* Save updated low half               */
   return u.hl;                        /* Return 64-bit usec time             */
}                                      /*  end: u64()                         */
/*----------------------------------------------------------------------------*/
/* Return current date/time as usec into the epoch                            */
/*----------------------------------------------------------------------------*/
time_t now(void)
{  return rst_time + u64();            /* Return reset time + uptime          */
}                                      /*  end: now()                         */
/*----------------------------------------------------------------------------*/
/* Set RESET date/time using externally-supplied current epochal date/time    */
/*----------------------------------------------------------------------------*/
void set_time(time_t t)
{  rst_time = t - u64();
}
/*----------------------------------------------------------------------------*/

to keep time in 64-bit microseconds. If you prefer milliseconds, just change micros() to millis(), but note that once you make the decision to keep 64-bit time, there is no practical penalty for the added microsecond precision, since the 64-bit time in microseconds won't roll over until year 584542 of the epoch.

millis() rollover is not a “problem” per se, and does not cause a lockup, it just restarts (rolls over) at zero after reaching its maximum value of 232-1. This is only a problem if you are trying to time an interval longer than ~50 days, in which case, using the Time library may be a good alternative, with or without an external real time clock.

Consider an 8 bit millis() value, and the “interval = millis() - lasttime;”
When lasttime == 100 and millis() == 110, the interval is 10 milliseconds, and presumably code works fine.
Now, when lasttime == 250 and millis == 4 (wrap has occurred), 4 - 250 == -246, which is … 10, still, when treated as an 8bit unsigned quantity. So as long as you’re reasonably careful, wrap of the counter should not be a big problem…