Go Down

Topic: Staggering millis() timers (Read 197 times) previous topic - next topic

clearlynotstefan

Hi Folks, and thanks in advance for your help. I am literally brand new at this. What's the preferred way of staggering 2 millis timers at start, but then having them keep the same (offset) interval from there.

 I have a variable that is set by a smart device that is programmed to change every 60 seconds. I am trying to get code to recognize if that variable stops flipping every 60 seconds, as a way of sensing if it's lost connection to my smart home platform (even if the internet is still connected). I'm thinking 2 variables, say "t2" and "t1", with t2 getting its value from the smart-home flipping variable every 120 seconds starting at launch and t1 getting its value from the smart-home flipping variable every 120 seconds starting at 65 seconds. Then some code to take an action if those numbers are ever equal (not worried about that part yet).

Code: [Select]
  int t1;     // variable for keeping local copy of the switch current state 1
int t2;     // variable for keeping local copy of the switch current state 2
int st;     // external flipping switch

unsigned long previousMillis = 0;
unsigned long interval = 120000;


//code that sets "st" based on reading smart home status goes here but is omitted (if switch on, set st=1 if switch off set st=0)

//st is the variable that alternates between 1 and 0 based on an external switch every 60 seconds

unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;
    t1 = st;
   
    Serial.print("     t1 is ");
    Serial.print(t1);
  }

 
unsigned long previousMillis2 = 65000;

   unsigned long currentMillis2 = millis();
    if (currentMillis2 - previousMillis2 > interval) {
    previousMillis2 = currentMillis2;
    t2 = st;
    Serial.print("      t2 is ");
    Serial.print(t2);
  }
//code that reacts if t1 == t2 goes down here




When run as written with the serial window open I see it picking up values at it goes, but they aren't right. t2 gets read much more frequently than it should and I can't figure out why. The only difference in my mind is that the starting time is should be staggered back 60 seconds (previous millis 2), but that once it loops the first time it should share the same interval of 2 minutes with the first portion except 60 seconds behind it. What am I doing wrong?

Thanks,
Stefan

blh64

I think you are over complicating it.  If you want to see if this external variable is flipping every 60 seconds. You just have to remember the previous state it was in and the time you recorded that previous state.  You then check to see if the variable has changed and if so, reset your previous state and time.  If it hasn't and your interval has expired (60 seconds or 120 seconds), then you know you've lost your connection.  If the interval hasn't expired, you continue...

johnwasser

Code: [Select]
unsigned long previousMillis2 = 65000; 

Things go wrong if you say that your timer started 65000 milliseconds in the future.  Since the math is unsigned, subtracting 65000 from a value less than 65000 will give you a very large number.  You interval will be exceeded immediately. 

 I suspect that your previousMillis2 is not a global and gets set to 65000 each time through the function.  That means your interval will have elapsed every time until 65000+interval has elapsed.  After that it will never trigger again.
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

johnwasser

#3
Sep 24, 2018, 02:01 am Last Edit: Sep 24, 2018, 02:02 am by johnwasser
If you want to delay the start, use something like:

Code: [Select]
static unsigned long previousMillis = 0;

unsigned long currentMillis = millis();
  if (currentMillis > 65000 && currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;
    t1 = st;


Note: This will only work correctly for about 49 days.  When the millis() counter rolls over to 0 the trigger will be delayed another 65 seconds.
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

Robin2

I have a variable that is set by a smart device that is programmed to change every 60 seconds. I am trying to get code to recognize if that variable stops flipping every 60 seconds, as a way of sensing if it's lost connection
A simple way to do that is to save the value of millis() every time the smart device sends a message. Something like this

Code: [Select]
if (messageReceived == true) {
   lastMessageMillis = millis(); // reset the clock when a message is received
}

if (millis() - lastMessageMillis >= timeoutInterval) { // clock was not reset within timeout
  // communicaation is lost
}


...R
Two or three hours spent thinking and reading documentation solves most programming problems.

clearlynotstefan

A simple way to do that is to save the value of millis() every time the smart device sends a message. Something like this

Code: [Select]
if (messageReceived == true) {
   lastMessageMillis = millis(); // reset the clock when a message is received
}

if (millis() - lastMessageMillis >= timeoutInterval) { // clock was not reset within timeout
  // communicaation is lost
}


...R
Now that is genius. With the help of the prior posters I made a version that did work by keeping track of the state and time at which the state was taken, per one users example, so thank you as well other poster, but this is even more intuitive/simple! Thanks again!

I can see this getting pretty addictive, the possibilities are endless!

clearlynotstefan

A simple way to do that is to save the value of millis() every time the smart device sends a message. Something like this

Code: [Select]
if (messageReceived == true) {
   lastMessageMillis = millis(); // reset the clock when a message is received
}

if (millis() - lastMessageMillis >= timeoutInterval) { // clock was not reset within timeout
  // communicaation is lost
}


...R
So I've got this working now, but now it's got me wondering how this plays out in 47.5 days (or whatever it is). As I said, I'm really new at this, so I'm practically guessing honestly, but will this put me in a bad position when it rolls over? Wouldn't millis() turn into some tiny number post roll, then, once the last time (some giant positive number before rollover) is subtracted, wouldn't we have a giant negative number and be waiting for it to be larger than  the interval before checking again? Would appreciate some clarity from anyone!

UKHeliBob

Quote
it's got me wondering how this plays out in 47.5 days (or whatever it is).
49 and bit days, but no problem

Whenever you subtract an older time from a newer one, you get the correct unsigned result. No matter if there was an overflow.

To make it easier to understand let's use an byte variable instead of unsigned long as the numbers are easier to get your head round.

Example: If your old time was at 250 and now you're at 5 , you calculate (5 - 250) and interpret the result as an unsigned byte, the result is 11.
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

clearlynotstefan

49 and bit days, but no problem

Whenever you subtract an older time from a newer one, you get the correct unsigned result. No matter if there was an overflow.

To make it easier to understand let's use an byte variable instead of unsigned long as the numbers are easier to get your head round.

Example: If your old time was at 250 and now you're at 5 , you calculate (5 - 250) and interpret the result as an unsigned byte, the result is 11.
Thanks!

And thanks to everyone else again as well, you've got a great community here.

Go Up