Millis() variable time updating

Can anyone explain why var_time in the code below is changing while var_t is true? I was under the impression the variable var_time would hold the value of millis() when var_t went true?

boolean var_t;
boolean var_top;
unsigned long var_time;

void loop(){

    if (var_t == true) var_time = millis();
    
    if (millis() - var_time >= 10000) var_top = true;

}

    if (var_t == true) var_time = millis();

Because of this line ?

1 Like

its not actually changing...you're calling millis() a second time & thats returning a different number for millis()

here is my standard, basic timing method:

uint32_t nextUpdateTime;
uint16_t updatePeriod;

void loop()
{
       if(millis() >= nextUpdateTime)
       {
               //do work
              nextUpdateTime+= updatePeriod;      //set the next time to run this
       }
}

you'll have to integrate whatever your doing with the bool vars.

That code won't properly handle the millis value overflowing, but with a very slight change it will.

#define INTERVAL 1000

static uint32_t t = 0;

void loop() {
	if (millis() - t >= INTERVAL) {
		// do work
		t += INTERVAL;
	}
}

if by not handle the overflow, you mean that the timing is irregular at the rollover then, yes I agree. But the program doesn't break at the rollover or anything. I use this when precise timing is not needed...printing serial reports for example. For precise timing, I usually turn to internal interrupts.

I will take your changes in advisement though. Could you explain your use of "static" ? I've only just learned how & when to use static...but thats only inside the context of classes. I don't really understand its meaning in the main namespace like that.

It is actually changing, I am writing var_time to a custom variable along with var_t. When var_t is true, var_time is incrementing. I need var_time to stay constant with the millis() of when var_t went true.

did you try the code we posted (either version) ?

assuming your most recent comment was about your original code:

this line is never run:

 if (var_t == true) var_time = millis();

walk it through, var_t is initiated as 0 (false), you never modify...therefore var_time is always 0 . millis is greater than 10,000, not immediately, but very quickly. so the second if statements "always" hits, but it only changes var_top which isn't even used anywhere else

seems like you meant that second if statement to read like this:

 if (millis() - var_time >= 10000) var_t = true;

now when you come back through the loop, the first statement will hit, set the current time then wait until the next time to do it all over again.

you could change the first if statment to check var_top, same effect. Point is, I think you've mixed up var_t & var_top.

It could.

Consider the scenario, where nextUpdateTime is calculated and is just short of the rollover point(4,294,967,295 ms), say 4,294,967,290ms ... so 5 ms short of the rollover.

If your other processing code takes longer than 5ms to execute in the next loop, then millis() will roll over and the next time you compare millis() >= nextUpdateTime this will be false... and remain false for the next 49 days at least.

The way @nicolajna has described is the correct way to handle millis(). It will never have a problem.

I have not mixed them up. Var_t is actually a digital input, when it goes true I need a snapshot of millis(), and if var_t is true longer than 10 seconds, then var_top is true. The issue is that var_time does not hold the snapshot of millis, it is incrementing as long as var_t is true.

Above was just a simplified version of testing code, which does the same thing as my actual code, maybe easier to under stand if you see more of it below.

    if (Tank.HighATO.IsActive() || Tank.isATOTimeOut()) topoff = false;
    else if (Tank.LowATO.IsActive()) topoff = true;
    
    if (topoff == true) topoff_t = millis();
    else topoff_t = 1000; //to show variable reset
    
    if (millis() - topoff_t <= 10000) Tank.Relay.Off( Port8 ); // if topoff true < 10 sec, port off
    else Tank.StandardATO( Port8 ); //else use standard top off routine
    Tank.CustomVar[2]=topoff_t/1000; //for monitoring variable in seconds
    Tank.CustomVar[3]=topoff; //for monitoring topoff flag where timer should start

Would be easier if you posted all your code, and advise exactly what is not working as you expect.

And a full description of the arithmetic of both ways (addition vs subtraction) is available here. The addition way is perhaps more intuitive, in that it sets a target time and you keep looking at the clock to see if you got there yet, but it's not the right way to ensure the overflow is handled correctly.

Also if nextUpdateTime overflows before millis the comparison will be true until millis overflows.

A cautionary tale:

At the company I work at we had a somewhat similar bug (had to do with comparing two different data types, but the effect is the same). We were working on a device which, among other things, periodically sent some telemetry data using a mobile connection. The bug was introduced in the part of the code which triggers the telemetry routine to run, which caused the device to send data as fast as the connection allowed. The subscription we had for the device was one of those very cheap IoT subscriptions with high overusage fees. We caught this during a longer testing phase, so we were able to effectively mitigate it, but a few devices did manage to cost us around a 1000USD in just a few days.

Sure, when declaring a variable or function as static in file scope, it makes that symbol visible only to that file. It serves a couple of purposes, mainly avoiding naming conflicts and hiding internal state from other parts of the program. If you were to take a look at a larger C codebase (I'm a C developer after all) you'll see the static keyword used like that all the time, but in C++ you'll typically see it less since it has classes/namespaces and all that.

In my example it's not necessary, but old habbits die hard.

1 Like

It is impossible to see the problem with this small snippet. But with the line

var_time will always be updated to the actual value of millis as long as var_t is true, not only when it becomes true.

huh?

you're still not showing us anything that does anything to the variables in question. what makes var_t true? thus far, the code you've posted operates the way I narrated in my previous response. I don't doubt you're doing something with it, but you haven't shown us.

post the whole program, or at least all of main.cpp if its a big program.

since I have no idea what else your program does, I start by asking if you're doing anything to modify timer0 ? that runs micros() & millis(), changing them will cause problems.

I really dont want to play anymore guessing games, post the code. also advise what board you are compiling for.

thank you. I'm not a coder, so my knowledge is spotty. I've done deep dives in to specific topics, but am missing some of the in between.

with the code they've posted, do you see var_t being set to anything? I don't. But I think they are toggling var_t elsewhere in the loop.

Hi guys,

you are all posting code as wild and start side-way discussions and nobody asked for a real clarification wthat the TO wants.

@tole365 post your complete sketch using this method

There is an automatic function for doing this in the Arduino-IDE
just three steps

  1. press Ctrl-T for autoformatting your code
  2. do a rightclick with the mouse and choose "copy for forum"
  3. paste clipboard into write-window of a posting

it doesn't matter if your code has 2000 lines.
If you add a hint in which linses of code you think the problem is

add a comment like "here is the problem"

Then anybody can search for this keywords here is the problem and will quickly find the place.

best regards Stefan

I agree, the simple action of posting a complete sketch would likely lead quickly to a solution. Instead, it's just, "I did this, I did that" responses which can't be resolved outside of the full context.

myself & several others have. Read the thread before you accuse "everyone" of something. had you done that, you'd also have seen the op is more than capable of copy & paste, but thanks for the instructions :man_facepalming:

How can I get a snapshot of millis time for when var_t goes true?

first of all you should use self-explainig names. "var_t" says nothing about the purpose of this variable

This is done by state-change-detection
This requires a flag-variable


boolean Var_t_changed = false;

if (lastVar_t == LOW && Var_t == HIGH) { // check if this is the first time that lastVar_t and Var_t are different
  if (Var_t_changed == false) { 
    // if snapshot of time was not yet made
    Var_t_changed = true; // set flag-variable "snapshot now done!"
    SnapShot = millis(); // store snapshot of time
  }
}

lastVar_t  = Var_t; // update lastVar_t

this is more or less the basic principle

best regards Stefan