How does it work?
Learn how ptScheduler works.
Last updated
Learn how ptScheduler works.
Last updated
ptScheduler uses the native micros()
implementation of Arduino. The micros()
function is a timer-based ISR (Interrupt Service Routine) that increments a global counter variable (32-bit unsigned integer) every microsecond. Calling the micros()
function will return the current value of the counter. Since Arduino implements the counter as a 32-bit unsigned integer, the counter will overflow every 71.582788266667 minutes. But ptScheduler is written with a workaround to overcome such overflow events and support up to 18446744000000000000 microseconds (584,942.42 years).
When you create a new ptScheduler object, you can specify the time intervals and execution modes. The time interval is stored in a variable or in an array, and is compared to the time elapsed since the last time the task was executed. For example, if the time period for a oneshot task is 1000 milliseconds, the value is stored in a list called intervalList
and is compared to the elapsed time every time the associated call()
function is invoked. If the elapsed time is less than 1000 ms, call()
will return false
. If the elapsed time is equal or greater than 1000 ms, call()
will return true
. This will cause the code under the conditional clause to be executed once. The current value returned by the micros()
will now be saved as the new entry point to calculate the elapsed time.
The next time you invoke call()
and if the elapsed time is less than 1000 ms, the function will again return false
. This kind of task where the code is executed only once after every time interval is called a Oneshot task. You might want to execute a task continuously for a specific time period and then sleep for another time period. It is possible with Spanning tasks. In addition to these basic types of tasks, ptScheduler allows you to alter many other behaviors of a task on the fly.
Let's look in detail how the logic behind task modes and timing work.
This is the type of task that is executed only once every time interval. This is useful for tasks such as blinking an LED every second, or printing a message to the serial monitor, or polling a sensor etc. Let's see how a oneshot task with a single interval works.
The default task mode is PT_MODE_ONESHOT
and the time interval is 1 second. This value is saved as the first value on an interval sequence list. An interval sequence is a set of repeating intervals, saved as an array.
When you first invoke sayHello.call()
, the value returned by micros()
will be saved to entryPoint
variable. The call()
will also immediately return true
since it is the first time we are invoking the task. The executionCounter
is incremented from 0 to 1. If you do not want the task to return true
when starting the task, you can set a pre-task delay using setSkipTime()
function. This will cause the task to wait until the skip time is elapsed, before returning true
.
If you invoke sayHello.call()
again within one second of the last call, the value returned by getTimeElapsed()
will be compared against the previously saved entryPoint
and the difference is saved in elapsedTime
. If the difference is less than 1 second, call()
immediately returns false
. There will be no changes to any other variables at this point.
If you invoke sayHello.call()
one second after the first call, the value returned by getTimeElapsed()
is again compared against entryPoint
. The difference is saved in elapsedTime
and if the value is greater than or equal to 1 second, call()
will immediately return true
. It will also save the new value returned by micros()
to entryPoint
for the next cycle, reset elapsedTime
to 0, and increment executionCounter
by 1.
If the sequenceRepetition
value is 0, the above-explained cycle repeats indefinitely. If you want to stop the task after a finite number of cycles, you can set sequenceRepetition
by calling setSequenceRepetition(<value>)
function. The task will automatically suspend or disable itself (determined by sleepMode
) after the specified number of repetitions.
During the Active time, the call()
will return true
, and will return false
during the inactive time. Ti
is the time interval of the task.
A task can also have multiple intervals in a sequence. Below shows a task with two different intervals T1
and T2
.
Spanning tasks, as the name suggests, span over an interval. The output of a spanning task remains true
for one duration and remains false
for the next duration. Spanning tasks are useful when you want to continuously perform some operations, in a repeating cycle. Let's see how a spanning task works.
The task mode is PT_MODE_SPANNING
and the time interval is 1 second. This value is saved as the first value on an interval sequence list. An interval sequence is a set of repeating intervals, saved as an array.
When you first invoke spanningTask.call()
, the value returned by micros()
will be saved to entryPoint
variable. The call()
will also immediately return true
since it is the first time we are invoking the task. If you do not want the task to return true
when starting the task, you can set a pre-task delay using setSkipTime()
function. This will cause the task to wait until the skip time is elapsed, before returning true
.
If you invoke sayHello.call()
again within one second of the last call, the value returned by getTimeElapsed()
will be compared against the previously saved entryPoint
and the difference is saved in elapsedTime
. If the difference is less than 1 second, call()
immediately returns true
. There will be no changes to any other variables at this point.
If you invoke sayHello.call()
one second after the first call, the value returned by getTimeElapsed()
is again compared against entryPoint
. The difference is saved in elapsedTime
and if the value is greater than or equal to 1 second, call()
will immediately return false
. This completes an interval cycle for spanning task. It will also save the new value returned by micros()
to entryPoint
for the next cycle, reset elapsedTime
to 0, and increment executionCounter
by 1.
If the sequenceRepetition
value is 0, the above-explained cycle repeats indefinitely. If you want to stop the task after a finite number of cycles, you can set sequenceRepetition
by calling setSequenceRepetition(<value>)
function. The task will automatically suspend or disable itself (determined by sleepMode
) after the specified number of repetitions.
You can have any number of intervals of any length.