Blink Without Delay Explanation

Hi. Below is the example sketch "BlinkWithoutDelay." If anyone could could they please explain HOW this works. Sometimes it confuses me a lot when it comes to the milli and interval. In general, I know what it is doing, but not how or what is making it do it. Also, overtime I upload a program to my Arduino Uno should the TX,RX, and LED do a little quick on and off thing. Every time they go on and off really quickly a lot. It takes about 2 seconds total.

// constants won't change. Used here to set a pin number :

const int ledPin = 13; // the number of the LED pin

// Variables will change :

int ledState = LOW; // ledState used to set the LED

// Generally, you should use "unsigned long" for variables that hold time

// The value will quickly become too large for an int to store

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

// constants won't change :

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

void setup() {

// set the digital pin as output:

pinMode(ledPin, OUTPUT);

}

void loop()

{

// here is where you'd put code that needs to be running all the time.

// 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.

unsigned long currentMillis = millis();

if(currentMillis - previousMillis >= interval) {

// save the last time you blinked the LED

previousMillis = currentMillis;

// if the LED is off turn it on and vice-versa:

if (ledState == LOW)

ledState = HIGH;

else

ledState = LOW;

// set the LED with the ledState of the variable:

digitalWrite(ledPin, ledState);

}

}

THANK YOU!

This is the third time you have been asked. You should have learned to follow the instructions by now. Please read the two posts at the top of this Forum by Nick Gammon on guidelines for posting here, especially the use of code tags which make the code looklike thiswhen posting source code files. Also, before posting the code, use Ctrl-T in the IDE to reformat the code in a standard format, which makes it easier for us to read.

If you have already posted without using code tags, open your message and select "modify" from the pull down menu labelled, "More", at the lower left corner of the message. Highlight your code by selecting it (it turns blue), and then click on the "</>" icon at the upper left hand corner. Click on the "Save" button.

Ok, sorry. I will read them now.

In general, I know what it is doing, but not how or what is making it do it.

Suppose I called you, and said meet me at the tavern in one hour, and I'll let you buy me a beer.

What would you have to do in order to be on time?

You'd need to know what time some event occurred. Which event? Why, the phone call, of course.

In that code, the event is the LED changing state, and when is recorded in previosMillis (which is, of course, a stupid name for the variable to hold an event time).

You'd need to check your watch, periodically, to see what time it is now.

In that code, unsigned long currentMillis = millis(); is how the Arduino checks its watch, recording now in the variable called currentMillis (another stupid name).

You'd need to determine how long it has been since I called.

currentMillis - previousMillis is how the Arduino does that.

Finally, you'd need to know if that amount of time equaled or exceeded the required amount of time.

The comparison to interval is how the Arduino does that.

And, last, but not least, if enough time has passed, you'd enter the tavern and buy me a beer.

Well, the Arduino doesn't particularly care for beer, but it does have a fondness for diddling LEDs. When it does that, it needs to record when, so it can do it again later.

the Arduino doesn't particularly care for beer,

Sometimes, mine acts like it does

Thank you @PaulS ! The scenario helps with the different terms that,like you said, have stupid names.

Groove:
Sometimes, mine acts like it does

Mine prefers Rum and Pepsi. Go figure.

Also, overtime I upload a program to my Arduino Uno should the TX,RX, and LED do a little quick on and off thing. Every time they go on and off really quickly a lot. It takes about 2 seconds total.

I hope you really met to say:

Also, every time overtime I upload a program to my Arduino Uno should the TX,RX, and LED do a little quick on and off thing ?

Good catch. Yes, those LED's monitor / display the actual data being processed during program download.
Download is not very fast - 1200 bauds - so it is a good indicator that download is working.

If you set "show verbose output during " options in "preferences" (file) you can also monitor the download process that way.

You have been told to "post your code properly". It is for benefit of some folks who just cannot read code unless it is posted THEIR way, but if you use Tools -> AutoFormat BEFORE you post, properly posted or not, it WILL be to your benefit first.
Makes it easier on your eyes and as a benefit it SOMETIME indicates errors too - likes missing closing brackets and others.
Good luck

