Using Millis instead of delay - help

Hello everyone,

I have read in several threads that using "delay" make the program stop completely and that is is recommended that we use millis or micros.

I am thing to implement this based of reading the reference (help) and I am wondering if I am missing anything.

The idea is that IF a condition is true, a pin will be set to high for 600 milliseconds, then the pin returns to low.

unsigned long fdelay;

if (variable = 1) 
{
  fdelay = millis();
  do{
  digitalWrite(Pin12, HIGH);
  while fdelay < 600);
  digitalWrite(slPin12, LOW);
 }

That's no better than delay. You're still just holding up the sketch until the delay period is over.

WHILE is probably the most OVERUSED keyword used by noobies. Stop thinking WHILE and learn to use IF.

Here's a bit of pseudo code to help you understand.

unsigned long thingStarted;

void loop()
{
unsigned long t=millis();

if(somecondition)
  {startSomething();
   thingStarted=t;
  }


if ( (t-thingStarted) >=fdelay)
 {stopSomething();
 }
 
 
}

Like KenF said, this part:

  do{
  digitalWrite(Pin12, HIGH);
  while fdelay < 600);

is the same thing that using a delay. But, in this case, your code will never work because of the errors you have in the code. First you need to close the brackets of the do/while loop. Second you need to read the time inside the loop. If you don't the loop will never end! So, in order to work, you need to do something like:

  do{
  fdelay = millis();
  digitalWrite(Pin12, HIGH);  
  } while fdelay < 600);

But like I said, this is the same thing that using the delay.

crullier:
Hello everyone,

I have read in several threads that using "delay" make the program stop completely and that is is recommended that we use millis or micros.

I am thing to implement this based of reading the reference (help) and I am wondering if I am missing anything.

The idea is that IF a condition is true, a pin will be set to high for 600 milliseconds, then the pin returns to low.

unsigned long fdelay;

if (variable = 1)
{
  fdelay = millis();
  do{
  digitalWrite(Pin12, HIGH);
  while fdelay < 600);
  digitalWrite(slPin12, LOW);
}

Even simple code like this should be commented and it will give you some ideas what is incorrect.

if (variable = 1) logical error - assignment instead of evaluation

if the variable can be true or false ONLY you can just evaluate it this way to avoid this common and little hard to find error

if(variable)

{
fdelay = millis(); // start time of evaluation ( after variable is true ) , not a delay - lStartTime would be better name for variable

// turn LED (or whatever ON
digitalWrite(Pin12, HIGH); // not necessary to be in do loop - set it once

do
{
//digitalWrite(Pin12, HIGH); // not necessary to be in do loop
//while fdelay < 600); // syntax do/while error - compiler will complain , but it may not be obvious

} while( millis() - 600 < fdelay); // current time - "magic number " 600 less than starting time / interval

// turn LED off after 600 ms
digitalWrite(slPin12, LOW); // typo - compiler will let you know
}

Look at how millis() is used to manage time in several things at a time

...R

gentleman thank you for all the responses and help.
I think I understand how to use millis and micros now and I see what I was doing wrong.

I really appreciate Vaclav post and his comments. It made it all very clear.

@Robin2, I will look at your thread tomorrow and it is certainly something I want to learn in more detail.

Last but least,

KenF:
That's no better than delay. You're still just holding up the sketch until the delay period is over.

WHILE is probably the most OVERUSED keyword used by noobies. Stop thinking WHILE and learn to use IF...

Ken, I actually was trying to use while to get out of the IF, then nobness. I thought that by using While, or do while my sketches would become more elegant or sophisticated? Can you please explain what you mean by your comment to better understand where my train of thought is failing?

Also, why is what I suggested the same as a delay() ?

I changed a variable so it makes more sense:

do
{
  startime = millis();
  digitalWrite(Pin12, HIGH);  
  } 
while startime < 600);

Again, thank you everyone for the help !

Ken, I actually was trying to use while to get out of the IF, then nobness. I thought that by using While, or do while my sketches would become more elegant or sophisticated? Can you please explain what you mean by your comment to better understand where my train of thought is failing?

When you have something that needs to be turned on and then off, it should be seen as TWO events, not one. The first event is turning it on, the second event is turning it off. Both of these conditions should be checked for separately.

For example, you want to get an LED to light up for a half a second. The typical noobie mistake is seeing this as just one event, it gets turned on and then the program comes to a halt WHILE that half second is passing by.

So you should expect to see plenty of IFs in your loop.

IF the user is pressing a key, take the appropriate action.
IF an LED needs turning on turn it on
IF an LED needs turning off turn it off
IF the display needs updating, do it

IF allows you to do something when a condition is met but doesn't hang around.
using WHILE to wait for something is generally a bad thing. If you're waiting your delaying.

KenF,

Thanks for the explanation. So in my original proposal, the sketch would be waiting for the Millis variable to reach a value and during this time my sketch would be sitting still as in DELAY.

