Delay, delay, delay

I noticed that the duration of the blink is always the same as the duration of the delay in the simple sketch below.

// Turn an LED on for one second, off for one second,
and repeat forever.
void setup()
{
pinMode(13, OUTPUT);
}
void loop()
{
digitalWrite(13, HIGH); // Turn on the LED
delay(1000); // Wait for one second
digitalWrite(13, LOW); // Turn off the LED
delay(1000); // Wait for one second
}

Can I assume any activity paused by delay must take place in the same interval? I understand delay causes all program activity to stop for the duration. This sketch seems to have more to do with delay than blinking a LED.

brianeo:
Can I assume any activity paused by delay must take place in the same interval?

you can be assured that the program will stop there and nothing** will happen for that many milliseconds.

So the interval between the completion of this:

digitalWrite(13, HIGH); // Turn on the LED

and the start of this:

digitalWrite(13, LOW); // Turn off the LED

will be the time spent here:

delay(1000); // Wait for one second

**interrupts will be managed/handled, of course

What I am learning from this is the sequence of events in a sketch. So, I modified the sketch to include another LED:

// Turn an LED on for one second, off for one second,
// and repeat forever.
void setup()
{
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
}
void loop()
{
digitalWrite(13, HIGH); // Turn on the LED
delay(1000); // Wait for one second
digitalWrite(13, LOW); // Turn off the LED
delay(1000); // Wait for one second
digitalWrite(12, HIGH); // Turn on the LED
delay(1000); // Wait for one second
digitalWrite(12, LOW); // Turn off the LED
delay(1000);
}

This works, but it looks to even a novice like a crude way to write functions. Anyway, but the sequence part of my question checks-out. Next step is to make the sequence of events more compact. How would you blink two LEDs?

brianeo:
What I am learning from this is the sequence of events in a sketch. So, I modified the sketch to include another LED:

// Turn an LED on for one second, off for one second,

// and repeat forever.
void setup()
{
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
}
void loop()
{
digitalWrite(13, HIGH); // Turn on the LED
delay(1000); // Wait for one second
digitalWrite(13, LOW); // Turn off the LED
delay(1000); // Wait for one second
digitalWrite(12, HIGH); // Turn on the LED
delay(1000); // Wait for one second
digitalWrite(12, LOW); // Turn off the LED
delay(1000);
}




This works, but it looks to even a novice like a crude way to write functions. Anyway, but the sequence part of my question checks-out. Next step is to make the sequence of events more compact. How would you blink two LEDs?

The code you have blinks two leds. What do you mean? Two LEDs at different rates at the same time? For that you'll have to abandon the use of delay. Go look in the example sketches that come with the IDE for the "Blink Without Delay" example or google that and find any of the many great tutorials on the subject.

Here's one to get you started: https://www.gammon.com.au/blink

How would you blink two LEDs?

Have a third one for free

const byte ledPins[] = {10, 11, 12};
const byte NUMBER_OF_LEDS = sizeof(ledPins) / sizeof(ledPins[0]);
unsigned long startTimes[3];
unsigned long periods[] = {300, 500, 700};

void setup()
{
  for (int led = 0; led < NUMBER_OF_LEDS; led++)
  {
    pinMode(ledPins[led], OUTPUT);
  }
}

void loop()
{
  unsigned long currentTime = millis();
  for (int led = 0; led < NUMBER_OF_LEDS; led++)
  {
    if (currentTime - startTimes[led] >= periods[led])
    {
      digitalWrite(ledPins[led], !digitalRead(ledPins[led]));
      startTimes[led] = currentTime;
    }
  }
}

The demo Several Things at a Time is an extended example of standard "Blink Without Delay" example and illustrates the use of millis() to manage timing. It may help with understanding the technique.

...R

brianeo:
This works, but it looks to even a novice like a crude way to write functions. Anyway, but the sequence part of my question checks-out. Next step is to make the sequence of events more compact. How would you blink two LEDs?

You are correct, this is purely a pedalogical exercise that is easy to understand for newbies. Congratulations Padawan, you are very strong with the force.

After you fully understand the links Delta_G and Robin2 offered, check the attached sketch.
Place a LED on D13 and D12.

//BWD example
unsigned long FlashTime;
unsigned long RelayTime;
unsigned long WaitTime;
unsigned long currentmillis; 
byte x;

void setup()
{
  pinMode(13, OUTPUT); //connect to LED
  pinMode(12, OUTPUT); //connect to relay driver

  FlashTime = millis();

} //  >>>>>>>>>>>>>> E N D   O F   s e t u p ( ) <<<<<<<<<<<<<<<<<


void loop()
{
  //leave this line of code at the top
  currentmillis  = millis();

  //***************************
  //just some code to see if the sketch is blocking
  if (CheckTime(FlashTime, 50UL))
  {
    digitalWrite(13,!digitalRead(13)); //toggle LED
  }
  //***************************
  if (CheckTime(RelayTime, WaitTime))
  {
    if(x < 20)
    {
      WaitTime = 400; //Fast
    }
    else
    {
      WaitTime = 800; //Slow
    }

    digitalWrite(12,!digitalRead(12)); //toggle relay
    x++;
    if(x > 39)
    {
      x = 0; 
    }
  }
  //***************************

  //Put your non-blocking regular stuff here



} //   >>>>>>>>>>>>>> E N D  O F  l o o p ( ) <<<<<<<<<<<<<<<<<


