Blink Sketch without delay ()

Hello and welcome to our contribution today. Today it's about a sketch that everyone probably knows, and I'm sure you've uploaded it to your microcontroller several times already: the Blink Sketch.

I myself have never paid much attention to the sketch, and I only use it to check if a module even gives a sign of life.

The use of delay(1000) in the Blink Sketch, however, has a major disadvantage: the microcontroller waits in place for a second (1000 ms), and can do nothing else in time. It is therefore not possible to switch on and off a second LED briefly during the Delay.

It becomes problematic even if you are working on a project where you are asked to check the status of a pin while blinking, for example to check if a switch has been pressed. When a button is pressed during the Delay and released before the Delay ends, the microcontroller gets nothing.

Take the following small code snippets as an example:

  void setup() {

  pinMode(3, OUTPUT);   pinMode(4, OUTPUT);   pinMode(8, INPUT);

void run() {   if (digitalRead(8) == HIGH){     digitalWrite(4, !digitalRead(4)); // Switches LED to pin 4 AN/AUS   }   digitalWrite(3, HIGH); // LED to Pin 3 AN   delay(1000); // Pause   digitalWrite(3, LOW); // LED to Pin 3 AUS   delay(1000); // Pause

At the beginning of the "void loop()" loop we read the status from the button on Pin 8. If this is HIGH, the value of Pin 4 is inverted by digitalWrite to Pin 4.

Then we switch pin 3 to HIGH, wait a second, flip the pin back to LOW, and wait another second.

So if we press the button during the two Delays, nothing happens. Only when we hold the button down while the digitalRead(8) is called will we turn on or off the second LED.

This became problematic, for example, with the alarm system that we recently introduced in the blog. A motion sensor triggered the alarm there. If you were standing in front of the device and wanted to enter the security code, the alarm was triggered repeatedly, which led to a pause at the input.

Therefore, it is recommended to omit the delay() function.

A possible solution would be, for example, to reduce the Delay to 100m or even less, and to count a counter high for each pass. When this has reached a certain value, put it back to 0 and switch the LED.

But we can save all the work thanks to the millis() function. The millis() function returns the number of milliseconds that have passed since the start of the current program. The number is reset to zero after about fifty days.

To save this value in a variable, it should be of the type "unsuitable long". This allows a number between0 and 4.294.967.295.

In our example we create a variable called "previousMillis" and create a variable of the type "const" in which we define the interval of 1000 ms.

When running "void loop()" we drop the output of milis() in the variable "currentMillis". Then we check if it has passed since the last run 1000 ms. If yes, previousMillis will be overwritten with currentMillis, and the LED will be either Disabled.


unsuitable long previousMillis = 0; // saves the time at which it was last switched on
const long interval = 1000; // Length of break in ms

void setup() {   pinMode(3, OUTPUT); // LED 1   pinMode(4, OUTPUT); // LED 2   pinMode(8, INPUT);  // Buttons

void run() {   if (digitalRead(8) == HIGH){     digitalWrite(4, !digitalRead(4)); // Switches LED to pin 4 AN/AUS   }
 unsuitable long currentMillis = millis(); // Current time is saved in currentMillis   if (currentMillis - previousMillis >= interval) { // If more than 1000 ms have passed      previousMillis = currentMillis; // Time of last circuit is recorded    digitalWrite(3, !digitalRead(3)); // LED is on or off. disabled   }


Now we can switch on the second LED with the button, regardless of what the first LED does.

Whoever has built the whole thing and tried the code will find that the main loop will pass so often that it is not so easy to switch the second LED with a button.

Here we would have to deflect the button (Engl. debouncing), but this is a theme for another blog post.

I hope our contribution today has shown you how easy it can be to work with millis().

We thank you for the growing interest and the many feedback from the last few weeks, and we will see you tomorrow.

Your Markus Neumann






Basics software


W. Parschfeld

W. Parschfeld

Alternativ wäre eine parallele Programmierung zu empfehlen – kann für viele zufälligen parallele Ereignisse benutz werden: z.B. Analog-Uhr auf graf. Display, Abfrage verschiedener Steuerimpulse, Kommunikation über I2C etc. (z.B. vom WiFi-Modul), laden von SD-Card… Gute Erfahrungungen habe ich mit der Bibliothek TimedAction gemacht …

A. Deppe

A. Deppe

Im Prinzip eine gute Idee – allerdings gibt es genau für dieses Problem (wenigstens für die MKR’s) die “scheduler” Funktion. Zusammen mit dem Scheduler macht die Delay (und Yield) Funktion dann wieder absolut Sinn , denn Delay legt die entsprechende Funktion in der Delay angewendet wird für den Delay Zeitraum schlafen und gib die Rechenzeit für andere “geschedulte” Funktionen frei. Das ist erheblich effizienter und ermöglicht multitasking.

Noch eine Bemerkung zu dem angeschnittenen Thema “Alarmanlage”: Wenn man Eingaben sicher verarbeiten will, ist es meistens eine gute Idee das Interupt handling dafür zu bemühen. Ich würde versuchenden die void loop so klein wie möglich zu halten und da nur das Interupt handling drin zu realisieren. Die eigentliche Verarbeitung würde ich in eigene Funktionen auslagern. Das ist nicht nur übersichtlicher sondern auch Speicher effizienter, weil die Funktionen/Variablen nur zur Laufzeit instanziert werden.

Auch hier kann der Scheduler helfen – um z.B. Ein- und Ausgabe zu deserialisieren.

Leave a comment

All comments are moderated before being published

Recommended blog posts

  1. Install ESP32 now from the board manager
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. OTA - Over the Air - ESP programming via WLAN