Program Blink Without Delay

I am trying to understand LED blinking without delay Example code.

The program :

unsigned long startMillis;  
unsigned long currentMillis;
const unsigned long period = 1000;  //the value is a number of milliseconds
const byte ledPin = 13;    //using the built in LED

void setup()
{
  Serial.begin(115200);  //start Serial in case we need to print debugging info
  pinMode(ledPin, OUTPUT);
  startMillis = millis();  //initial start time
}

void loop()
{
  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  {
    digitalWrite(ledPin, !digitalRead(ledPin));  //if so, change the state of the LED.  Uses a neat trick to change the state
    startMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.
  }
}

I could not understand the following line, what is happening in it?

if (currentMillis - startMillis >= period)

Why is the start time being subtracted from the current time?

What is stored in variable currentMillis and when does its value change?

What is stored in variable startMillis and when does its value change

Yes, they could have explained that better.

Rather than just giving answers, here's a tool to use.
take a pen and envelope. walk through the code line by line, and write down what happens in English. I think it will become evident by your second or third time around the loop().

2 Likes

At this level of code, the only thing that changes the value of a variable is an assignment statement.

So in this case,

  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)

every time loop() gets control, right away the current time in milliseconds since reset or power up is placed in currentMillis.

a7

The code is trying to measure the passage of time (in milliseconds) from a starting time (i.e startMillis) and the current time (i.e. currentMillis).

currentMillis stores the value of the milliseconds counter (from the function call millis() ) and it updates every time round the loop() function. Remeber, loop() gets called continuously once setup() completes.

startMillis holds the milliseconds counter and in firstly setup at the end of the setup() function. It will be assigned a new value once the time period has expired (inside the if statement).

The "blink without delay" example from my IDE (v1.8.19) is slightly different. The code is:

// constants won't change. Used here to set a pin number:
const int ledPin =  LED_BUILTIN;// 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);
  }
}

I think this version explains better what the code is doing for a beginner, especially the way the LED is turned on or off.

When I get up in the morning after eating breakfast I load into my memory that I will eat again in 4 hours, its currently 7:00.

At 8AM I can say 1 hour has passed and 3 hours till eat again. During the rest of the time waiting I do other things.

At 9AM I can say 2 hours have passed and 2 hours till eat again. During the rest of the time waiting I do other things.

At 10AM I can say 3 hours have passed and 1 hour till eat again. During the rest of the time waiting I do other things.

At 11AM I can say 4 hours have passed, time to eat. Eat. Reset hours passed to 0, load into memory the next eat time, and begin the count down again.

4 Likes

But what is of utmost importance is will there be bacon consumed in this meal :thinking: :smiling_face_with_three_hearts:

3 Likes

1. Let us define 1-blink of L (built-in LED) of UNO.
Turn ON L.
Wait for a while (say: 1000 ms).
Turn OFF L.
Wait for a while (say: 1000 ms)

2. We understand from Section-1 that there are four events (ON-wait-OFF-wait) in 1-blink. The L remains ON for 1-sec and then remains OFF for 1-sec. The L blinks at 2-sec interval.

3. We can implement 1-sec "waiting time" by calling delay(1000) function. But the problem is that the MCU remains blocked for this 1-sec time and can't do any other task until the waiting time is expired.

4. This is no good to keep the MCU blocked; so, our aim is to turn ON L and let it be at this state for 1-sec while the MCU is free (not blocked for this 1-sec) to do any other task assigned by the user. This means that the MCU will be simultaneously doing two tasks:

(1) Change state of L (from ON to OFF and vice versa) at the elapse of every 1-sec time.
(2) While L remains ON (or OFF) for 1-sec, check if a smoke detector sensor is active (for example).

5. The objectives of Section-4 can only be achieved if there happens to be running a "clock/timer" in the background from which the MCU can exactly determine if 1-sec (1000 ms) time has elapsed or not.

