Here the sketches behind the Wokwi links:
Millis() Function Example
/*
============================
Millis() Function Example
============================
This is an example of a non-blocking millis() function replacing delay()
First Edition 2023-04-02
ec2021
Simulation: https://wokwi.com/projects/360903822433974273
Discussion: https://forum.arduino.cc/t/millis-instead-of-delay-and-loop-instead-of-for-loop/1110044/7
Changed 2023-07-26
*/
constexpr byte LEDPin = 13;
void setup() {
Serial.begin(115200);
pinMode(LEDPin, OUTPUT);
}
unsigned long lastChange = 0; // Variable to store the time in ms when ledState was changed
unsigned long delayTime = 300; // Delay in [ms] when then next change shall take place
boolean firstTime = true; // Boolean that ensures that the if-clause will be performed immediately
// in the first call
void loop() {
if (millis()-lastChange >= delayTime || firstTime){
// As "firstTime" has been set to true when the sketch started
// it will definitely perform what's inside the curly brackets
// immediately in the first loop()
// The greater in ">="" is required as we cannot always be sure
// that this comparison is performed exactly "delayTime" later ...
lastChange = millis(); // Stores this time so that it takes in mininimum delayTime for
// the next entry to this bracket procedures
boolean ledState = digitalRead(LEDPin); // Read the actual status of the ledPin, so we do not have
// to memorize and handle it in a variable
digitalWrite(LEDPin, !ledState); // Change the status by inverting ledState with the ! operator
// !ledState provides the opposite of ledState
firstTime = false; // "firstTime" is set to false to make sure
// that in future the entry into the if-clause only depends
// on the comparison of the time difference between "millis()"
// and "lastChange" with "delayTime"
}
}
This is a flowchart of the millis() function example:
- The statements marked grey are only performed once after start of the sketch.
- The green parts are performed every loop().
- The blue path is performed when the condition in the "diamant" symbol is true otherwise the sketch follows the yellow path.
So most of the loops the sketch follows the green and yellow path. Only on the first occasion and then every 300 msec the blue statements are performed.
Selfmade For-Loop I
/*
============================
Selfmade For-Loop I
============================
This is an example of a "selfmade" for-loop
which is usually required where a a non-blocking
loop is required
First Edition 2023-04-02
ec2021
Simulation: https://wokwi.com/projects/360901842970872833
Discussion: https://forum.arduino.cc/t/millis-instead-of-delay-and-loop-instead-of-for-loop/1110044
Changed 2023-07-26
*/
void setup() {
Serial.begin(115200);
// Standard for-loop
Serial.println("Standard for-loop");
for (int i = 0; i < 10;i++){
Serial.print(i);
Serial.print("\t"); // prints tabs
}
Serial.println();
Serial.println("Selfmade for-loop");
}
// Selfmade for-loop with the same result as the Standard for-loop coded in setup()
// The next line replaces the (int i = 0) in for (int i = 0; i < 10;i++)
// ---------
int i = 0;
void loop() {
// This replaces the condition in for (int i = 0; i < 10;i++)
// ------
if (i < 10) {
Serial.print(i);
Serial.print("\t"); // prints tabs
i++;
}
}
Selfmade For-Loop II
/*
============================
Selfmade For-Loop II
============================
This is an example of a "selfmade" for-loop
which is usually required where a a non-blocking
loop is required e.g. to blink an LED
This is an example of
a non-blocking millis() function to blink a LED
but counting a variable in a for loop with delay()
The LED will not blink in the correct timing as the for-loop incl.
the delay() blocks loop()
First Edition 2023-04-02
ec2021
Simulation: https://wokwi.com/projects/360902704451617793
Discussion: https://forum.arduino.cc/t/millis-instead-of-delay-and-loop-instead-of-for-loop/1110044/3
Changed 2023-07-26
*/
constexpr byte LEDPin = 13;
void setup() {
Serial.begin(115200);
pinMode(LEDPin, OUTPUT);
}
unsigned long lastChange = 0; // Variable to store the time in ms when ledState was changed
unsigned long delayTime = 300; // Delay in [ms] when then next change shall take place
unsigned long delayCount = 500;
int iMax = 9;
void loop() {
if (millis()-lastChange >= delayTime){
lastChange = millis();
boolean ledState = digitalRead(LEDPin);
digitalWrite(LEDPin, !ledState);
}
for (int i = 0; i <= iMax;i++){
Serial.print(i);
Serial.print("\t"); // prints tabs
delay(delayCount);
if (i == iMax) Serial.println();
}
}
This is the flowchart of Selfmade For-Loop II (if you watch carefully you will see that the for-loop is broken up into an initialization, an incrementation statement and the condition statement that ends the for-loop):
While the green and blue parts are performed very quickly, the red loop contains a delay of 500 msec and is performed 10 times (iMax+1 times). Therefore the red loop consumes 10 x 0.5 s = 5 sec (plus a little bit for the other functions inside the red loop which can be neglected if compared with the delay).
That is the reason why the green if condition is only checked about every 5 sec. This is a far greater interval than the intended 0.3 sec to toggle the led state. Obviously the delay() function makes it impossible to combine the two functionalities in a sequence. The function delay() has to be replaced by a different method ...
A possible solution is to use a second millis() function to control the timing of the counting which leads to the next example:
Selfmade For-Loop III
/*
============================
Selfmade For-Loop III
============================
This is an example of a "selfmade" for-loop
which is usually required where a a non-blocking
loop is required e.g. to blink an LED
This is an example of a non-blocking millis() function replacing delay()
to blink a LED and counting a variable in given time intervals
First Edition 2023-04-02
ec2021
Simulation: https://wokwi.com/projects/360905127753897985
Discussion: https://forum.arduino.cc/t/millis-instead-of-delay-and-loop-instead-of-for-loop/1110044
Changed 2023-07-26
*/
constexpr byte LEDPin = 13;
void setup() {
Serial.begin(115200);
pinMode(LEDPin, OUTPUT);
}
unsigned long lastChange = 0; // Variable to store the time in ms when ledState was changed
unsigned long delayTime = 300; // Delay in [ms] when then next change shall take place
unsigned long lastCount = 0;
unsigned long delayCount = 500;
boolean firstBlink = true; // Added firstBlink and firstCount to make sure
boolean firstCount = true; // that the millis()-if-clauses are already entered
// in the first loop()
int i = 0;
int iMax = 9;
void loop() {
if (millis()-lastChange >= delayTime || firstBlink){
lastChange = millis();
boolean ledState = digitalRead(LEDPin);
digitalWrite(LEDPin, !ledState);
firstBlink = false;
}
if (millis()-lastCount >= delayCount || firstCount){
lastCount = millis();
firstCount = false;
if (i <= iMax) {
Serial.print(i);
Serial.print("\t"); // prints tabs
i++;
} else {
Serial.println();
i = 0;
}
}
}
Selfmade For-Loop IV
/*
============================
Selfmade For-Loop IV
============================
This is an example of a "selfmade" for-loop
which is usually required where a a non-blocking
loop is required e.g. to blink an LED
This is an example of a non-blocking millis() function replacing delay()
to blink a LED and counting a variable in given time intervals
It is more or less identical to Selfmade For-Loop III but
the handling of the LED and the counting are taken out of loop()
into separate functions to "reduce complexity"; it is easier to understand
and test functions which are short and at least do not require scrolling
of the screen
First Edition 2023-04-02
ec2021
Simulation: https://wokwi.com/projects/360905879808368641
Discussion: https://forum.arduino.cc/t/millis-instead-of-delay-and-loop-instead-of-for-loop/1110044
Changed 2023-07-26
*/
constexpr byte LEDPin = 13;
constexpr int MaxCount = 9;
void setup() {
Serial.begin(115200);
pinMode(LEDPin, OUTPUT);
}
void loop() {
handleLED();
doCountingUpTo(MaxCount);
}
void handleLED(){
static unsigned long lastChange = 0; // Variable to store the time in ms when ledState was changed
static unsigned long delayTime = 300; // Delay in [ms] when then next change shall take place
static boolean firstChange = true; // To make sure that the if-clause is entered in the first call
// of this function
if (millis()-lastChange >= delayTime || firstChange){
lastChange = millis();
firstChange = false;
boolean ledState = digitalRead(LEDPin);
digitalWrite(LEDPin, !ledState);
}
}
void doCountingUpTo(int iMax){
static unsigned long lastCount = 0;
static unsigned long delayCount = 500;
static boolean firstCount = true;
static int i = 0;
if (millis()-lastCount >= delayCount||firstCount){
lastCount = millis();
firstCount = false;
if (i <= iMax) {
Serial.print(i);
Serial.print("\t"); // prints tabs
i++;
} else {
Serial.println();
i = 0;
}
}
}
The simple wiring for the blink functions