Arduino Task Scheduler

RE: How to Use an Arduino Task Scheduler to Run Multiple Functions Simultaneously

At the bottom of the loop:

    // Add a delay to prevent the loop from running too fast‎
‎  delay(10);‎

Question: What is the downside if the loop runs “too fast?”

Hello jchristensen and welcome to the forum.

When you loop an LED to be ON/OFF fast enough it just looks like it is on to the human eye. Seven segment multiplexers actually take advantage of looping too fast to drive multiple displays from just one set of outputs.

1 Like

Hello jchristensen,

That’s a very nice article you mentioned as written by Don Wilcher. You are asking a good question about the faux Arduino Task Scheduler**.**

Let’s explore some of the background information that will help answer your question. There are two very important concepts that are not immediately obvious to folks programming a microcontroller.

Blocking code : This is code that stops the microcontroller for a duration of time as with delay(1000); or indefinitely as with while(1);. The microcontroller is effectively stuck in a tight loop doing nothing at all. It does not respond to inputs and does not control outputs.

Non-blocking Code: This type of code is generally preferred as the microcontroller is never stuck in one location. It will continue to perform the code within loop as fast as it can. Function such as delay( ) are never allowed with non-blocking code as this would prevent the microcontroller from visiting all of the code in a timely manner. We could say that any system that requires real time performance does not allow block code as it would prevent timely response to the outside world.

There is another closely related concept that we must now address. We must at least mention interrupt. For our purposes, an interrupt is something that happen in the background typically at the hardware level. One important example is millis( ) which is a function prominently featured in the article you mentioned. Here the Arduino keep track of time by periodically interrupting the microcontroller and incrementing the register associated with the millis( ) function. Understand that a basic Arduino does not have a real time clock. It is only through this background interrupt processes that we have a crude ability to track time.

Note that the concept of the interrupt is deliberately hidden from the Arduino programmer. That is until you explore functions such as attachInterrupt( ).

Returning to Don Wilcher’s code we see this non-block control of an LED:

‎ if (millis() - task1Time >= TASK_INTERVAL_1) {‎
‎ task1Time = millis();‎
‎ digitalWrite(LED_PIN_1, !digitalRead(LED_PIN_1)); // Toggle LED 1‎
‎ }‎

Consider a clock analogy. Suppose we decided to do something every 7 seconds. Also suppose that we start the process when the clock is at second 14. From now until the end of time I would ask you a question:

Is the current time – 14 greater than 7?

If not, no worries, I’ll ask again in a few microseconds during the next loop iteration. If it is, great! We will do something and set up a new question:

Is the current time – 21 greater than 7?

TLDR Non-blocking code is required for real time response. Interrupts run in the background and are largely hidden by the Arduino programmers in order to provide a user-friendly environment.

What is the downside if the loop runs “too fast?”

To answer your question, we must answer two additional questions:

  1. Does the blink rate depend on the loop speed? In this example it does not as the non-blocking delay is dependent only on millis( ) which is a background (interrupt) derived process.

  2. Are any background Arduino tasks (interrupts) somehow enabled when the delay function is used? To my knowledge there are none. Although, I could be wrong and invite others to correct my understanding. Note that things are more complex when we communicate using serial methods but that is not applicable in the example.

Consequently, the delay(10) could be removed.