Help with millis

Hi everyone, I am trying to use a blink without delay timer to turn on an output for 8 seconds, then turn it off. I can't get it to work. Am I even close. Thanks adown

unsigned long interval = 8000; // Time we need to wait
unsigned long previousMillis = 0; //millis() returns an unsigned long

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin 13 as an output.
  pinMode(13, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {

  if ((unsigned long)(millis() - previousMillis) <= interval) {

    digitalWrite(13, HIGH);
  }

  else {
    digitalWrite(13, LOW);
    previousMillis = millis();
  }
}

Nope.

SO let's look at your logic here. If it hasn't bee more than 8 seconds you write the pin low and then set previousMillis to the current time. Then on the next check, a few ms later, it still hasn't been 8 seconds and you update previousMillis again. Since previousMillis keeps getting updated to the current time on every pass, you'll never test 8 seconds having passed.

You should only update previousMillis when you take an action and are ready to reset your timer. That line should probably be right behind the digitalWrite(13, HIGH) line.

I don't think you need (unsigned long) here.

if ((unsigned long)(millis()

I would add a flag also, set it once the turn on time is met so you're not wasting time writing it low every pass thru loop after it turns off.

Have a look at the code in Several Things at a Time. It blinks LEDs and it would be simple to adapt that for longer intervals.

...R

adown:
Hi everyone, I am trying to use a blink without delay timer to turn on an output for 8 seconds, then turn it off. I can't get it to work. Am I even close.

I think you are ready and the code works perfectly like you described as you want it:

  • 8 seconds ON
  • then set OFF
  • then restart the cycle

That's what you described and that's what the code does.

Unfortunately the OFF time is zero milliseconds, so it is invisible and it will look as if the LED is always ON. But for 4 microseconds it will be OFF every 8 seconds. You'll need an oscilloscope to find out.

So if this (8.000000 seconds ON and 0.000004 seconds OFF) is not what you want, please describe what you want!

adown:
Hi everyone, I am trying to use a blink without delay timer to turn on an output for 8 seconds, then turn it off. I can't get it to work. Am I even close. Thanks adown

unsigned long interval = 8000; // Time we need to wait

unsigned long previousMillis = 0; //millis() returns an unsigned long

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin 13 as an output.
  pinMode(13, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {

if ((unsigned long)(millis() - previousMillis) <= interval) {

digitalWrite(13, HIGH);
  }

else {
    digitalWrite(13, LOW);
    previousMillis = millis();
  }
}

It's really not so bad. But switching HIGH and LOW both belong inside of the if millis-etc time check.

Make it easy to know if the led should be HIGH or LOW with a variable.

One way to do it:

byte ledState; // if the led pin is HIGH or LOW, this is the same

// then when the code switches the led HIGH or LOW, the next step is to change ledState.
// whenever the interval is up,

if ( ledState == LOW )
{
// set ledState HIGH
}
else
{
// set ledState LOW
}
// set the led pin to whatever is in ledState

// tip about the above:
// I keep my braces all on the same level, it makes them easier to find and to line up the indent levels
// when my eyes don't have to look all over the place for lines ending in { to line up the matching }.
// When you code 8+ hours a day for a while, it does add up even when you're still young.

Do you have the missing puzzle pieces now?

It will work either way but I always like to test whether the period has elapsed and take action rather than testing whether the period has not elapsed. This will often remove the need for an else clause because nothing has changed.

The code can also be shortened by reading the current state of the LED pin and inverting it.

unsigned long interval = 8000; // Time we need to wait
unsigned long previousMillis = 0; //millis() returns an unsigned long
const byte ledPin = 13;

void setup() 
{
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  if ( (millis() - previousMillis) >= interval)
  {
    digitalWrite(ledPin, !digitalRead(ledPin));
    previousMillis = millis();
  }
}

a lot of people struggle with millis timers as theres no instruction to start the timer.

previousMillis = millis(); this line really says reset the timer

if you keep reseting the timer then you are really saying stop the timer

So to have any control over a millis timer you have to think about how to time using basically

1/ when to run the timer
2/ when to reset the timer
3/ how to keep the timer reset so it seems to be stopped

how a if works:

if (question){

question is true

}else{

question is false

}

so your original code says:

if (has the timer run for 8 seconds){

timer has run for 8 seconds

}else{

timer has not run for 8 seconds
reset the timer which is the same as start the timer with 8 seconds to go

}

so the big question is what to do after the timer has run 8 seconds. That requires a plan.

if you plan is to wait 8 seconds then never reset the timer to run again you can turn the led on in setup then use if ( (millis() - previousMillis) >= interval) to turn the led off

if you want the led to cycle every 8 seconds then post#6 is the way to go as the timer is reset every 8 seconds thus it will repeat every 8 seconds

using basic "if" and flags you can code

1/ timer is timing
2/ timer is done
3/ repeating timer (both times are the same)

from a single timer.

if you change previousMillis to previousMillis1 you create another timer so you have no limit on the amount of timer available.

@gpop1, I think your terminology is confusing. What you call a timer is really a time stamp. Most people think of a changing value when they think of a timer. Which millis() actually is (at least virtually...).

millis() is the function that we use to fetch the value that a timer and IRQ generate.

aarg:
@gpop1, I think your terminology is confusing. What you call a timer is really a time stamp. Most people think of a changing value when they think of a timer. Which millis() actually is (at least virtually...).

I hope I haven't confused the situation. I only deal with people who are new to programming which generally means they are moving from delay to millis for the first time. I figured a little white lie to help them understand the concept is easier than using all the right words. I wish there was a better example than blink with out delay as that's a looping program that doesn't really explain the concept of millis.

To the Op if you find my post confusing just ignore it.

Thanks for all the replies. What I am trying to do is, light the led for 8 seconds, turn it off and end. This is actually part of a bigger sketch that will be called under one condition. I am just trying to get it to work alone before I add it to the sketch. I do have a flag that will keep it from running again, but I can't figure out how to turn the LED on for 8 seconds then off and end. I will read through all the replies and see if I can figure it out. If my clarification on what I want helps, please reply. Thanks, adown

adown:
Thanks for all the replies. What I am trying to do is, light the led for 8 seconds, turn it off and end. This is actually part of a bigger sketch that will be called under one condition. I am just trying to get it to work alone before I add it to the sketch. I do have a flag that will keep it from running again, but I can't figure out how to turn the LED on for 8 seconds then off and end. I will read through all the replies and see if I can figure it out. If my clarification on what I want helps, please reply. Thanks, adown

You can do just that part very easily but do it that way and it won't work along with other actions.

But, if you learn what people are trying to show you then not only will that work with other actions but you will have a really good start on how to implement those.

The Arduino Classic Sketch for this is called BlinkWithoutDelay.

I did a little cleaning up of the original and added comments.
Take out the comments and there are only 12 lines of code, not counting braces {}.

/* Blink without Delay -- with minor fixes by GFS

  Turns on and off a light emitting diode(LED) connected to a digital  
 pin, without using the delay() function.  This means that other code
 can run at the same time without being interrupted by the LED code.
 
 The circuit:
 * LED attached from pin 13 to ground.
 * Note: on most Arduinos, there is already an LED on the board
 that's attached to pin 13, so no hardware is needed for this example.
 
 
 created 2005
 by David A. Mellis
 modified 8 Feb 2010
 by Paul Stoffregen
 
 This example code is in the public domain.
 
 http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
 
 GFS fixes and modifications -- May 5 2013:
 . changed time variables to be ALL unsigned longs, as they should be.
  . changed the variable name 'interval' to 'blinkTime' as interval is now a
 word used by the IDE, it shows up red (like the word 'if') instead of black.
 . changed the if-else logic to change the ledState variable to 1 line XOR logic.
 . added comments about adding more tasks to the sketch.
 
 */

// constants won't change. Used here to 
// set pin numbers:
const byte ledPin =  13;      // the number of the LED pin

// Variables will change:
byte ledState = LOW;             // ledState used to set the LED

unsigned long previousMillis = 0;  // will store last time LED was updated

unsigned long blinkTime = 1000;  // interval at which to blink (milliseconds)

void setup() 
{
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);      
}

void loop()
{
  unsigned long currentMillis = millis();
 
  // here is where you'd put code that needs to be running all the time.
  
  // GFS adds -- you see the if() { } block below? You can add more blocks
  // whether if() or switch-case or whatever to do other tasks and as long
  // as they run quick without delays or prolonged loops, your sketch will
  // be responsive as if everything runs at the same time.
  // just as the blink runs on time, another task can run when a button or 
  // sensor or serial data comes in or changes. 
  // simple commands run in less than a millionth of a second so you can pack
  // a good bit of process into a block and still run quick. analog read takes
  // longer, about 9 per millisecond so it's best not to do a bunch of those 
  // in a row but instead 1 analog read per time through loop() so other tasks
  // can get a chance in between analog reads. 
  // it's also good to avoid using floating-point as that is slooowww and avoid
  // using C++ Strings as they mess with your RAM and suck up CPU cycles doing it.

  // Back to the original program:
  // check to see if it's time to blink the LED; that is, if the 
  // difference between the current time and last time you blinked 
  // the LED is bigger than the interval at which you want to 
  // blink the LED.
  if(currentMillis - previousMillis >= blinkTime) // is it time to change the led? 
  {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    ledState = ledState ^ 1; // ^ is logical XOR, true if the values are different
    // using logic operations can save a lot of tedious, pain to debug if's

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

gpop1:
I wish there was a better example than blink with out delay as that's a looping program that doesn't really explain the concept of millis.

I totally agree. It only shows how you can use millis() to perform one task. Many new programmers would need some help making the leap to using it to simultaneously perform more than one task. Which is the main purpose of using it in the first place. Problem is, the bare board doesn't have more than one device that everybody would have in common, the built in LED. So it's hard to think of a demo that people could quickly test and play around with.

@aarg,

Most can use the serial monitor, so they can see the led blink, and the serial monitor run at the same time. That would show two processes.

Great idea. I'll give it a shot tomorrow, and try to style it as a really good introduction for newbs. Unless it's been done very well already somewhere.

Great, I look forward to seeing your results..

blink led, on 100ms, off for 3 seconds.
display milli on the serial monitor ever 2 seconds.

That should be a good mix.

just some random code for the op that shows a few examples

this will turn on the led for 8 seconds then turn it off (notes on how to make it repeat added)

also added some other play code as a example. (hope you know how to use serial monitor?)

unsigned long previousMillis = 0;
unsigned long interval = 8000;
unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
byte flag = 0;
byte flag2 = 0;
byte counter = 0;
void setup() {
  Serial.begin(9600);
  pinMode(13, OUTPUT);

}

void loop()
{
  //on reboot millis starts at zero so will currentMillis
  unsigned long currentMillis = millis();

  if (flag == 0) {//true on start up
    digitalWrite(13, HIGH);
  }
  if (currentMillis - previousMillis >= interval) {
    digitalWrite(13, LOW);//true after 8 seconds
    flag = 1;//this will block the  digitalWrite(13, HIGH);
  }


  //make a one second counter so it looks like seconds counting up
  if (currentMillis - previousMillis1 >= 1000) {
    counter++;//bad example as i dont stop the overflow but this is just for fun
    previousMillis1 = currentMillis;
  }

  //slow down the serial print as its annoying
  if ((currentMillis - previousMillis2 >= 250) && (flag == 0)) {
    Serial.print ("seconds:");
    Serial.println (counter);
    previousMillis2 = currentMillis;
  }

  if (counter == 8 && flag2 == 0) {
    Serial.println ("turn led off");
    flag2 = 1;
  }
  //if i do something like push a button to turn the led back on
  // then i would add something like

  //if (buttonPush==HIGH){
  //  previousMillis = currentMillis;
  //flag=0;}
}

gpop1:
I wish there was a better example than blink with out delay as that's a looping program that doesn't really explain the concept of millis.

I don't know how it does not. The sketch cycles around checking time as it goes by and changes the led state on time. It teaches one thing without extra confusion, and then the student moves on to the next step.

But if you want, I can post button and led sketches where the button is a jumper that you ground to 'press' and the serial output just about traces program execution. That's a big step for a beginner though.

GoForSmoke:
I don't know how it does not. The sketch cycles around checking time as it goes by and changes the led state on time. It teaches one thing without extra confusion, and then the student moves on to the next step.

But if you want, I can post button and led sketches where the button is a jumper that you ground to 'press' and the serial output just about traces program execution. That's a big step for a beginner though.

I personally found it hard to understand how to start and stop things using millis as the example had the time stamp (reset) in the same "if". To understand how to make things start and stop also required knowing how to block code which the bwod does not cover.

There was also a learning curve on changing the interval in the code so one timer can be used multiply times.

many times I reverted back to making a counter using millis as it was easier to understand and it only added a byte instead of multiple unsigned long. bwod teaches how to toggle a led it doesn't teach millis very well for a new person.