Bliniking a led with Millis()

const int led = 13;
unsigned long oldTime;
unsigned long newTime;
unsigned long timeDelay;
boolean ledOn;

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

void loop() {
  newTime = millis();
  timeDelay = (newTime - oldTime);

  if (timeDelay > 1000 && ledOn == 0) {
    digitalWrite(led, HIGH);
    ledOn = 1;
    oldTime = newTime;
    timeDelay = 0;
  }

  if (timeDelay > 1000 && ledOn == 1) {
    digitalWrite(led, LOW);
    ledOn = 0;
    oldTime = newTime;
    timeDelay;
  }
}

the code is correct and the led is blinking . the problem is I don't understand why .according to my logic in the beginning , it have to wait 1 second to go high in the first time and then it have to wait an other 1 second to go low as old time become 1000 and new time become 2000 and etc if executed manually so there is a dead time in the blinking process but in reality the arduino execute it normally without any dead time and can't understand why it keep 1 second high and 1 second high despite the IF is red one time ( I mean not like while). thanks

Hi @meriam_12 ,

it's not so hard once you start to "think like a computer" :wink:

Let's look at the loop() only and remove the second "if" to make it easier ...

void loop() {
  // This is line #1. It stores the actual time in milliseconds
  newTime = millis();

 // Now we calculate the interval between "newTime" and "oldTime"
// This is the time in milliseconds expired since the last time we have stored oldTime
  timeDelay = (newTime - oldTime);
 
 // As long as this difference is  less than or equal to 1000 msecs 
 // everything inside the if-clause is skipped!
  if (timeDelay > 1000 && ledOn == 0) {
    digitalWrite(led, HIGH);
    ledOn = 1;
    oldTime = newTime;
    timeDelay = 0;
  }
// This is the line after this if-clause
// and the end of loop() 
// so the controller will proceed with line #1 again
}

You can see that everything inside the if-clause is skipped until the interval has expired.

When the time has expired the if-clause will be entered and ledOn is set to 1 and oldTime to the recent time inside it.

From now on the controller will never again enter the if-clause as long as ledOn stays 1 ...

Now the second if-clause has a chance to be entered:

  if (timeDelay > 1000 && ledOn == 1) {
    digitalWrite(led, LOW);
    ledOn = 0;
    oldTime = newTime;
    timeDelay = 0;  // This is a corrected line, however  
                    // not necessary here as timeDelay is calculated 
                    // in loop() before it is evaluated by the first if-clause
  }

It has to wait again until timeDelay has expired and then the content will be performed:
(Actually it does not "wait" ... The content of the if-clause is just skipped until the conditions of the "if" are met).

Inside the second if clause ledOn is set to 0 again and oldTime to the recent time.

Now verything starts from the beginning...

You can change the loop() as follows:

const int led = 13;
unsigned long oldTime;
unsigned long newTime;
unsigned long timeDelay;
boolean ledOn;

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

void loop() {
  newTime = millis();
  timeDelay = (newTime - oldTime);

  if (timeDelay > 1000 ) {
    if (ledOn == 0) {
      digitalWrite(led, HIGH);
      ledOn = 1;
    } else {
      digitalWrite(led, LOW);
      ledOn = 0;
    }
    oldTime = newTime;
  }
}

or even shorter

const int led = 13;
unsigned long oldTime;
unsigned long newTime;
unsigned long timeDelay;
boolean ledOn;

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

void loop() {
  newTime = millis();
  timeDelay = (newTime - oldTime);
  if (timeDelay > 1000 ) {
    ledOn = 1 - ledOn;    // if ledOn is 0 the result is 1, if ledOn is 1 the result is 0
    digitalWrite(led, ledOn);
    oldTime = newTime;
  }
}

digitalWrite will write LOW if the value is zero and HIGH if the value is 1.

Don't hesitate if you have still questions.
Have fun!
ec2021

(Just to complete the explanation: In your sketch from post #1 timeDelay has to be set to zero in the first if-clause to avoid that the sketch runs immediately into the second if-clause.)

1 Like

If you like flowcharts this is roughly what your sketch from post #1 does

Most of the time it follows the green lines.

The red and the yellow line will be performed alternating every second (due to the value of ledOn).

2 Likes

It doesn't wait.

It is coded like a checklist with an item that says "If it has it been 1000 milliseconds since I switched the switch, switch it again." It quickly skips to the next checklist item and when it gets to the bottom of the list (loop()) it immediately goes back to the top, checking its list thousands of times per second.

a lot of extraneous code make the code more difficult to follow

const int PinLed = 13;       // Capitalize Constants

const unsigned long MsecPeriod = 1000;

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

void loop() {
    usigned long msec = millis();

    if (msec - msec0 >= MsecPeriod)  {
        msec0 += MsecPeriod;
        digitalWrite (PinLed, ! digitalRead (PinLed));
    }
}

How about code that actually compiles?

const unsigned long MsecPeriod = 1000;  // Capitalize Constants

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

void loop() {
    unsigned long msec = millis();
    static unsigned long msec0;

    if (msec - msec0 >= MsecPeriod)  {
        msec0 += MsecPeriod;
        digitalWrite (LED_BUILTIN, ! digitalRead (LED_BUILTIN));
    }
}
1 Like

Good Flow Chart (post #3) except the introduction of the small circle. There is no processing inside the small circle, then why is it here? I know that the following sysmbols are used for Flow Chart Programming where there is no circle.

I used LibreOffice Draw. The circle is just a place where arrows can be hooked to.

As this is not directly related to the TO's topic:

Off topic explanation

Some flowchart software uses this option called "reference point" or "connector node" or "connector point" or (with a rotated cross inside) "summoning junction symbol"

Source: https://www.breezetree.com/flowchart-software/help/work-with-flow-lines

or here
https://www.zenflowchart.com/blog/flowchart-connector-explanation-guide

Here a diagram

Source: https://www.edrawmax.com/flowchart/flowchart-connector.html

Named connector points are often used to show connections across a flowchart where drawing a direct line would be difficult.

Please don't blame me for the terms used or differences to existing standards ... :wink:

1 Like

Another new user that like - almost every week - has difficulties to understand because the BWD-example does NOT emphasize the fundamental difference between delay() and nonblocking timing BASED on millis()

Leaving out this explanation leads to the totally wrong assumption that non-blocking timing would wait similar to delay()

Non-blocking timing checks 10000 of times each second:
"has enough time passed by"?
and only in case of really enough time has passed by take action.

badly chosen variable names
better names:
startOfPeriod
timePassedSincePeriodStarted
actualTime

void loop() {
  // This is line #1. It stores the actual time in milliseconds
  actualTime = millis();

 // Now we calculate the interval between "newTime" and "oldTime"
// This is the time in milliseconds expired since the last time we have stored oldTime
  timePassedSincePeriodStarted = (actualTime - startOfPeriod);
 
 // As long as this difference is  less than or equal to 1000 msecs 
 // everything inside the if-clause is skipped!
  if (timePassedSincePeriodStarted  > 1000 && ledOn == 0) {
    digitalWrite(led, HIGH);
    ledOn = 1;
    startOfPeriod = actualTime ; // update variable startOfPeriod because a NEW periods starts right now
  }
// This is the line after this if-clause
// and the end of loop() 
// so the controller will proceed with line #1 again
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.