I'm building a project by programming an arduino using an atmega168 or a 328, then setting the fuses to use the internal clock at 8mhz (i think), and then removing the chip and putting it into a breadboard with my own circuit.
The project is going to run 24/7, but I would like to use an if() to have it run a special command once every day or so. Its not exact by any means, but i need to know when somewhere around 24-100 hours have gone by. Thus I don't really care how inaccurate the internal clock is.
I've read that the millis() function has been fixed to use the whole of the long int, which is around 55 days.
So a few questions:
will I really get ~50 days out of millis()? Its hard to test this one:)
What exactly happens to millis() when it overflows?
2(a). if it really simply just resets to 0, does this affect ANYTHING else? The clock, other variables or registers or ANYTHING? I need to know if this is going to cause me a hassle.
3.just in theory, what about if this runs for 4 years? will there be any problem when millis() has overflowed a few times?
What would you recommend to keep track of, say, 50 hours? Use modulus somehow? I've been typing a few suggestions here, but none of them work when I finish thinking them through. I have a feeling I'm just tired and missing something simple.
It is 0xFFFFFFFF (the maximum possible unsigned long) one millisecond, and then 0 the next.
No, not unless you have written your code poorly.
To do something every 24, 50, or 100 hours do this:
#define EVENT_INTERVAL_HOURS 24 // change this to 50 or 100 if you want
unsigned long last_event_time = 0;
void setup()
{}
void loop()
{
if (millis() - last_event_time >= EVENT_INTERVAL_HOURS * 60UL * 60UL * 1000UL)
{
// do your thing here
...
// now reset the counter
last_event_time = millis();
}
}
actually I thought of one thing. Say you're at 54 days and have an event that occurs every 5 days.
after the overflow, millis()-last_event_time will be 0-54 days and, well, you get where I'm going with this.
so is this if statement the way to fix it?
#define EVENT_INTERVAL_HOURS 24 // change this to 50 or 100 if you want
unsigned long last_event_time = 0;
void setup()
{}
void loop()
{
if(millis()< last_event_time)
last_event_time=0;
if (millis() - last_event_time >= EVENT_INTERVAL_HOURS * 60UL * 60UL * 100UL)
{
// do your thing here
...
// now reset the counter
last_event_time = millis();
}
}
If you want to work in periods of hours or days then you may want to use the DateTiem library: Arduino Playground - DateTime
Here is an example sketch that shows how you can call a function after a given number of hours.
#include <DateTime.h>
time_t lastEvent = 0; // this holds the time of the last event
void doAlarm()
{
// do something here every 50 hours
}
void setup()
{
Serial.begin(9600);
DateTime.sync(0); // start the clock (1st Jan 1970)
}
void loop()
{
time_t elapsedTime;
elapsedTime = DateTime.now() - lastEvent; // calculate the elapsed time
if(numberOfHours(elapsedTime) >= 50) { // has it been at least 50 hours
doAlarm();
lastEvent = DateTime.now(); // store the time for this event
}
}
It certainly is worthwhile to look at the DateTime library, but whether you do or not, I want to clear up a misconception. The code I posted will trigger every 24 hours for 5, 50 or 500 days, and doesn't need any "fixing". In fact the "fix" you propose will cause it to fire early every 50 days and should be avoided.
This works because of the way unsigned subtraction works in C, where the expression "0 - 0xFFFFFFFF" is 1 just the same way "10 - 9" is.
If you want to test the stability of a program near the millis() overflow, halley's suggestion is a very good one.