diff options
| author | Anatoli Arkhipenko <arkhipenko@hotmail.com> | 2015-10-01 09:34:10 -0400 |
|---|---|---|
| committer | Anatoli Arkhipenko <arkhipenko@hotmail.com> | 2015-10-01 09:34:10 -0400 |
| commit | 332d0cf661ff7d86640773168113ffe5e47de505 (patch) | |
| tree | 527af3ac3deaaaafdffdaced2512b2d9b01a4b49 /extras/TaskScheduler.html | |
| parent | 1efab7eae2d24629f819e4b0ae5aa7aa0b7bcf43 (diff) | |
Updated library to be arduino 1.5 comliant
* Included library.properties file
* Updated version numbers to be semver compliant
* Tagged lib files with the version number
Diffstat (limited to 'extras/TaskScheduler.html')
| -rw-r--r-- | extras/TaskScheduler.html | 841 |
1 files changed, 841 insertions, 0 deletions
diff --git a/extras/TaskScheduler.html b/extras/TaskScheduler.html new file mode 100644 index 0000000..7855c7f --- /dev/null +++ b/extras/TaskScheduler.html @@ -0,0 +1,841 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> + <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8"> + <TITLE></TITLE> + <META NAME="GENERATOR" CONTENT="LibreOffice 3.5 (Linux)"> + <META NAME="CREATED" CONTENT="20150206;16300000"> + <META NAME="CHANGEDBY" CONTENT="Anatoli Arkhipenko"> + <META NAME="CHANGED" CONTENT="20150921;21210000"> + <META NAME="Info 1" CONTENT=""> + <META NAME="Info 2" CONTENT=""> + <META NAME="Info 3" CONTENT=""> + <META NAME="Info 4" CONTENT=""> + <STYLE TYPE="text/css"> + <!-- + @page { margin: 0.79in } + P { margin-bottom: 0.08in; direction: ltr; color: #000000; widows: 0; orphans: 0 } + P.western { font-family: "Liberation Serif", "Times New Roman", serif; font-size: 12pt; so-language: en-US } + P.cjk { font-family: "WenQuanYi Micro Hei", "MS Mincho"; font-size: 12pt; so-language: zh-CN } + P.ctl { font-family: "Lohit Hindi", "MS Mincho"; font-size: 12pt; so-language: hi-IN } + --> + </STYLE> +</HEAD> +<BODY LANG="en-US" TEXT="#000000" DIR="LTR"> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>Task Scheduler – +cooperative multitasking for Arduino microcontrollers</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>Version 1.6.0: +2015-10-01</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>REQUIREMENT</B>:</P> +<P CLASS="western" STYLE="margin-bottom: 0in">A lightweight +implementation of the task scheduling supporting:</P> +<OL> + <LI><P CLASS="western" STYLE="margin-bottom: 0in">execution period + (n times per second)</P> + <LI><P CLASS="western" STYLE="margin-bottom: 0in">number of + iterations (n times)</P> + <LI><P CLASS="western" STYLE="margin-bottom: 0in">execution of tasks + in predefined sequence</P> + <LI><P CLASS="western" STYLE="margin-bottom: 0in">dynamic change of + the execution parameters for both tasks and execution schedule</P> + <LI><P CLASS="western" STYLE="margin-bottom: 0in">power saving via + entering IDLE sleep mode if no tasks are scheduled to run</P> +</OL> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>IDEA</B>:</P> +<P CLASS="western" STYLE="margin-bottom: 0in">“Task” is a +container concept that links together:</P> +<OL> + <LI><P CLASS="western" STYLE="margin-bottom: 0in">Execution interval</P> + <LI><P CLASS="western" STYLE="margin-bottom: 0in">Number of + execution iterations</P> + <LI><P CLASS="western" STYLE="margin-bottom: 0in">A piece of code + performing the task activities (callback function)</P> +</OL> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">Tasks are linked into +execution chains, which are processed by the “Scheduler” in the +order they are linked.</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">Tasks are responsible +for supporting cooperative multitasking by being “good neighbors”, +i.e., running their callback functions in a non-blocking way and +releasing control as soon as possible. +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">“Scheduler” is +executing Tasks' callback functions in the order the tasks were added +to the chain, from first to last. Scheduler stops and exists after +processing the chain once in order to allow other statements in the +main code of <B>loop()</B> function to run. This a “scheduling +pass”.</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">If compiled with +<FONT FACE="Courier New, monospace">_TASK_SLEEP_ON_IDLE_RUN</FONT> +enabled, the scheduler will place processor into IDLE sleep mode (for +approximately 1 ms, as the timer interrupt will wake it up), after +what is determined to be an “idle” pass. An Idle Pass is a pass +through the chain when no Tasks were scheduled to run their callback +functions. This is done to avoid repetitive empty passes through the +chain when no tasks need to be executed. If any of the tasks in the +chain always requires immediate execution (aInterval = 0), then there +will be no end-of-pass delay.</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>Note: </B>Task +Scheduler uses <B>millis()</B> to determine if tasks are ready to be +invoked. Therefore, if you put your device to any “deep” sleep +mode disabling timer interrupts, the <B>millis()</B> count will be +suspended, leading to effective suspension of scheduling. Upon wake +up, active tasks need to be re-enabled, which will effectively reset +their internal time scheduling variables to the new value of +<B>millis(). </B>Time spent in deep sleep mode should be considered +“frozen”, i.e., if a task was scheduled to run in 1 second from +now, and device was put to sleep for 5 minutes, upon wake up, the +task will still be scheduled 1 second from the time of wake up. +Executing <B>enable() </B>function on this tasks will make it run as +soon as possible. This is a concern only for tasks which are required +to run in a truly periodical manner (in absolute time terms). +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>COMPILE PARAMETERS:</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in">This library could be +compiled with several options. +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">These parameters must +be defined before inclusion of the library header file into the +sketch.</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">#define +<B>_TASK_TIMECRITICAL</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in">...will compile the +library with time critical tracking option enabled.</P> +<P CLASS="western" STYLE="margin-bottom: 0in">Time critical option +keeps track where next execution time of the task falls, and makes it +available via API through Task::<B> getOverrun() </B>function. If +<B>getOverrun </B>returns a negative value, this Task’s next +execution time is in the past, and task is behind schedule. This most +probably means that either task’s callback function runtime is too +long, or the execution interval is too short (then schedule is too +aggressive).</P> +<P CLASS="western" STYLE="margin-bottom: 0in">A positive value +indicates that task is on schedule, and callback functions have +enough time to finish before the next scheduled pass. +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">#define +<B>_TASK_SLEEP_ON_IDLE_RUN</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in">...will compile the +library with the <B>sleep</B> option enabled (AVR boards only).</P> +<P CLASS="western" STYLE="margin-bottom: 0in">When enabled, scheduler +will put the microcontroller into <B>SLEEP_MODE_IDLE</B> state if +none of the tasks’ callback functions were activated during pass. +<B>IDLE</B> state is interrupted by timers once every 1 ms. Helps +conserve power. Device in SLEEP_MODE_IDLE wakes up to all hardware +and timer interrupts, so scheduling is kept current.</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>NOTE: above +parameters are DISABLED by default, and need to be explicitly +enabled.</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>API DOCUMENTATION:</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>TASKS:</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">CREATION:</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>Task();</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Default +constructor. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Takes +no parameters and creates a task that could be scheduled to run at +every scheduling pass indefinitely, but does not have a callback +function defined, so no execution will actually take place. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">All +tasks are created <B>disabled</B> by default.</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid"> +<B>Task(unsigned long aInterval, long aIterations, void +(*aCallback)(), Scheduler* aScheduler, bool aEnable);</B></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Constructor +with parameters. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Creates +a task that is scheduled to run every <aInterval> milliseconds, +<aIterations> times, executing <aCallback> function on +every pass. +</P> +<OL> + <LI><P CLASS="western" STYLE="margin-bottom: 0in">aInterval is in + milliseconds</P> + <LI><P CLASS="western" STYLE="margin-bottom: 0in">aIteration in + number of times, -1 for indefinite execution<BR><B>Note: </B>Tasks + do not remember the number of iteration set initially. After the + iterations are done, internal iteration counter is 0. If you need to + perform another set of iterations, you need to set the number of + iterations again. <BR><B>Note: </B>Tasks which performed all their + iterations remain active. + </P> + <LI><P CLASS="western" STYLE="margin-bottom: 0in">aCallback is a + pointer to a void function without parameters</P> + <LI><P CLASS="western" STYLE="margin-bottom: 0in">aScheduler – + <B>optional</B> reference to existing scheduler. If supplied (not + NULL) this task will be appended to the task chain of the current + scheduler). <B>Default=NULL</B></P> + <LI><P CLASS="western" STYLE="margin-bottom: 0in">aEnable – + <B>optional</B>. Value of <B>true </B>will create task enabled. + <B>Default = false</B></P> +</OL> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">All +tasks are created <B>disabled</B> by default (unless aEnable = true). +You have to explicitly enable the task for execution.</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Enabled +task is scheduled for execution immediately. Enable tasks with delay +(standard execution interval or specific execution interval) in order +to defer first run of the task.</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>INFORMATION</B></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">The +following 3 “getter” functions return task status +(enabled/disabled), execution interval in milliseconds, number of +<I><B>remaining</B></I> iterations. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>bool +isEnabled() </B> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>unsigned +long getInterval()</B></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>long +getIterations() </B> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>long getOverrun()</B></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If +library is compiled with <FONT FACE="Courier New, monospace">_TASK_TIMECRITICAL</FONT> +enabled, tasks are monitored for “long running” scenario. A “long +running” task is a task that does not finish processing its +callback functions quickly, and thus creates a situation for itself +and other tasks where they don't run on a scheduled interval, but +rather “catch up” and are behind. When task scheduler sets the +next execution target time, it adds Task's execution interval to the +previously scheduled execution time:</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> <B>next +execution time = previous execution time + task execution interval</B></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If +<B>next execution time</B> happens to be already in the past (<B>next +execution time</B> < <B>millis()</B>), then task is considered +<I><B>overrun</B></I>. <B>GetOverrun</B> function returns number of +milliseconds between next execution time and current time. If the +<B>value is negative</B>, the task is overrun by that many +milliseconds. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Positive +value indicate number of milliseconds of slack this task has for +execution purposes. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>bool +isFirstIteration()</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>bool +isLastIteration()</B></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">For +tasks with a defined number of iterations, indicates whether current +pass is a first or a last iteration of the task (respectively). +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid"> +<B>CONTROL:</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>void enable();</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Enables +the task, and schedules it for immediate execution (without delay) at +this or next scheduling pass depending on when the task was enabled. +Scheduler will execute the next pass without any delay because there +is a task which was enabled and requires execution. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>void delay();</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Schedules +the task for execution after a delay (aInterval), but does not change +the enabled/disabled status of the task. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>void +enableDelayed();</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Enables +the task, and schedules it for execution after a delay (aInterval). +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>void enableDelayed +(unsigned long aDelay);</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Enables +the task, and schedules it for execution after a specific delay +(aDelay, which maybe different from aInterval). +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>void restart();</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">For +tasks with limited number of iterations only, <B>restart</B> function +will re-enable the task, set the number of iterations back to when +the task was created and and schedule the task for execution as soon +as possible.</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>void restartDelayed +(unsigned long aDelay);</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Same +as <B>restart() </B>function, with the only difference being that +Task is scheduled to run first iteration after a delay = <B>aDelay</B> +milliseconds.</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>void disable();</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Disables +the task. Scheduler will not execute this task any longer, even if it +remains in the chain. Task can be later re-enabled for execution. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>void set(unsigned +long aInterval, long aIterations, void (*aCallback)());</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Allows +dynamic control of all task execution parameters in one function +call. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">Next three “setter” +functions allow changes of individual task execution control +parameters. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>void +setInterval (unsigned long aInterval) </B> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>void +setIterations (long aIterations) </B> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>void +setCallback (void (*aCallback)()) </B> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>Note: </B>Next +execution time calculation takes place <B>after</B> the callback +function is called, so new interval will be used immediately by the +scheduler. For the situations when one task is changing the interval +parameter for the other, <B>setInterval</B> function calls <B>delay +</B>explicitly to guarantee schedule change, however it <B>does not +</B>enable the task if task is disabled.</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>Note: </B><SPAN STYLE="font-weight: normal">Tasks +that ran through all their allocated iterations are disabled. +</SPAN><B>SetIterations()</B><SPAN STYLE="font-weight: normal"> +method </SPAN><B>DOES NOT</B><SPAN STYLE="font-weight: normal"> +enable the task. Either enable explicitly, or use restart methods. </SPAN> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>TASK SCHEDULER:</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>CREATION:</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>Scheduler()</B><BR><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Default +constructor. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Takes +no parameters. Creates task scheduler with default parameters and an +empty task queue. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>void init()</B></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Initializes +the task queue and scheduler parameters, Executed as part of +constructor, so don't need to be explicitly called after creation.</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note: +</B>be default (if compiled with <FONT FACE="Courier New, monospace">_TASK_TIMECRITICAL</FONT> +enabled) scheduler is allowed to put processor to IDLE sleep mode. If +this behavior was changed via <B>allowSleep() </B>function, <B>inti() +</B>will <B>NOT</B> reset allow sleep particular parameter. +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void +addTask(Task& aTask)</B></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Adds +task aTask to the execution queue (or chain) of tasks by appending it +to the end of the chain. If two tasks are scheduled for execution, +the sequence will match the order tasks are appended to the chain. +However, in reality, due to different timing of task execution, the +actual order will be different. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note: +</B>Currently, changing the execution dynamically is not supported. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">If +you need to reorder the queue – initialize the scheduler and re-add +the tasks in a different order. +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void +deleteTask(Task& aTask)</B></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Deletes +task aTask from the execution chain. The chain of remaining tasks is +linked together (i.e</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">if +original task chain is 1 → 2 → 3 → 4, deleting 3 will result in +1 → 2 → 4).</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><B>Note: +</B>it is not required to delete a task from the chain. A disabled +task will not be executed anyway, but you save a few microseconds per +scheduling pass by deleting it, since it is not even considered for +execution. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">An +example of proper use of this function would be running some sort of +<B>initialize</B> task in the chain, and then deleting it from the +chain since it only needs to run once. +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>void allowSleep(bool +aState) </B> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Available +in API only if compiled with <FONT FACE="Courier New, monospace">_TASK_TIMECRITICAL</FONT> +enabled. Controls whether scheduler is allowed (<B>aState =true</B>), +or not (<B>aState =false</B>) to put processor into IDLE sleep mode +in case not tasks are scheduled to run.</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">The +<B>default</B> behavior of scheduler upon creation is to allow sleep +mode. +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void enableAll()</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><B>void disableAll()</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">enables +and disables (respectively) all tasks in the chain. Convenient if +your need to enable/disable majority of the tasks (i.e. disable all +and then enable one). +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>Task& +currentTask()<BR></B><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Returns +reference to the task, currently executing via <B>execute()</B> loop. +Could be used by callback functions to identify which of the +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR><B>void execute()</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">Executes +one scheduling pass, including end-of-pass sleep. This function +typically placed inside the <B>loop()</B> function of the sketch. +Since <B>execute</B> exits after every pass, you can put additional +statements after <B>execute</B> inside the <B>loop()</B> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in; page-break-after: avoid"> +<B>IMPLEMENTATION SCENARIOS AND IDEAS:</B></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<OL> + <LI><P CLASS="western" STYLE="margin-bottom: 0in"><B>EVENT DRIVEN + PROGRAMMING</B></P> +</OL> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">Each of the processes +of your application becomes a separate and distinct programming area, +which may or may not interact and control each other. +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">Example: +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">In a plant watering +system you need to measure soil humidity, control pump and display +the results</P> +<P CLASS="western" STYLE="margin-bottom: 0in">Each of the areas +becomes a task:</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task +<B>tMeasure</B> (TMEASURE_INTERVAL*SECOND, -1, +&measureCallback);<BR>Task <B>tWater</B> +(TWATER_INTERVAL*SECOND, RETRIES, &waterCallback);<BR>Task +<B>tDisplay</B> (TDISPLAY_INTERVAL*SECOND, -1, &displayCallback); +<BR></FONT></FONT><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Scheduler +</FONT></FONT><FONT FACE="Courier New, monospace"><FONT SIZE=2><B>taskManager</B></FONT></FONT><FONT FACE="Courier New, monospace"><FONT SIZE=2>;</FONT></FONT><BR><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">Further, once you turn +on the pump, you keep it running for TWATER_INTERVAL interval and +then turn it off. Turning off a pump is also a task which only needs +to run once for every time the pump is turned on:</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task +</FONT></FONT><FONT FACE="Courier New, monospace"><FONT SIZE=2><B>tWaterOff</B></FONT></FONT><FONT FACE="Courier New, monospace"><FONT SIZE=2> +(WATERTIME*SECOND, 1,</FONT></FONT><FONT FACE="Courier New, monospace"> +&waterOffCallback);</FONT><BR><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in">Example of the callback +function:</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void +waterOffCallback() {<BR> motorOff();<BR> +tWater.enableDelayed();<BR>}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>or</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void +waterCallback() {<BR> if (tWater.getIterations()) {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>// +If this is not the last iteration = turn the pump on<BR> +motorOn();<BR> tWaterOff.set(parameters.watertime * SECOND, 1, +&waterOffCallback);<BR> tWaterOff.enableDelayed();<BR> +return;<BR> }</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>// +We could not reach target humidity – something is wrong<BR> +motorOff;<BR> taskManager.disableAll();<BR> tError.enable();<BR>}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Your +sample <B>setup</B>() and <B>loop</B>() (partially) are as follows. </FONT> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>Note: +</B>please note that tWater is <B>not</B> activated during setup(). +It is activated by tMeasure callback once the watering conditions are +met. </FONT> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"> </FONT><FONT FACE="Courier New, monospace">setup()</FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Courier New, monospace"> + ...</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> +<FONT FACE="Courier New, monospace">tWater.setIterations(parameters.retries);<BR> + tWaterOff.setInterval(parameters.watertime * SECOND);<BR><BR><BR> +taskManager.init();<BR> taskManager.addTask(tMeasure);<BR> +taskManager.addTask(tDisplay);<BR> taskManager.addTask(tWater);<BR> +taskManager.addTask(tWaterOff);<BR> <BR> tMeasure.enable();<BR> +tDisplay.enable();<BR><BR> currentHumidity = +measureHumidity();<BR>}<BR><BR><BR>void loop ()<BR>{<BR> +taskManager.execute();<BR>}</FONT><FONT FACE="Times New Roman, serif"><BR></FONT><BR> +</P> +<OL START=2> + <LI><P CLASS="western" STYLE="margin-bottom: 0in">“<FONT FACE="Times New Roman, serif"><B>NATIVE” + SUPPORT FOR FINITE STATE MACHINE</B></FONT></P> +</OL> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Define +“states” as callback function or functions. Each callback +function executes activities specific to a “state” and then +“transitions” to the next state by assigning next callback +function to the task. </FONT> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Transition +from one state to the next is achieved by setting next callback +function at the end of preceding one. </FONT> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>Note: +</B>do not call the next callback function. Let the schedule take +care of that during the next pass. (Thus letting other tasks run). </FONT> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Example: +Blinking LED 2 times a second could be achieved this way</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">Task +tLedBlinker (500, -1, &ledOnCallback);</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">Scheduler +taskManager;</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">void + ledOnCallback() {</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> turnLedOn();</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> tLedBlinker.setCallback(&ledOffCallback);</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">}</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">void + ledOffCallback() {</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> turnLedOff();</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> tLedBlinker.setCallback(&ledOnCallback);</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">}</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">setup() +{</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> taskManager.init();<BR> + taskManager.addTask(tLedBlinker);</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> </FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> tLedBlinker.enable();</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">}</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">loop +() {</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"> taskManager.execute();</FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace">}</FONT><FONT FACE="Times New Roman, serif"><BR></FONT><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Obviously +the example is simple, but gives the idea of how the tasks could be +used to go through states.</FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<OL START=3> + <LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>MULTIPLE + POSSIBLE CALLBACKS FOR TASK</B></FONT></P> +</OL> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">There +may be a need to select an option for callback function based on +certain criteria, or randomly. </FONT> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">You +can achieve that by defining an array of callback function pointers +and selecting one based on the criteria you need. </FONT> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Example: +when a robot detects an obstacle, it may go left, right backwards, +etc. Each of the “directions” or “behaviors” are represented +by a different callback function. </FONT> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">Another +example of using multiple callbacks:</FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">You +may need to “initialize” variables for a particular task.</FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">In +this case, define a tasks with two callbacks:</FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>Task +<B>tWork</B> (T_INTERVAL, -1, &workCallbackInit);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in">…</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void + workCallbackInit() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> // +do your initializationstuff here</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> </FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> // +finally assigne the main callback function </FONT></FONT> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> tWork.setCallback(&workCallback);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void +workCallback() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> // +main callback function</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> …</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">The +task will initialize during first execution pass and switch to +“regular” callback execution starting with second pass. There is +a delay between first and second passes of the task (scheduling +period, if defined). In order to execute the second pass immediately +after initialization first pass, change the above code like this:</FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>void + workCallbackInit() {</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> // +do your initializationstuff here</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> </FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> // +finally assigne the main callback function </FONT></FONT> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> tWork.setCallback(&workCallback);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2> tWork.enable();</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>}</FONT></FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">The +task will run initialization first, then immediately second pass, and +then switch to processing at regular intervals starting with a third +pass. </FONT> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<OL START=3> + <LI><P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>INTERRUP-DRIVEN + EXECUTION SUPPORT </B></FONT> + </P> +</OL> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif">In +case of interrupt-driven program flow, tasks could be scheduled to +run once to request asynchronous execution (request), and then +re-enabled (restarted) again with a different callback function to +process the results. </FONT> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-bottom: 0in"><FONT FACE="Times New Roman, serif"><B>Example</B>: +event driven distance calculation for ultrasonic pulses. EchoPin #6 +triggers pin change interrupts on rising and falling edges to +determine the length of ultrasonic pulse.</FONT></P> +<P CLASS="western" STYLE="margin-bottom: 0in"><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>#include +<DirectIO.h><BR>#include <TaskScheduler.h><BR>#include +<PinChangeInt.h><BR><BR><BR>#define TRIGGERPIN 5<BR>#define +ECHOPIN 6<BR><BR>Output<TRIGGERPIN> +pTrigger;<BR>Input<ECHOPIN> pEcho;<BR><BR>Scheduler +r;<BR><BR>Task tMeasure(1000, -1, &measureCallback);<BR>Task +tDisplay(1000, -1, &displayCallback);<BR>Task tPing(0, 1, +&pingCalcCallback);<BR><BR><BR>volatile bool pulseBusy = +false;<BR>volatile bool pulseTimeout = false;<BR>volatile unsigned +long pulseStart = 0;<BR>volatile unsigned long pulseStop = +0;<BR>volatile unsigned long pingDistance = 0;<BR><BR><BR>void +pingTrigger(unsigned long aTimeout) {<BR> if (pulseBusy) return; // +do not trigger if in the middle of a pulse<BR> if (pEcho == HIGH) +return; // do not trigger if ECHO pin is high<BR> <BR> pulseBusy = +true;<BR> pulseTimeout = false;</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2><BR> + pTrigger = LOW;<BR> delayMicroseconds(4);<BR> pTrigger = HIGH;<BR><BR> + tPing.setInterval (aTimeout);<BR><BR> delayMicroseconds(10);<BR> +pTrigger = LOW; <BR></FONT></FONT><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> +<FONT FACE="Courier New, monospace"><FONT SIZE=2>tPing.restartDelayed(); +// timeout countdown starts now<BR></FONT></FONT><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>// +will start the pulse clock on the rising edge of ECHO pin</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> +<FONT FACE="Courier New, monospace"><FONT SIZE=2>PCintPort::attachInterrupt(ECHOPIN, +&pingStartClock, RISING); <BR>}<BR><BR></FONT></FONT><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>// +Start clock on the <B>rising</B> edge of the ultrasonic pulse<BR>void +pingStartClock() {<BR> pulseStart = micros();<BR> +PCintPort::detachInterrupt(ECHOPIN); // not sure this is necessary<BR> + PCintPort::attachInterrupt(ECHOPIN, &pingStopClock, FALLING); <BR> + tPing.restartDelayed();<BR>}<BR><BR>// Stop clock on the <B>falling</B> +edge of the ultrasonic pulse<BR>void pingStopClock() {<BR> pulseStop += micros();<BR> PcintPort::detachInterrupt(ECHOPIN);</FONT></FONT></P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"> +<FONT FACE="Courier New, monospace"><FONT SIZE=2>pingDistance = +pulseStop - pulseStart;<BR> pulseBusy = false;<BR> tPing.disable(); +// disable timeout<BR>}<BR></FONT></FONT><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>// +Stop clock because of the timeout – the wave did not return<BR>void +pingCalcCallback() {<BR> if (pulseBusy) {<BR> pingStopClock();<BR> + }<BR> pulseTimeout = true;<BR>}<BR><BR><BR><BR>// Initial measure +callback sets the trigger<BR>void measureCallback() {<BR> if +(pulseBusy) { // already measuring, try again<BR> +tMeasure.enable();<BR> return;<BR> }<BR> pingTrigger(30); // 30 +milliseconds or max range of ~5.1 meters<BR> +tMeasure.setCallback(&measureCallbackWait);<BR>}<BR></FONT></FONT><BR> +</P> +<P CLASS="western" STYLE="margin-left: 0.49in; margin-bottom: 0in"><FONT FACE="Courier New, monospace"><FONT SIZE=2>// +Wait for the measurement to <BR>void measureCallbackWait() {<BR> if +(pulseBusy) return;<BR> tMeasure.setCallback(&measureCallback); +<BR>}<BR><BR><BR>bool state = true;<BR><BR>void displayCallback() {<BR> + char d[256];<BR> <BR> unsigned long cm = pingDistance * 17 / 100; +// cm<BR> <BR> snprintf(d, 256, "pulseStart = +%8lu\tpulseStop=%8lu\tdistance, cm=%8lu", pulseStart, pulseStop, +cm);<BR> Serial.println(d);<BR> <BR>}<BR><BR>void setup() {<BR> // +put your setup code here, to run once:<BR> <BR> +Serial.begin(115200);<BR> <BR><BR> pTrigger = LOW;<BR> pEcho = +LOW;<BR> <BR> r.init();<BR> r.addTask(tDisplay);<BR> +r.addTask(tMeasure);<BR> r.addTask(tPing);<BR> <BR> +r.enableAll();<BR> tPing.disable();<BR>}<BR><BR>void loop() {<BR> +// put your main code here, to run repeatedly:<BR> r.execute();<BR>}<BR></FONT></FONT><BR> +</P> +</BODY> +</HTML>
\ No newline at end of file |