Thank you Vaclav! I appreciate everything. I looked at the auto format and that is very cool. Thx! Yes, I did mean every time and I will auto format and look it over from now on. Finally, thx for letting me know about the lights going off quickly being the sketch uploading! :slight_smile:

EQOxx123:
Thank you Vaclav! I appreciate everything. I looked at the auto format and that is very cool. Thx! Yes, I did mean every time and I will auto format and look it over from now on. Finally, thx for letting me know about the lights going off quickly being the sketch uploading! :slight_smile:

you are welcome.

Small suggestion - since you check the state of the LED and change it only if the state changed you could
just complement the output value ( HIGH /LOW) without checking it.
It is binary and only 0 or 1.

In pseudo code:
if( state changed)
ledState = ~ ledState; // change (complement) output value / LED state value
digitalWrite(ledPin, ledState);

But it makes code more readable if you do it the way you did, it is perfectly OK.

I would use !ledState instead of ~ledState.

If ledState is 1, so we're writing HIGH, then ~ledState would be 254, which would still set the pin HIGH.

PaulS:
Suppose I called you, and said meet me at the tavern in one hour, ... t it does have a fondness for diddling LEDs. When it does that, it needs to record when, so it can do it again later.

PaulS nice job at making something plain English.

One thing that could use a little extra explaining for the Blink without Delay (code sample shown and taken right from the built-in code examples menu in Arduino IDE) is something that is a bit of a head scratcher:

As millis() advances ever higher and higher... it eventually wraps back to 0.

How does the sample program continue to give a consistent interval (of does it!?) when the previous and current millis are straddling the high end of the variable and need to be wrapping around to zero again?

Supppose the length of an unsigned long is only 4 digits, just to make this illustration a little easier:

In some iteration previousMillis is assigned 9050
and millis is counting up.. and it's going to hit 9999 and then wrap
so currentMillis is climbing getting assigned values up to 9999
the test ( current - previous >= 1000 ) is not quite achieved yet... because (9999 - 9050 < 1000)
so millis wraps and is now zero
currentMillis is therefore 0
around comes the test again ( current - previous >= 1000 ) so (0 - 9050 ) is -9050 which is way < 1000
and millis starts to climb from zero and so does currentMillis..
and the test fails and fails and fails for a long time ... because no value in range of millis (0..9999) will ever make the test true again.. it's only until millis gets to 9050 again that the test becomes non-negative ...

So does the example all fall apart in 49 days when millis hits the ceiling?

Tell me it's not so! Tell me why in plain English what prevents this sad fate.

Does it have to do with the fact these are unsigned longs and a test like this ( 0 - 9050) cannot yield a negative number? What does it yield?

I think I'll write a little program to find out.

around comes the test again ( current - previous >= 1000 )  so (0 - 9050 ) is -9050 which is way < 1000
and millis starts to climb from zero and so does currentMillis..

Notice how that sketch uses unsigned variables. Can an unsigned variable be negative?

To make things simple, let's think of an unsigned char instead of unsigned long since the numbers will be smaller but the effect the same.

If I have unsigned 8 bit unsigned variables and I say what is 5 - 250, what do you get? I get 11. Remember, we're doing computer math, not people math.

I think the answer lies in here:

void setup() {
  // put your setup code here, to run once:

  unsigned long j = 9000 ;
  unsigned long k = 0 ;

  Serial.begin(57600);

  Serial.print("subtract two unsigned longs k - j (0 - 9000) gives: ");
  Serial.println ( k - j ) ;

  k = -1;
  Serial.print("unsigned long being assigned -1 gives: ");
  Serial.println ( k ) ;

  k = -2;
  Serial.print("unsigned long being assigned -2  gives: ");
  Serial.println ( k ) ;

  k = 4294967295 ;
  Serial.print("unsigned long being assigned 4294967295  gives: ");
  Serial.println ( k ) ;

  k += 1  ;
  Serial.print("unsigned long adding 1  gives: ");
  Serial.println ( k ) ;

  k += 1 ;
  Serial.print("unsigned long adding 1 more gives: ");
  Serial.println ( k ) ;

}

