arduino to do something every 5 days. overcome millis() overflow??

hello forum. i am building a project, that will require an atmega chip, to among other things, turn on a relay (for 3 hours), every 5 days..

the arduino itself, is supposed to be constantly working (it will never loose power)., so i was wandering, what would be the best way to do this with software?? my problem is, that after 50days, the millis will overflow, so i will have bugs... any way to overcome this??

P.S ; would it be easier, to just do a software reset, after the 5days + 3 hours??? if yes, what would be the best way to do this??

thanks allot!

Real Time Clock chip, maybe?

unsigned long currentMillis;
usigned long previousMillis;
unsigned long elapsedTime;
unsigned long duration = 3600000UL; // one hour

void setup(){
// whatever

// end with:
previousMillis = millis();
}

void loop(){
currentTime = millis();
elapsedTime = currentTime - previousTime;
if (elapsedTime >=duration){
previousTime = previousTime + duration;
// start relay, stop relay, using flags to indicate state, # of times performed, whatever
} // end time interval check
} // end loop

Will never have a rollover problem.

cross roads, i cant really understadn your code... :/ i mean, what is the idea behind it?? can you please explain again??

also, isint there a way, to just force overflow, the millis() every 5days+3 hours??? that would seem like the easiest way...

currentTime = millis();
elapsedTime = currentTime - previousTime;

The above handles roll-overs automatically without issue, as long as you perform the subtraction shown

Lefty

Never to say never. If duration is 60 days, you need some intermediate counter too. I think an rtc will be the way to go. Use adafruit rtc library for unix time support so you can calculate 5 days in seconds and compare current time against the alarm time.

liudr: Never to say never. If duration is 60 days, you need some intermediate counter too. I think an rtc will be the way to go. Use adafruit rtc library for unix time support so you can calculate 5 days in seconds and compare current time against the alarm time.

Oh course. OP had stated a ( after the 5days + 3 hours??? ) interval time well below the need for any thing additional, it would work fine for his need.

i dont want to use anything additional, like an external clock or something. i bealive it can be done easier with code...

i dont get why this code should work..

currentTime = millis();
elapsedTime = currentTime - previousTime;
if (elapsedTime >=duration){
previousTime = previousTime + duration;

as i see, elapsedTime , will indeed always stay bellow one hour, but previousTime , will always get an even biger number, and eventually, it will reach 50 days... what cant i see??

in a complete diferent approach: since the code i will be using for things i want to be done, will be fair simple , couldent i use a "Cycle " method?? like, its time the main_loop is run one time , i raise a flag by one, and have a delay somewhere, to know how many time, it takes for one cycle... something like this ::

int cycle;

void setup() {
  
cycle = 0 ;

}


void loop () {
  
   cycle++;    //here it will start with a fake cycle, but its a small error
  
  if ( cycle > (cycles required for 5 days)  ) {
     //do the things i want it to do //
     
  }
  
  
  if cycle > (cycles required for 5 days + 3 hours)  {
   cycle = 0 ;
    
  }
  
  delay(1);
  

}

as i see, elapsedTime , will indeed always stay bellow one hour, but previousTime , will always get an even biger number, and eventually, it will reach 50 days... what cant i see??

What you are not seeing is the mystery and amazement of unsigned long variables which are using binary 32 bit math. When one does a subtraction there is a extra carry/borrow bit available that makes the calculation work beyond the roll-over interval. Only if your desired timed event periods are more then the 50 day rollover, then it's never an issue. There have been several posting over time here that explain the binary math down to step by step values proving that millis() roll-over time does not have to be a concern.

But it seems to be a horse that can't be beaten too much. ;)

Lefty

i see... well, do you think that the cycle method would work?? it seems way to easier, and in my application, i can set the delays to be even 100ms , wich will lower the energy consumption of the arduino(i think??), wich would be good, since i will be running on battery...

settra: i see... well, do you think that the cycle method would work?? it seems way to easier, and in my application, i can set the delays to be even 100ms , wich will lower the energy consumption of the arduino(i think??), wich would be good, since i will be running on battery...

The recommended method is to utilize the code example crossroads posted.

unsigned long currentMillis;
usigned long previousMillis;
unsigned long duration = 3600000UL; // one hour

void setup(){
// whatever

// end with:
previousMillis = millis();
}

void loop(){
currentTime = millis();
elapsedTime = currentTime - previousTime;
if (elapsedTime >=duration){
previousTime = previousTime + duration;
// start relay, stop relay, using flags to indicate state, # of times performed, whatever
} // end time interval check
} // end loop

This example supports keeping track of one event time, 1 hour. Adding additional variables and constants allows one to time an almost unlimited number of separate and independent event timings.

wich will lower the energy consumption of the arduino(i think??),

No, the AVR chip draws a near constant current ( 25mA or so as I recall) no matter what code it is executing, it never stops or halts, but rather is executing continuously at 16Mhz clock rate. Only drawing variable currents from digital output pins have an effect on chip current consumption. Only by using various AVR chip sleep modes can you reduce chip current but such is a more advance features not supported directly with any arduino supplied functions.

Lefty

My focus has been fail-safe for months at a time so I saw "never" and my eye brows started to contract towards my forehead ;)

