Hi,
Do someone know if millis and micros share the same zero base ?
what I want to be sure is :
can I safely assume micros is almost millis*1000 ?
Hi,
Do someone know if millis and micros share the same zero base ?
what I want to be sure is :
can I safely assume micros is almost millis*1000 ?
In theory they have the same zero base, but after 2^32 microseconds micros() will overflow() and the relation is gone
2^32 micros is about 70-75 minutes.
You could modify my Stopwatch class to get a millis() and micros() that always have this relation. But still it will only have it for ~ one hour (or you must include 64 bit math which is really slow or add overflow counters etc.
Interesting idea
Each tick of millis() is a millisecond, but each tick of micros() is four microseconds.
ok,
what I want to be sure is when millis will turn around, will micros turn around in sync ?
As micros is 1000 times millis, I think it will turn exactly 1000 times before millis does, no ?
Unfortunately, I would have to wait 50 days to check this.
I suspect the real issue is... http://xyproblem.info/
If you can provide a valid reason to need the answer, I will provide the answer.
mgth:
ok,
what I want to be sure is when millis will turn around, will micros turn around in sync ?
As micros is 1000 times millis, I think it will turn exactly 1000 times before millis does, no ?
Unfortunately, I would have to wait 50 days to check this.
you can write a simulator that uses millis() + fiftyDaysInMIllis.
Seriously, if it matters to your sketch that millis always indexes forward at exact multiples of 1000 in micros, then you're doing it wrong.
Since both are unsigned long even if they start out synchronised, every time millis rolls over, micros will get a further 296 out of step (due to differences in the base 2 and base 10 systems). Since 1000 % 296 = 112 and the LCM of 10 and 12 = 60 (which is 12 * 5) It will therefore take 5^3 * 2 cycles of millis to get back in step with micros. (ie 250 complete cycles)
But honestly, do you really want this kind of thing in your sketch?
Ok, I will explain what I'm trying to do then :
I wrote a sort of task manager that works great with millis :
It uses a stack, ordered by due times, so each loop I only have to check first element in stack to execute it at due time.
I'm using this successfully with micros too.
Now i'm trying to have an universal version, and I have it working good now, but it rely on converting due times from millis to micros when the task is entering micros "window" and I wanted to be sure it will be roll over proof as it will be used in always power on devices (home automation)
I think I will try to change tick ratio to make roll over occur faster, I think it can go down to one day.
(home automation)
What, in home automation, needs microsecond resolution? Your questions sound like a solution in search of a problem.
Sensor timings need microseconds, I wanted to be able to replace some delay_us by using my task manager, but I'm ok that it could be more a problem than a solution.
Anyway I tried to change Timer0 prescaler to have faster roll over, its running now.
Some feedback :
After one millis full loop, it seams there is no specific drift. Millis and micros stay within 3ms accuracy (actually not real ms because of prescaler change)
here is code used to check :
unsigned long ms, us, old_ms, old_us, loop_ms, loop_us;
byte old_TCCR0A, old_TCCR0B, old_TCNT0, old_TIMSK0;
void restorePrescaler()
{
cli();
TCCR0A = old_TCCR0A;
TCCR0B = old_TCCR0B;
TIMSK0 = old_TIMSK0;
sei();
}
void setPrescaler()
{
cli();
old_TCCR0A = TCCR0A;
old_TCCR0B = TCCR0B;
old_TIMSK0 = TIMSK0;
TCCR0B = TCCR0B & 0b11111000 | 0x01;
TIMSK0 |= 0b00000001;
TCCR0A &= 0b11111100;
TCCR0B &= 0b11110111;
sei();
}
void setup()
{
Serial.begin(115200);
setPrescaler();
loop_us = 0;
loop_ms = 0;
old_ms = millis();
old_us = micros();
}
void loop()
{
ms = millis();
us = micros();
if (old_us > us) loop_us++;
if (old_ms > ms) loop_ms++;
unsigned long ms2 = ms * 1000;
ms2 /= 1000;
// restorePrescaler();
Serial.print(loop_ms);
Serial.print("/");
Serial.print(loop_us);
Serial.print(" - ");
Serial.print(ms);
Serial.print("/");
Serial.print(us);
Serial.print(" : ");
Serial.println(us/1000 - ms2);
old_ms = ms;
old_us = us;
// setPrescaler();
delay(100000);
}
Couldn't you just keep a separate variable within the class to note which kind of time you're using for it.
for example
class schedItem
{
public:
byte timeType;
unsigned long timeFrom;
unsigned long timeDue;
schedItem(unsigned long tFrom, byte tType);
bool checkDue();
};
schedItem::schedItem(unsigned long tFrom,byte tType)
{
timeDue=tFrom;
timeType=tType;
switch(timeType)
{case 0:
timeFrom=micros();
break;
case 1:
timeFrom=millis();
break;
//etc...
}
}
bool schedItem::checkDue()
{
switch (timeType)
{case 0:
return((micros()-timeFrom)>=timeDue);
case 1:
return((millis()-timeFrom)>=timeDue);
//etc..
}
}
I did try this solution, and it works great, but I then have to deal with two queues, one for millis, one for micros if I don't want to compare millis and micros.
So in a final solution I switched to micros, and use an enclosing task that loops n times before to actually fire the task. the problem is only for more than half an hour delay, that I don't use anyway for now.
I will have to deal with that long delay, but it will be in absolute time (fire at 8 o'clock for example) and that's an other story.
For those interested in coherence betwin millis and micros my conclusion is :
It seams to be consistent against roll over.
but as explained elsewhere millis drift 1ms in about 42ms and get resync, not a big deal for me but good to know.
Just had a look through your code but I don't understand how you are stacking the tasks. How many scheduled tasks are you keeping track of at any time?