Btw, all of you guys' earlier post helped and I was able to refine my sketch.

crullier:
KenF,

Thanks for the explanation. So in my original proposal, the sketch would be waiting for the Millis variable to reach a value and during this time my sketch would be sitting still as in DELAY.

Btw, all of you guys' earlier post helped and I was able to refine my sketch.

You are getting there but not yet.

You -can- watch the clock for later time but some day it will pass 12 and start again.
That will work as long as you never pass the clock limit. Arduino millis() limit is just over 49.7 days. But micros() limit is just over 90 minutes!

What we do is to find the difference between two times up to the clock limit apart.
This lets us run many timed processes off one clock and not care how long the sketch is running.

millis() and micros() return unsigned long variables for time and because they are unsigned, if you use unsigned longs as well then simply subtracting the earlier time from the later time you will always get the positive difference between the two, same as if I look at a 12 hour clock, from 11 to 2 is 3 hours.

unsigned long startMillis, elapsedMillis;

..... later

startMillis = millis();

...... later on

elapsedMillis = millis() - startMillis; // elapsedMillis now holds how much later on.

We also trigger events using if ()

if ( millis() - startMillis >= waitMillis )
{
// do what should be done when time is up, which might include resetting startMillis
}

****** as far as while loop in your case

Arduino has setup() for things that run once and then loop() which goes round and round, every time a bit later than last. Every time, your code may do something so you don't need to do everything in a single pass through loop().

