| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841 |
- <!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>
|