//======================================================================
//                       F U N C T I O N S
//======================================================================

//***************************
//Delay time expired function
boolean CheckTime(unsigned long &lastMillis, unsigned long wait) 
{
  //is the time up for this task?
  if (currentmillis - lastMillis >= wait) 
  {
    lastMillis += wait;  //get ready for the next iteration

    return true;
  }

  return false;
} //END of CheckTime()

//***************************

//======================================================================
//                       E N D   O F   C O D E
//======================================================================

Thanks for all replies. I see the terminology for it is "blocking." What I want is "non-blocking." That's a good start, for me. I will print the entire thread for study.
I have been aware of the Example/02.Digital/BlinkWithoutDelay since I found it on my own, plus the repeated discussion of it on the forum. It's still clear as mud to me. That's not because it's not a good tutorial. It's me. I don't get it until I get it.
It looks to me like the link offered by Delta_G is another way of explaining it. Sometimes when I look at a thing from a different point of view is makes better sense, and, afterwards, the first explanation sinks in also...

BWOD is fundamentally simple.

Save the time from millis() when the start action happens, such as turning on an LED, then each time through loop() check whether the current time minus the start time is equal to or greater than the required interval. If so, then act on it, such as turning the LED off, save the time from millis() and off you go again. If the period has not passed then keep going round loop() until it has. Now the important bit. Because loop() is running freely (not blocked) you can do other things until the interval passes.

The code in reply #4 uses this principle but holds the variables in arrays so that several different periods can be used on different LEDs without duplication of code.

UKHeliBob:
BWOD is fundamentally simple.

And you already do it every day, you just don’t realize it. If it is currently half past the hour and I tell you I’ve been here since 10 minutes past then how long have I been here? You subtract 10 from 30 and get 20 minutes. That’s all BWoD is. On each pass of the loop you look at millis and the difference between what it is now and what it was when you last did something to see how long it has been since you did it.

brianeo:
Can I assume any activity paused by delay must take place in the same interval? I understand delay causes all program activity to stop for the duration. This sketch seems to have more to do with delay than blinking a LED.

Delay does not pause any one specific activity, it pauses EVERYTHING*.

  • Except for interrupt driven activities, like the millis/micros timer and Serial TX/RX.

This works, but it looks to even a novice like a crude way to write functions. Anyway, but the sequence part of my question checks-out. Next step is to make the sequence of events more compact. How would you blink two LEDs?

It is very crude and ugly. The sooner you cultivate a healthy disgust for the delay function, the sooner you will be able to fully unleash the power of your microcontroller.

delay() is an evil function. delay() entices little children to the back of a windowless van with promises of candy. delay() sacrifices kittens, puppies, and baby seals in Satan's glory. delay() caused the 9/11 terrorist attacks. delay() hacked the 2016 US election. delay() steals your socks from the dryer and hides your keys in the morning when you're late for work.

delay() poisons everything.

To continue my analogy, it is the dark side of the force...

As much as delay is maligned here, I feel like the transition from delay to millis usage is a step that can be easily taken farther down the line in the learning process. Spend more time now or less time later, latter being more efficient.
In other words, use delay, learn to do many different things, one at a time. Then, when your toolbox actually has multiple things, and you want to run simultaneously and non-blockingly, then implementing millis for delay behavior will be a snap.

Although the advice of avoiding the use of delay means well, I think it gets mindlessly dispensed too eagerly too often.

Then, when your toolbox actually has multiple things, and you want to run simultaneously and non-blockingly, then implementing millis for delay behavior will be a snap.

delay() has its place, but it is easier to learn to use millis() in simple cases such as BWOD before you need to use it in a complicated one.

If it were just the code that someone needs to learn then I would agree with you. But the concept is a lot bigger than that. And there is more to learn from BWoD than just how to make lights blink at different speeds. I think it is a great first challenge.

If your looking for something that is simple and not very accurate take a look at this.

int led = 13;
int timer;

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

void loop() {

  timer++;

  if (timer < 500) {
    digitalWrite(led, HIGH);

  }
  if (timer > 500) {
    digitalWrite(led, LOW);

    if (timer > 1000) {
      timer = 0;
    }
  }
}

That's going to flash the light really fast running at 16MHz. Back in the day when we didn't have a way to get time, I remember writing stuff in basic that handled timing via long counting loops. And you'd have to calibrate it for each processor you ran it on. And when you cam back and tried the code years later on a faster processor it would run WAY too fast.

That is NOT a good way to handle timing. Nowadays we can actually time things in real milliseconds which makes a lot more sense.

yeah i know its not a good way to handle timing, but for blinking just an led without delay it works fine.

ryisnelly10:
yeah i know its not a good way to handle timing, but for blinking just an led without delay it works fine.

No, actually it doesn't. As soon as you add any more code the timing would change and you have to go calibrate the timing again.