How does it work?

Learn how ptScheduler works.

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.

Oneshot Task

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.

ptScheduler sayHello = ptScheduler(1000000); //time in microseconds
  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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 Task

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.

ptScheduler spanningTask = ptScheduler(PT_MODE_SPANNING, 1000000);

  • 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.

Last updated