I am curious to know if there is any reason to not have millis() entries proliferated throughout my code, or if i should set some variable equal to millis() somewhere in my loop section and make my references to that variable? Wouldnt using a variable tie up more memory?
If you set a variable equal to millis() then all following code will refer to that time period.
Also, calling millis() through out the the sketch may be slower than just referring to a once set variable.
One other thing to point out is that the compiler is very, very clever. If it can, it may just stash the value in a set of registers and constantly refer to them, using no RAM at all.
Unlikely with a 32 bit value on an 8 bit machine, but it is possible.
"Wouldnt using a variable tie up more memory? "
Gonna tie up 4 bytes reading millis() and either using it or saving it, no matter what.
I capture millis() or micros() once at the top of loop() and then have all comparisons done based against that one number.
Ok thanks for the help everyone. I thought i might have been causing a crash by working it this way but i think it may be caused by something else (likely electrical...). Using freeRam() i get over 1300 free depending where i am in the code (1320-1340 or so), so even if i am tying up 4bytes i should have plenty free, still.... maybe. Oh well. I will simplify it into a single variable but i dont expect it to solve some of my reset and erratic issues. I'll make a different thread when i start getting a handle on whats happening.
KeithRB:
One other thing to point out is that the compiler is very, very clever. If it can, it may just stash the value in a set of registers and constantly refer to them, using no RAM at all.
Unlikely with a 32 bit value on an 8 bit machine, but it is possible.
Wrong. That reasoning works for most variables, but not those that are volatile-qualified.
The variable the millis() function references is volatile-qualified, so the compiler is not allowed to optimize away or even reorder any access to it. Every single invocation of millis() will pull this value fresh from the memory again.
Also, calling millis() involves accessing the SREG register to disable and re-enable interrupts. Every hardware register is volatile-qualified, so those statements cannot be optimized away or reordered either.
Im not sure i follow what jiggy is saying, but i think i did "create" some stability but referencing a variable instead of millis(). Still getting some weird gitchiness in the program that im 99% sure is program and not hardware.
LarryD:
If you set a variable equal to millis() then all following code will refer to that time period.
Also, calling millis() through out the the sketch may be slower than just referring to a once set variable.
As far as I understood, millis() was already a variable that is automatically incremented by the Timer0 overflow interrupt handler...so it is pretty much exactly the same as "just storing in a variable"?
unsigned long millis()
{
unsigned long m;
uint8_t oldSREG = SREG;
// disable interrupts while we read timer0_millis or we might get an
// inconsistent value (e.g. in the middle of a write to timer0_millis)
cli();
m = timer0_millis;
SREG = oldSREG;
return m;
}
Literally...assigns a long variable (m), halts interupts, sets the value of m to the value of timer0_millis which is the number of overflows of milliseconds.
Johnny010:
As far as I understood, millis() was already a variable that is automatically incremented by the Timer0 overflow interrupt handler...so it is pretty much exactly the same as "just storing in a variable"?
thank you
unsigned long millis() {
return timer0_millis;
}
There would be the extra time to call the millis() function, but nothing that I would guess be that much.
Johnny010:
As far as I understood, millis() was already a variable that is automatically incremented by the Timer0 overflow interrupt handler...so it is pretty much exactly the same as "just storing in a variable"?
millis() is a function, not a variable. As Johnny010 posted, the TIMER0_OVF ISR updates a global variable called timer0_millis. All the millis() function does is provide atomic access to that value by disabling interrupts when it is being copied, and reloading the interrupt state before returning.
KeithRB:
There might be a mills variable somewhere, but we access it with a function call. (Can the call be inlined?)
Yes it can, as long as any access to volatile-qualified variables remains in order. That means no caching; every time millis() is called, the SREG must be read, interrupts must be disabled, timer0_millis must be copied from memory, and SREG must be reloaded with the old value. All 4 of those actions involve accessing a volatile variable, so the compiler is not permitted to remove or reorder those statements.
LarryD:
There would be the extra time to call the millis() function, but nothing that I would guess be that much.
Interrupts will be disabled for a significant part of that first time.
Edit
About 190uS difference.
Nanoseconds actually, which is just about 3 clock cycles of time. That's probably accounted for by assuming that the compiler inlines the millis() function. Both statements are performing a copy of the unsigned long value to another memory location, but millis() requires the extra steps of reading SREG, disabling interrupts, and reloading SREG. Each of those things should be able to be done in 1 cycle each, so there's the extra time accounted for.
In the grand scheme of things, it's probably not that big of a deal. If your code is so fragile that having interrupts disabled for a few more microseconds each loop causes problems, you have a serious problem. I prefer to cache millis() at the start of loop() into a local variable, but I'm not going to bite anyone's head off if they're calling it fresh each time.
newneo_phyte:
Im not sure i follow what jiggy is saying, but i think i did "create" some stability but referencing a variable instead of millis(). Still getting some weird gitchiness in the program that im 99% sure is program and not hardware.
Most of this conversation is probably not relevant to your issue, but store it away for later - it's very informative of the inner workings of your machine.
As a specific answer to your question, you can use the function millis() at any time, and all it does is return an unsigned 32 bit number that represents the number of milliseconds the Arduino has been on. If you don't use it, it just disappears, you won't be penalized by throwing away 4 bytes of RAM.
For non-blocking, fast executing parts of your sketch, the value of millis() will change by one at most for the entire segment. In these cases, you can save a few cycles by using an unsigned long variable. Perhaps call it "currentMillis". Unless your program benefits by saving half a microsecond per call, it doesn't make a difference which way you deal with millis().
My 'usual habit' is to call millis() explicitly whenever I need the time.