I think the RTC is a very decent solution. You start your project by reading the UNIX time on the RTC using adafruit rtclib library. Then you calculate the 5 days in advance and only trigger events when this time elapsed. You may even save it in EEPROM so your system won't lose counts between power cycles or sketch uploads. It would lose counts quite easily due to power cycle and code upload, right?

liudr: My focus has been fail-safe for months at a time so I saw "never" and my eye brows started to contract towards my forehead ;)

I think the RTC is a very decent solution. You start your project by reading the UNIX time on the RTC using adafruit rtclib library. Then you calculate the 5 days in advance and only trigger events when this time elapsed. You may even save it in EEPROM so your system won't lose counts between power cycles or sketch uploads. It would lose counts quite easily due to power cycle and code upload, right?

Horse won't die will it. ;)

Have a look at the Arduino Time and TimeAlarms libraries. --- bill

well, do you think that the cycle method would work??

That is what is set up - 1 hr cycles. Add a counter or two to keep track of how many hours of on-time occurred, how many total hours occurred. And when the cycle is to start again.

@crossroads

Maybe what is throwing SETRRA is the same thing that kind of throws me?

I see this setup:
unsigned long currentMillis;
usigned long previousMillis;

but then I see this usage:
elapsedTime = currentTime - previousTime;

I guess I sort of expected to see
elapsedTime long or int or something
currentTime long
previousTime long

In other words, some similiar sort of initialization in there.

Just a guess.

yep, unsigned long elapsedTime; should have been in with the rest.

I've gonee back & added it.

i still cant get why a code like that would work... want the previous time, reach a maximum value after some days??

a more precise version of the code i previous posted is that :

int cycle
int time_elapsed
int end_time
int start_time


void setup() {  
  cycle=0 ;
}


void loop () {
 start_time=  millis();
  
  cycle++;
  
  if (acc==HIGH)OR( cycle >= 5days cylces ) {       //5days 
    
   do some things    
  }
  
        
  if (cycle > 5 days + 3 hours cycles) {
  cycle = 0 ;
   }
   
  end_time=millis() ;
  
  time_elapsed = end_time - start_time ;
  
  delay (100 - time_elapsed);

}

which takes in account, how much time, it takes for the program to run, so that you know that every cycle is precise 100ms. BUT this will also have a problem when millis() rollover, because the "Time_elapsed" would be negative.

so now i ask : is this what the unsigned long do? they cant be negatives, so its like saying x= |x1 - x2| ?? (The absolute value)

OK, a little searching brought out the posting thread (one of several as I recall) where how 32 bit subtraction works and how it deals with the millis() roll-over non-problem.

http://forum.arduino.cc/index.php/topic,42997.0.html

Lefty

settra, any variable that is part of the millis() cycle -must- be an unsigned long or risk overflow. That is because millis() is an unsigned long.

So:

unsigned long time_elapsed
unsigned long end_time
unsigned long start_time

An int or a long can be positive or negative (on an Arduino, int and long are both 32 bit signed, so -2M to 2M). It is an unsigned long that is only positive (32 bit unsigned, so 0 to 4M). In that case, it rolls over (or under) as described in the link given.

http://arduino.cc/en/Reference/UnsignedLong

http://arduino.cc/en/Reference/Int