Using millis() to create a single time delay

I need to create a single 5 second time delay within a function, and then set a flag which will be used and reset later on in the sketch. I have it working with the following code. Just wondering if there is a more elegant way to do it, hopefully without introducing the two extra variables, flag and startTime? See below....

// initialize gateOpenDelay and flag  to zero(0)

  int gateOpenDelay = 0;
  int flag = 0;
  
// initialize the gateOpenDelayTime to 5 secs, and startTime to zero(0)
  long gateOpenDelayTime = 5000;
  long startTime = 0;

....some code here which was deleted for brevity sake.....

  void delayGateOpen (){
  // this function delays opening the gates.
   
   // If it is the first time through this function, record the start time and
   // set flag = 1 to skip recording the start time next time through this function
    
    if (flag == 0) {
    startTime = millis();
    flag = 1;
  }
    // If the timer is finished, then set the flag gateOpenDelay  = 1

   if (millis() - startTime >= gateOpenDelayTime) {
     gateOpenDelay = 1;
    }  
   }

I'm confused. If you are concerned about remaining SRAM then why is your flag two bytes?

unsigned long gateOpenDelayTime = 5000;
unsigned long startTime = 0;

[quote author=Coding Badly link=topic=232175.msg1673522#msg1673522 date=1397093708]

I'm confused. If you are concerned about remaining SRAM then why is your flag two bytes?

[/quote] Coding Badly - thank you for your quick response. When you say my "flag is two bytes", would you kindly elaborate what this means. I am very new to Arduino, so please go softly on your explanation. Thanks in advance.

Don

When you say my "flag is two bytes", would you kindly elaborate what this means.

The variable type int takes up two bytes of memory. As it is only a flag you only need one bit. As it is not easy to get one bit of storage you can at least halve the ammount of memory this flag takes up by making it a boolean type, that only takes one byte.

Int definition http://arduino.cc/en/Reference/Int

Grumpy_Mike: The variable type int takes up two bytes of memory. As it is only a flag you only need one bit. As it is not easy to get one bit of storage you can at least halve the ammount of memory this flag takes up by making it a boolean type, that only takes one byte.

Grumpy_Mike - thanks for the explanation. I did not know the variable type "int" takes up two bytes of memory. How do I make it a boolean type variable?

I am not strapped for SRAM yet. Just curious to know if there is a better way to create a time delay than what I have shown above.

Don

Is “unsigned long” used when you are not sure if the value will go negative? I have seen both “long” and “unsigned long” used in example “blink without delay” sketches. I am not exactly clear when to use one vs. the other. Please feel free to point me to a link if this is too basic of a question to ask on this forum.

Thanks,

Don

dz63:
I have seen both “long” and “unsigned long” used in example “blink without delay” sketches. I am not exactly clear when to use one vs. the other. Please feel free to point me to a link if this is too basic of a question to ask on this forum.

Don-

Good question. Check out "Blink without delay" example sketch has bugs · Issue #1618 · arduino/Arduino · GitHub.

Regards,

Brad
KF7FER

Brad - thank you for the helpful link. The blink without delay sketch referred to in the link is in fact one of the sketches I was using as a reference. I also noticed on this forum another sketch where the author used "unsigned long". I tried it both ways in my sketch and they both worked.

Anyone in the know care to comment what the difference is? Any any disadvantages to using "unsigned long" for the startTime or "unsigned int" for the gateOpenDelayTime?

dz63: I tried it both ways in my sketch and they both worked.

I've edited BlinkWithoutDelay and changed the data type of previousMillis to an int, and then watched it fail after 16 blinks (or so, roughly 32 seconds). I suspect your test would have failed as well you just didn't wait long enough :-)