6. In Arduino UNO, at the end of uploading a sketch, a time counter (called millisCounter) is automatically started with initial value of 0, and then it counts every elapsed millisecond. The user can call this function: millis() to know how many milliseconds the millisCounter has accumulated up to now. The code is:

unsigned long presentMillis = millis(); //presentMillis holds the return value

7. If we have understood the millisCounter and millis() function, then we can execute the following sketch to blink L without using delay(1000) function.

byte ledState = HIGH;   //L is ON initially
unsigned long presentMillis = millis();  //record the present time ~=0
#define  L   13     //L is connected with DPin-13

void setup()
{
     pinMode(L, OUTPUT);
     digitalWrite(L, ledState);   //L is ON
}

void loop()
{
     if(millis() - presentMillis >= 1000) //1000 ms has elapsed
     {
          ledState = !ledState;  //change ledState from HIGH to LOW
          digitalWrite(L, ledState); //L is OFF ; after 1-sec, L will be ON again
          presetMillis = millis();   //load presentMillis with current time
      } 
      else
      {
           //insert codes to check smoke detector sensor's output
      }
}

Blink without delay() explained line-by-line

1 Like

Example program is written to blink LED every 1 second.

I want to make look up table just for understanding

currentMillis - previousMillis >= 1000

Let's say 100 milliseconds have passed then what will be the value of these variables

Let's say 200 milliseconds have passed then what will be the value of these variables

Let's say 500 milliseconds have passed then what will be the value of these variables

why not have them print out so you can see?

unsigned long startMillis;  
unsigned long currentMillis;
const unsigned long period = 1000;  //the value is a number of milliseconds
const byte ledPin = 13;    //using the built in LED

void setup()
{
  Serial.begin(115200);  //start Serial in case we need to print debugging info
  pinMode(ledPin, OUTPUT);
  startMillis = millis();  //initial start time
}
unsigned long printInterval = 100;
unsigned long printMillis = millis();

bool Tick = true;
////
void loop()
{
  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
if( millis()-printMillis >= printInterval )
{
Serial.print( currentMillis );
Serial.print( " " );
Serial.print( startMillis );
Serial.print( " millis() - startMillis= "  );
Serial.print( currentMillis - startMillis );
Serial.println();
printMillis=millis();
 }
if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  {
if(Tick){
digitalWrite(ledPin, LOW);
Tick=!Tick;
    ////!digitalRead(ledPin));  //if so, change the state of the LED.  Uses a neat trick to change the state
}else {
digitalWrite(ledPin, HIGH);
Tick=!Tick;
}
    startMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.
  }
}
1 Like

Passed since when?

That's where you and I are different.

a7

Sleeping is a other thing.

2 Likes

People, in code just as in real life, inactivity is itself an activity.

i still can't imagine. Can you assume anything for example?

it would be easier to understand if i have some samples

Go back, read post 3, and try to execute the advice. If you can't figure out what millis() returns, read the Reference material on the website for hints.

The problem is, we can't guess what parts of it you don't understand. You can analyze a line like the one you cited, in many different ways, for example C syntax, the operation of the functions that it calls, the semantics ( what it means ) ... etc etc.

When a student looks at many examples and can't figure it out, it often just means that they are not ready, the preceding prerequisite lessons and projects were missed.

The use of millis() requires learning a programming paradigm, often called a "design pattern". This has little to do with the language or system in use but is instead a general method. Design patterns are sometimes implicit, you don't see them directly, it looks just like some code that does something. Thus, recognizing them and using them, is a separate skill next to coding, which itself has a learning curve and requires practice.

We've seen on this forum, someone completely baffled by millis(), suddenly just "get it", as if a light bulb just came on by magic. What that is, they are staring at the code, trying to see it there. It isn't. Then they begin to see the pattern, and "aha".

1 Like

assuming that currentMillis() is the current timestamp captured using millis() and previousMillus is an earlier timestamp, the condition is true when the difference between timestamps is >= 1000 (1 sec)

the condition repeats when current is set to previous

I tinker, eat & tinker, tinker, eat & tinker, and so on.
I never stop tinkering.