void loop() {
  // put your main code here, to run repeatedly:

}

output:

subtract two unsigned longs k - j (0 - 9000) gives: 4294958296
unsigned long being assigned -1 gives: 4294967295
unsigned long being assigned -2  gives: 4294967294
unsigned long being assigned 4294967295  gives: 4294967295
unsigned long adding 1  gives: 0
unsigned long adding 1 more gives: 1

Negative 1 in an unsigned variable is the same as maximum value it can hold.
Negative 2 starts coming down from the max.

Delta_G:

around comes the test again ( current - previous >= 1000 )  so (0 - 9050 ) is -9050 which is way < 1000

and millis starts to climb from zero and so does currentMillis..




Notice how that sketch uses unsigned variables. Can an unsigned variable be negative? 

To make things simple, let's think of an unsigned char instead of unsigned long since the numbers will be smaller but the effect the same. 

If I have unsigned 8 bit unsigned variables and I say what is 5 - 250, what do you get? I get 11. Remember, we're doing computer math, not people math.

..yep..

so this code should handle wrapping millis just fine too, right?

    unsigned long tstart = millis();
    unsigned long tstop = tstart + 10000;  // allow 10 seconds to get going

    while ( millis() < tstop ) {
      // do stuff
    }

    // this code block begins executing 10 seconds after tstart point in time

No, that code will fail.

When that one rolls over you end up with tstop being some small number while millis is still big, so millis starts out not being less than tstop. To make it work you always have to work with subtraction to find an interval, you can't predict points in the future with addition.

So does the example all fall apart in 49 days when millis hits the ceiling?

DeltaG is correct in that rollover is not an issue by virtue of unsigned math.

However, "Blink Without Delay" as written in the ide example is not rollover proof.

To make sure that unsigned math is being used, you must explicitly cast the subtraction.

if(unsigned long(current - previous) >= 1000)

See this example code using byte --an unsigned variable which rolls over at 255. Without the explict cast of the subtraction, the sketch fails at rollover.

byte tick;//will roll at 255 to 0
byte lasttick;
byte previousTime;
byte elapsedInterval;

void setup() {

  Serial.begin(115200);
  Serial.println("rollover test");
}

void loop() {
  tick = millis() / 100;//"tick" = 100ms 
  if (tick != lasttick)
  {
    lasttick += 1;
    Serial.print(tick);
    Serial.print('\t');
    elapsedInterval = (tick - previousTime);
    Serial.println(elapsedInterval);
  }
  //if (tick - previousTime >= 5)
  if (byte(tick - previousTime) >= 5)//byte caste is needed here
  {
    Serial.print("scheduled event at ");
    Serial.print(tick);
    Serial.print(" elapsed interval = ");
    Serial.println(elapsedInterval);
    previousTime += 5;
    Serial.print("updated previousTime = ");
    Serial.println(previousTime);
    Serial.print("next scheduled event at ticks =  ");
    //add 5 for calculation and display, then correct back
    Serial.println(previousTime += 5);
    previousTime -= 5;
  }
}

cattledog:
To make sure that unsigned math is being used, you must explicitly cast the subtraction.

Not if the operands are both unsigned. I think yours is required because the expression has an int result (more precision than a byte).

Not if the operands are both unsigned.

In the test sketch, both operands are globally declared as byte which is unsigned.

byte tick;//will roll at 255 to 0
byte previousTime;

EDIT:

I think yours is required because the expression has an int result (more precision than a byte).

I think you are correct that the unsigned int and unsigned long types will not undergo any kind of promotion in arithmetic operations, and BWOD will handle roll over without the explicit cast of the subtraction.

OK, gotcha need the difference computed in the comparison

so this code should do it:

    unsigned long tstart = millis();
    unsigned long tstop = 10000;  // allow 10 seconds 

    while (  (millis() - tstart ) < tstop ) {
      // do stuff for 10 seconds
    }

    // this code block begins executing 10 seconds after tstart point in time

I tried type casting that subtraction as 'unsigned long' inside the while condition but compiler no likey. I don't think it's needed. millis() and tstart are both unsigned long so that expression should result in same.