In general the idea is to use the smallest data type that will properly hold the values you will be expecting (so you aren't wasting memory).

So for example, to properly handle the output of Millis() you should use an unsigned long.

As Nick said in that link,

It is better to suggest unsigned long for time variables, to get beginners into the right method from the start.

Did that help?

Regards,

Brad KF7FER

dz63: Any any disadvantages to using "unsigned long" for the startTime or "unsigned int" for the gateOpenDelayTime?

As @Brad Burleson mentioned, if you use the wrong datatype your application has a high probability of behaving in unexpected ways (i.e. being buggy).

You have yet to establish that you are actually running short of SRAM.

So, the answer to your second question is "yes". The disadvantage is that there is essentially no cost to using unsigned long and using something else could lead to unexpected behaviour.

This Thread seems to have become very complicated for no good reason.

Variables that store the value from millis() should be defined as unsigned long because that's what millis() returns. The Arduino Reference will tell you the sort of variables (if any) returned by the various functions.

Don't worry about using extra flag variables - in general that is a good way to do things. Your objective should be to write code that is easy to understand 6 months later.

...R

Actually, the extra flag variable is not needed. It will be set to true when startTime is set to 0, and will be set to false later.

You could, instead, set startTime back to 0. Then, startTime == 0 means one thing and startTime != 0 means something else, the same as the flag being true or false would.

[quote author=Brad Burleson link=topic=232175.msg1673572#msg1673572 date=1397098216] I've edited BlinkWithoutDelay and changed the data type of previousMillis to an int, and then watched it fail after 16 blinks (or so, roughly 32 seconds). I suspect your test would have failed as well you just didn't wait long enough :-)

In general the idea is to use the smallest data type that will properly hold the values you will be expecting (so you aren't wasting memory).

So for example, to properly handle the output of Millis() you should use an unsigned long[/quote]

Brad - that is helpful. Thanks for sharing the results of your test. 32 seconds makes sense as I have read that int stores a 16-bit (2-byte) value. This yields a range of -32,768 to 32,767 which would explain the 32 seconds (ie. 32,000 milliseconds).

Robin2: Don't worry about using extra flag variables - in general that is a good way to do things. Your objective should be to write code that is easy to understand 6 months later.

Robin2 - thanks for confirming that using extra flags is a good way to program and reinforcing that writing code that is easy to understand in 6 months time is more important than keeping it short. I won't sweat adding the extra flags.

[quote author=Coding Badly link=topic=232175.msg1673614#msg1673614 date=1397101200] So, the answer to your second question is "yes". The disadvantage is that there is essentially no cost to using unsigned long and using something else could lead to unexpected behaviour.[/quote]

Coding Badly - thanks for confirming that there is no "cost" to using unsigned long. That is what I was wondering about.

Grumpy_Mike:
The variable type int takes up two bytes of memory. As it is only a flag you only need one bit. As it is not easy to get one bit of storage you can at least halve the amount of memory this flag takes up by making it a boolean type, that only takes one byte.

Anybody know how to make a flag a boolean type variable as Grumpy_Mike recommends?

A boolean is just a variable type like int. So you just declare it that way.

boolean flag = false; // or true, or unitialized 
// flag can any be valid variable name
boolean areTheZebrasRunningAway = false;

PaulS: Actually, the extra flag variable is not needed. It will be set to true when startTime is set to 0, and will be set to false later.

You could, instead, set startTime back to 0. Then, startTime == 0 means one thing and startTime != 0 means something else, the same as the flag being true or false would.

PaulS - brilliant suggestion! :)

That simplifies my code and gets rid of one unnecessary flag. I just tried it and it works perfectly! Instead of using the flag variable, I simply "trigger" off of the value of the startTime variable.

Since startTime is initialized at 0, the first time through the loop, it is still zero(0), so then I set startTime = millis(). On subsequent passes, since startTime is no longer equal to zero(0), it bypasses this step. Very clever idea! Thank you for taking the time to review my code and share this suggestion.

Don

For the benefit of anyone reading this in the future, here is the resulting simplified code including the "boolean" variable declaration shared by Jimmy60...

 boolean gateOpenDelayComplete = false;
 unsigned long gateOpenDelayTime = 5000;
 unsigned long startTime = 0;

...some code removed here to keep this short...

    void gateOpenDelay (){
 // this function delays opening the gates.
    
 // If it is the first time through this function, set the startTime = current time. 
//  On subsequent passes, this step will be skipped.
    
    if (startTime == 0) {
    startTime = millis();
  }
   
 // When the timer is finished, then set the gateOpenDelay flag = true
// This gateOpenDelayComplete flag is reset to "false" later in the sketch.
   
   if (millis() - startTime >= gateOpenDelayTime) {
     gateOpenDelayComplete = true;
    }  
   }
  }

millis() rolls over every 49.7 days or so. If your Arduino program is going to be running this long, AND if this code could be executed when millis() == 0, then startTime could get set to 0 once again. Maybe the boolean flag is needed after all?

One time (first time) setup should be placed in the setup() function. Unfortunately, you then may need to have some global variables, and this may make some people unhappy.

millis() - startTime ... etc works properly through a millis() rollover. No special arrangements are needed. That's the "beauty" of integer maths.

...R