In fact, if your loop() has more than one thing to do like check 2 different things, having one thing that sometimes or always takes long will hold up the other and may make it late checking. :o(

Don't forget that besides time, a common thing to check is the state of a pin. If your loop() is always fast you won't need an interrupt to do that in timely fashion either. Interrupt costs cycles to run too!

You also may have if (Serial.available()) in your loop but serial is slow compared to Arduino so I usually put that last, especially if a human is behind it. They don't notice 100ms most of the time.

For smooth multiple task coding, keep what anything does short. Sometimes this will mean running a task in stages, what is called process states. One variable keeps the state value and when the overall task runs it only does what the current state should. This gives you a very powerful yet simple tool, look around for tutorials on finite state machines to get started.

Okay, lets see if I am understanding..

I am adding my responses/questions to your code.

unsigned long startMillis, elapsedMillis;  <- you defined two variables with one line. Clever trick. This works for all types of variables?

//LATER I CODE.

startMillis = millis(); // When the processor get to this line it will start the timer...

//MORE CODE TO BE EXECUTED.

elapsedMillis = millis() - startMillis; // elapsedMillis now holds how much later on.. When we get to this line, the millis() tells the arduino to take a time reading again and then look at the time it has passed since the original millis(). Does the math which is PRESENT TIME (whatever it is) - ELAPSED TIME.

We also trigger events using if ()

if ( millis() - startMillis >= waitMillis ) <- Here I am guessing I would type the VALUE for wait Millis.
{
  // do what should be done when time is up, which might include resetting startMillis
}

Correct me if I am wrong, but what I am getting from this is that every time I write:

Variable = millis();

in my code or millis(); for that matter I am asking the arduino to start the timer at that precise time and whatever that value is, is irrelevant, could be 0:00, or 20 etc. What make it work is the difference between such current time and previously running milli() or even user input. For instance:

(millis()-600); essentially means 600mS.

If so, with that said,

the suggested code earlier that was:

if... 
{
  startime = millis(); // Start time evaluation
  do   {
  digitalWrite(Pin12, HIGH);
  }
  while (millis()- 600 < startime);
  digitalWrite(Pin12, LOW);
}

I presume that this will hold the sketch the 600mS since I am using WHILE. Is there a way to make this work with an IF?

I have tried the code below but doesn't seem to work..

if... 
 startime = millis(); // Start time evaluation
 digitalWrite(Pin12, HIGH);
 if(millis()- 600 < startime); 
 {
  digitalWrite(Pin12, LOW);
 }

Last question, 

Is there a difference between:

millis() - 600 < starttime  and  millis() - starttime < 600 ?

Correct you then.

When the board starts up, the millis and micros counters also start.

The command millis() returns how many milliseconds since startup.

So if the board has been running for 1 second, millis() will be 1000UL. UL is for unsigned long.

2.5 seconds later millis() will be 3500.

40 days later is will be some very large value and 10 days after that it will be very small.
But if I subtract the 40 days value from the 50 days value the answer will be 10 days.

If I am using micros() the rollover will be in a bit over 90 minutes.

The subtraction is the safe way to write time code.

You're getting closer.

Just to put things into perspective. If your loop function doesn't do any waiting around you can expect the whole loop to be executed within about 20 MICROseconds. So the loop function will run about 50 times every millisecond.

Now the first thing you'll likely be looking for is a condition where you want to set that output high. If this condition is met you'll set that output high AND take note of what millis holds at this time. This you will hold in a variable that is declared OUTSIDE the loop function (otherwise it will get reset less than 20 microseconds later).

The second condition you'll want to check is whether your input is due to be turned OFF. You'll do this by comparing the current value that millis hold against that note you took when you turned it on.

Something like this.

//Variable declared OUTSIDE loop so it doesn't get reset every pass through
//For now it doesn't hold anything relevant.
unsigned long pulseStart;

void loop()
{
//get a note of what millis holds THIS time through loop
unsigned long t=millis();  

//check if output needs to be turned ON
if (variable == 1)
  {
  digitalWrite(13,HIGH);
  //keep a note of when we turned it on using the variable we declared OUTSIDE the loop
  pulseStart=t;
  //You'll also need to do something to stop 
  //our condition being true next time through the loop
  //maybe something like:
  variable=0;
  }
  
//check if output needs to be turned OFF  
if ( (t-pulseStart) > 600)
  {
   digitalWrite(13,LOW); 
  }

//Down here we can do other stuff too
//this loop will run about 30,000 times (maybe even more) between
//turning the output on and turning it off again 
}

millis() is not a timer, it's a clock!
When you look at or note the time of the clock, does it reset itself?
Imagine you're baking a cake. It takes one hour to cook. When you put the cake in the oven you note the start time from the clock. You don't sit around in front of the oven for an hour twiddling your thumbs, you get on with other things, checking the time regularly. Only when an hour has passed do you stop whatever else you were doing and take the cake out of the oven. So:
timeNow = look at the clock
startTime is when you put the cake in the oven.
cookTime = 1 hour.
loop(){
Is the cake done? Is timeNow - startTime =>cookTime?
No...get on with something else.
Yes...take the cake out of the oven.
}

Henry_Best:
millis() is not a timer, it's a clock!
When you look at or note the time of the clock, does it reset itself?
Imagine you're baking a cake. It takes one hour to cook. When you put the cake in the oven you note the start time from the clock. You don't sit around in front of the oven for an hour twiddling your thumbs, you get on with other things, checking the time regularly. Only when an hour has passed do you stop whatever else you were doing and take the cake out of the oven. So:
timeNow = look at the clock
startTime is when you put the cake in the oven.
cookTime = 1 hour.
loop(){
Is the cake done? Is timeNow - startTime =>cookTime?
No...get on with something else.
Yes...take the cake out of the oven.
}

My wife just uses the smoke alarm. :slight_smile:

been editing my earlier post and trying to work / learn / digest all the info. didn't realize you guys would respond.

@Henry, thank you for the baking analogy / clock. That makes more sense. I was wrong in my earlier post then.

so with the case analogy I should be able to use IF rather then WHILE and create a statement that says (as previously demonstrated).

Look at time, put cake in oven;
IF (one hours has passed since the time I put the cake in the oven);
turn off the oven.

So when is it appropriate to use while, or Do...while?

When it doesn't hold up checking on the cake!

When I have 16 buttons, I check one each time loop() runs.
That lets all my other tasks to get a step in between button checks.
I do not process all 16 buttons and then check on my cake!

Use loop() to work through lists except for the short and fast ones.
Make loop() run fast and all your tasks inside will work together smoothly, unless there are too many.

The first link at the bottom of my posts is to a tutorial on starting this kind of coding.
Nick explains about blocking including why and how to not block code.

You would use WHILE when there are a number of actions to perform that can be easily terminated by the condition.

So for instance if you're copying a string of characters from one char array to another.

char source[]={"SOME TEXT TO BE COPIED"};
char dest[30];

int index=0;

while(source[index] !=0 )
  {
   dest[index]=source[index];
   index++;
  }

You'll note that the WHILE here isn't waiting for some time to pass, it's checking an endpoint has been reached.

So basically you should think of it as While there's something to do, DO IT.
Using a loop that is WHILE there's NOTHING to do, WAIT is wrong.

I try to limit how much a task does at a time to how long it takes to do an analog read and just a bit more. Analog read takes 1/9th of a millisecond, more than 1600 cycles which is quite long in Arduino time.

As long as I can do that, I can run a good task load and generally have response to events down to 1 millisecond or less.

As far as I'm concerned, state machines are the best way to break functions into small steps and reduce logic and loop indent levels as well as to modularize code.

crullier:
So when is it appropriate to use while, or Do...while?

When you want to SIMULATE multitasking / consecutive processing.
For example:

while( no incoming signal ) // check the condition
{
calculate lottery winning numbers // do something "useful" while waiting
}
got incoming signal ,now process it

Other nice feature is that do { process} while(condition) will guarantee to run the process once - will evaluate AFTER the process. But while( condition) { process } may skip over the process - the condition gets evaluated first.

I look at while / do as a "working" replacement of delay(x), where the simple delay can be replaced by combination of conditions, including time.