Arduino: TaskScheduler, no more millis or delay

In this post I am going to talk about TaskScheduler. TaskScheduler are, as the name implies, an object that will allow us to create periodic tasks without having to use millis or conditionals.

How do they work?

TaskSchedulers are objects to which you can add tasks and they are in charge of executing them from time to time. In addition, these schedulers are dynamic and allow you to vary the waiting time between tasks, and even enable and disable them.

In this post I will tell you about one that I have used and that is called TaskScheduler, which I found simple and functional, in addition to providing certain useful functionalities.

Installation

To install the TaskScheduler, we will only have to open the Arduino IDE, enter the library manager, search for TaskScheduler and install it will give us:

Functions

Among the functions available to it, the following can be highlighted:

  • Scheduled execution every x milliseconds and even microseconds.
  • Switch to “Standby” mode, when you are not executing any task, which will allow us to save energy.
  • Running a number of times or forever.
  • Dynamic tasks activation and deactivation.
  • Change settings like number of runs or time between runs dynamically.

What is the difference with millis?

The difference with milis is basically that you don’t have to be using logics to manage the executions, but the module itself does it. This will allow us to make code more readable and easier to maintain. In addition, we must take into account the extra functions it provides, such as saving energy when not in use, or changing settings dynamically.

Is multitask?

It depends … personally, I refuse to call something that is not really multitasking, and both the millis function and the TaskScheduler are not multitasking on Arduino Uno as much as people online claim that they are. Why do I think this? Because in neither case are two tasks executed at the same time, but rather one, then another, and another … but never two at the same time. If you create a task that takes 10 seconds to run, and then another that runs every second, the one that runs every second will have to wait for the other to finish before you can continue.

Of course I would be cheating on you if I told you this is always the case. If your microcontroller is Single Core like for example the Arduino Uno that I mentioned above, Nano or all those based on ATMega328, it will not be multitasking. However, if your microcontroller is Dual Core or higher, such as the Arduino Due, then if you can execute functions in multitasking mode.

Objects that we have

  • Task: This object will allow you to configure the execution of the function, as well as its number of executions and how often.
  • Scheduler: This object is the scheduler in charge of executing the tasks, which will have to be executed in each loop.

Simple example

In this example we will see the simple function of turning the Arduino internal LED on and off, but using the TaskScheduler for that purpose.

#include <TaskScheduler.h>

// We declare the function that we are going to use
void led_blink();

// We create the Scheduler that will be in charge of managing the tasks
Scheduler runner;

// We create the task indicating that it runs every 500 milliseconds, forever, and call the led_blink function
Task TareaLED(500, TASK_FOREVER, &led_blink);

bool statusLED = false;

// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(9600);

  // We configure the internal led pin as output
  pinMode(LED_BUILTIN, OUTPUT);

  // We add the task to the task scheduler
  runner.addTask(TareaLED);

  // We activate the task
  TareaLED.enable();
}

// the loop function runs over and over again forever
void loop() {
  // It is necessary to run the runner on each loop
  runner.execute();
}

void led_blink() {
  statusLED = !statusLED;
  digitalWrite(LED_BUILTIN, statusLED);
  Serial.println((String)millis() + " - Led: " + (String)statusLED);
}

As we can see, the Scheduler is created to manage the tasks, then the task that we will execute every 500ms is created and finally we add this task to the Scheduler, activating it later (otherwise it would not be executed).

Energy saving

One of the reasons why I liked this library and why it seems much better than using millis or delay, is because of the energy management it does. Just saying that we want the microcontroller to be put into low power mode while there are no tasks, she is in charge of managing it.

In a test that I did with an ATMega328p with the basic configuration, it has been able to lower the consumption from 8.4ma during the operation of the microcontroller, to just 3.4ma on standby. This means that without doing anything special you consume less than half. In a project where, for example, a sensor is read every minute, it is a great battery saving.

Without further ado, I leave you the example I used to measure the current used, which is nothing more than turning a led on and off every five seconds. Of course, when the led is on it consumes a lot more than what I mentioned above.

#include <TaskScheduler.h>

void ledBlink();

Scheduler runner;
Task tBlink(5000, TASK_FOREVER, &ledBlink);

bool ledStatus = false;

void ledBlink(){
  ledStatus = !ledStatus;
  digitalWrite(LED_BUILTIN, ledStatus);
}

void setup(){
  runner.addTask(tBlink);
  tBlink.enable();
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop(){
  runner.execute();
}

As you can see in the code, just by adding a line, energy savings have been added to the Scheduler:

#define _TASK_SLEEP_ON_IDLE_RUN

More information

For more information about the module, you can visit its GitHub page: https://github.com/arkhipenko/TaskScheduler

I recommend using the method described at the beginning to install it, instead of downloading it from Github. The operation will be the same, but installing it from the Arduino library manager will make it easier for us to update it.

Best Regards!!

1 thought on “Arduino: TaskScheduler, no more millis or delay”

  1. I have a different understanding on multitasking. It is a conceptcrelted to context switch, not necessarily parallel execution. Hence, a single core processor is ablento run multitasking, as long as there is context switching.
    Nonetheless, i do agree what you have in Arduino is not multitasking.

    Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.