| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271 |
- <html>
- <head>
- <meta http-equiv=Content-Type content="text/html; charset=windows-1252">
- <meta name=Generator content="Microsoft Word 14 (filtered)">
- <style>
- <!--
- /* Font Definitions */
- @font-face
- {font-family:"Liberation Serif";}
- @font-face
- {font-family:OpenSymbol;}
- @font-face
- {font-family:"Liberation Sans";}
- /* Style Definitions */
- p.MsoNormal, li.MsoNormal, div.MsoNormal
- {margin:0in;
- margin-bottom:.0001pt;
- font-size:12.0pt;
- font-family:"Liberation Serif";}
- p.MsoCaption, li.MsoCaption, div.MsoCaption
- {margin-top:6.0pt;
- margin-right:0in;
- margin-bottom:6.0pt;
- margin-left:0in;
- font-size:12.0pt;
- font-family:"Liberation Serif";
- font-style:italic;}
- p.MsoList, li.MsoList, div.MsoList
- {margin-top:0in;
- margin-right:0in;
- margin-bottom:6.0pt;
- margin-left:0in;
- font-size:12.0pt;
- font-family:"Liberation Serif";}
- p.MsoBodyText, li.MsoBodyText, div.MsoBodyText
- {mso-style-link:"Body Text Char";
- margin-top:0in;
- margin-right:0in;
- margin-bottom:6.0pt;
- margin-left:0in;
- font-size:12.0pt;
- font-family:"Liberation Serif";}
- span.BodyTextChar
- {mso-style-name:"Body Text Char";
- mso-style-link:"Body Text";
- font-family:"Liberation Serif";}
- p.Heading, li.Heading, div.Heading
- {mso-style-name:Heading;
- margin-top:12.0pt;
- margin-right:0in;
- margin-bottom:6.0pt;
- margin-left:0in;
- page-break-after:avoid;
- font-size:14.0pt;
- font-family:"Liberation Sans";}
- p.Index, li.Index, div.Index
- {mso-style-name:Index;
- margin:0in;
- margin-bottom:.0001pt;
- font-size:12.0pt;
- font-family:"Liberation Serif";}
- span.WW8Num1z0
- {mso-style-name:WW8Num1z0;}
- span.WW8Num1z1
- {mso-style-name:WW8Num1z1;}
- span.WW8Num1z2
- {mso-style-name:WW8Num1z2;}
- span.WW8Num1z3
- {mso-style-name:WW8Num1z3;}
- span.WW8Num1z4
- {mso-style-name:WW8Num1z4;}
- span.WW8Num1z5
- {mso-style-name:WW8Num1z5;}
- span.WW8Num1z6
- {mso-style-name:WW8Num1z6;}
- span.WW8Num1z7
- {mso-style-name:WW8Num1z7;}
- span.WW8Num1z8
- {mso-style-name:WW8Num1z8;}
- span.WW8Num2z0
- {mso-style-name:WW8Num2z0;}
- span.WW8Num2z1
- {mso-style-name:WW8Num2z1;}
- span.WW8Num2z2
- {mso-style-name:WW8Num2z2;}
- span.WW8Num2z3
- {mso-style-name:WW8Num2z3;}
- span.WW8Num2z4
- {mso-style-name:WW8Num2z4;}
- span.WW8Num2z5
- {mso-style-name:WW8Num2z5;}
- span.WW8Num2z6
- {mso-style-name:WW8Num2z6;}
- span.WW8Num2z7
- {mso-style-name:WW8Num2z7;}
- span.WW8Num2z8
- {mso-style-name:WW8Num2z8;}
- span.WW8Num3z0
- {mso-style-name:WW8Num3z0;
- font-weight:normal;}
- span.WW8Num3z1
- {mso-style-name:WW8Num3z1;}
- span.WW8Num3z2
- {mso-style-name:WW8Num3z2;}
- span.WW8Num3z3
- {mso-style-name:WW8Num3z3;}
- span.WW8Num3z4
- {mso-style-name:WW8Num3z4;}
- span.WW8Num3z5
- {mso-style-name:WW8Num3z5;}
- span.WW8Num3z6
- {mso-style-name:WW8Num3z6;}
- span.WW8Num3z7
- {mso-style-name:WW8Num3z7;}
- span.WW8Num3z8
- {mso-style-name:WW8Num3z8;}
- span.WW8Num4z0
- {mso-style-name:WW8Num4z0;}
- span.WW8Num4z1
- {mso-style-name:WW8Num4z1;}
- span.WW8Num4z2
- {mso-style-name:WW8Num4z2;}
- span.WW8Num4z3
- {mso-style-name:WW8Num4z3;}
- span.WW8Num4z4
- {mso-style-name:WW8Num4z4;}
- span.WW8Num4z5
- {mso-style-name:WW8Num4z5;}
- span.WW8Num4z6
- {mso-style-name:WW8Num4z6;}
- span.WW8Num4z7
- {mso-style-name:WW8Num4z7;}
- span.WW8Num4z8
- {mso-style-name:WW8Num4z8;}
- span.WW8Num5z0
- {mso-style-name:WW8Num5z0;
- font-family:"Times New Roman","serif";
- font-weight:bold;}
- span.WW8Num5z1
- {mso-style-name:WW8Num5z1;}
- span.WW8Num5z2
- {mso-style-name:WW8Num5z2;}
- span.WW8Num5z3
- {mso-style-name:WW8Num5z3;}
- span.WW8Num5z4
- {mso-style-name:WW8Num5z4;}
- span.WW8Num5z5
- {mso-style-name:WW8Num5z5;}
- span.WW8Num5z6
- {mso-style-name:WW8Num5z6;}
- span.WW8Num5z7
- {mso-style-name:WW8Num5z7;}
- span.WW8Num5z8
- {mso-style-name:WW8Num5z8;}
- span.WW8Num6z0
- {mso-style-name:WW8Num6z0;}
- span.WW8Num6z1
- {mso-style-name:WW8Num6z1;}
- span.WW8Num6z2
- {mso-style-name:WW8Num6z2;}
- span.WW8Num6z3
- {mso-style-name:WW8Num6z3;}
- span.WW8Num6z4
- {mso-style-name:WW8Num6z4;}
- span.WW8Num6z5
- {mso-style-name:WW8Num6z5;}
- span.WW8Num6z6
- {mso-style-name:WW8Num6z6;}
- span.WW8Num6z7
- {mso-style-name:WW8Num6z7;}
- span.WW8Num6z8
- {mso-style-name:WW8Num6z8;}
- span.WW8Num7z0
- {mso-style-name:WW8Num7z0;}
- span.WW8Num7z1
- {mso-style-name:WW8Num7z1;}
- span.WW8Num7z2
- {mso-style-name:WW8Num7z2;}
- span.WW8Num7z3
- {mso-style-name:WW8Num7z3;}
- span.WW8Num7z4
- {mso-style-name:WW8Num7z4;}
- span.WW8Num7z5
- {mso-style-name:WW8Num7z5;}
- span.WW8Num7z6
- {mso-style-name:WW8Num7z6;}
- span.WW8Num7z7
- {mso-style-name:WW8Num7z7;}
- span.WW8Num7z8
- {mso-style-name:WW8Num7z8;}
- span.WW-DefaultParagraphFont
- {mso-style-name:"WW-Default Paragraph Font";}
- span.Absatz-Standardschriftart
- {mso-style-name:Absatz-Standardschriftart;}
- span.NumberingSymbols
- {mso-style-name:"Numbering Symbols";}
- span.Bullets
- {mso-style-name:Bullets;
- font-family:OpenSymbol;}
- .MsoChpDefault
- {font-size:10.0pt;}
- @page WordSection1
- {size:8.5in 11.0in;
- margin:56.7pt 56.7pt 56.7pt 56.7pt;}
- div.WordSection1
- {page:WordSection1;}
- /* List Definitions */
- ol
- {margin-bottom:0in;}
- ul
- {margin-bottom:0in;}
- -->
- </style>
- </head>
- <body bgcolor=white lang=EN-US style='line-break:strict'>
- <div class=WordSection1>
- <p class=MsoNormal><b>Task Scheduler – cooperative multitasking for Arduino microcontrollers</b></p>
- <p class=MsoNormal><b>Version 1.51: 2015-09-20</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal><b>REQUIREMENT</b>:</p>
- <p class=MsoNormal>A lightweight implementation of the task scheduling
- supporting:</p>
- <ol style='margin-top:0in' start=1 type=1>
- <li class=MsoNormal>execution period (n times per second)</li>
- <li class=MsoNormal>number of iterations (n times)</li>
- <li class=MsoNormal>execution of tasks in predefined sequence</li>
- <li class=MsoNormal>dynamic change of the execution parameters for both tasks
- and execution schedule</li>
- <li class=MsoNormal>power saving via entering IDLE sleep mode if no tasks are
- scheduled to run</li>
- </ol>
- <p class=MsoNormal> </p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal><b>IDEA</b>:</p>
- <p class=MsoNormal>“Task” is a container concept that links together:</p>
- <ol style='margin-top:0in' start=1 type=1>
- <li class=MsoNormal>Execution interval</li>
- <li class=MsoNormal>Number of execution iterations</li>
- <li class=MsoNormal>A piece of code performing the task activities (callback
- function)</li>
- </ol>
- <p class=MsoNormal> </p>
- <p class=MsoNormal>Tasks are linked into execution chains, which are processed
- by the “Scheduler” in the order they are linked.</p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal>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=MsoNormal> </p>
- <p class=MsoNormal>“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=MsoNormal> </p>
- <p class=MsoNormal>If compiled with <span style='font-family:"Courier New"'>_TASK_SLEEP_ON_IDLE_RUN</span>
- 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=MsoNormal> </p>
- <p class=MsoNormal><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=MsoNormal> </p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal><b>COMPILE PARAMETERS:</b></p>
- <p class=MsoNormal>This library could be compiled with several options. </p>
- <p class=MsoNormal>These parameters must be defined before inclusion of the
- library header file into the sketch.</p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal>#define <b>_TASK_TIMECRITICAL</b></p>
- <p class=MsoNormal>...will compile the library with time critical tracking
- option enabled.</p>
- <p class=MsoNormal>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=MsoNormal>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=MsoNormal> </p>
- <p class=MsoNormal>#define <b>_TASK_SLEEP_ON_IDLE_RUN</b></p>
- <p class=MsoNormal>...will compile the library with the <b>sleep</b> option
- enabled (AVR boards only).</p>
- <p class=MsoNormal>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=MsoNormal> </p>
- <p class=MsoNormal><b>NOTE: above parameters are DISABLED by default, and need
- to be explicitly enabled.</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal><b>API DOCUMENTATION:</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal><b>TASKS:</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal>CREATION:</p>
- <p class=MsoNormal><b>Task();</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>Default constructor. </p>
- <p class=MsoNormal style='margin-left:35.45pt'>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=MsoNormal style='margin-left:35.45pt'>All tasks are created <b>disabled</b>
- by default.</p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='page-break-after:avoid'><b>Task(unsigned long aInterval,
- long aIterations, void (*aCallback)(), Scheduler* aScheduler, bool aEnable);</b></p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>Constructor with parameters. </p>
- <p class=MsoNormal style='margin-left:35.45pt'>Creates a task that is scheduled
- to run every <aInterval> milliseconds, <aIterations> times,
- executing <aCallback> function on every pass. </p>
- <p class=MsoNormal style='margin-left:71.45pt;text-indent:-.25in'>1.<span
- style='font-size:7.0pt;font-family:"Times New Roman","serif"'>
- </span>aInterval is in milliseconds</p>
- <p class=MsoNormal style='margin-left:71.45pt;text-indent:-.25in'>2.<span
- style='font-size:7.0pt;font-family:"Times New Roman","serif"'>
- </span>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>
- <p class=MsoNormal style='margin-left:71.45pt;text-indent:-.25in'>3.<span
- style='font-size:7.0pt;font-family:"Times New Roman","serif"'>
- </span>aCallback is a pointer to a void function without parameters</p>
- <p class=MsoNormal style='margin-left:71.45pt;text-indent:-.25in'>4.<span
- style='font-size:7.0pt;font-family:"Times New Roman","serif"'>
- </span>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>
- <p class=MsoNormal style='margin-left:71.45pt;text-indent:-.25in'>5.<span
- style='font-size:7.0pt;font-family:"Times New Roman","serif"'>
- </span>aEnable – <b>optional</b>. Value of <b>true </b>will create task
- enabled. <b>Default = false</b></p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>All tasks are created <b>disabled</b>
- by default (unless aEnable = true). You have to explicitly enable the task for
- execution.</p>
- <p class=MsoNormal style='margin-left:35.45pt'>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=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal><b>INFORMATION</b></p>
- <p class=MsoNormal style='margin-left:35.45pt'>The following 3 “getter”
- functions return task status (enabled/disabled), execution interval in
- milliseconds, number of <b><i>remaining</i></b> iterations. </p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal style='margin-left:35.45pt'><b>bool isEnabled() </b></p>
- <p class=MsoNormal style='margin-left:35.45pt'><b>unsigned long getInterval()</b></p>
- <p class=MsoNormal style='margin-left:35.45pt'><b>long getIterations() </b></p>
- <p class=MsoNormal style='margin-left:35.45pt'><b> </b></p>
- <p class=MsoNormal><b>long getOverrun()</b></p>
- <p class=MsoNormal style='margin-left:35.45pt'>If library is compiled with <span
- style='font-family:"Courier New"'>_TASK_TIMECRITICAL</span> 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=MsoNormal style='margin-left:35.45pt'>
- <b>next execution time = previous execution time + task execution interval</b></p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>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 <b><i>overrun</i></b>. <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=MsoNormal style='margin-left:35.45pt'>Positive value indicate number
- of milliseconds of slack this task has for execution purposes. </p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal><b>bool isFirstIteration()</b></p>
- <p class=MsoNormal><b>bool isLastIteration()</b></p>
- <p class=MsoNormal style='margin-left:35.45pt'>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=MsoNormal> </p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='page-break-after:avoid'><b>CONTROL:</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal><b>void enable();</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>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=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal><b>void delay();</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>Schedules the task for execution
- after a delay (aInterval), but does not change the enabled/disabled status of
- the task. </p>
- <p class=MsoNormal style='margin-left:35.45pt'><b> </b></p>
- <p class=MsoNormal><b>void enableDelayed();</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>Enables the task, and schedules
- it for execution after a delay (aInterval). </p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal><b>void enableDelayed (unsigned long aDelay);</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>Enables the task, and schedules
- it for execution after a specific delay (aDelay, which maybe different from aInterval).
- </p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal><b>void restart();</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>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=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal><b>void restartDelayed (unsigned long aDelay);</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>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=MsoNormal><b> </b></p>
- <p class=MsoNormal><b>void disable();</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>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=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal><b>void disableOnLastIteration (bool aBool);</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>Controls iterative task behavior
- on the last iteration. If <b>aBool</b> is <b>true</b> task will be disabled
- after last iteration. If <b>aBool</b> is <b>false</b>, task will remain active
- (but not invoked until new number of iterations is set)</p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal><b>void set(unsigned long aInterval, long aIterations, void (*aCallback)());</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>Allows dynamic control of all
- task execution parameters in one function call. If task being modified is
- active, it will be scheduled for execution immediately. </p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal>Next three “setter” functions allow changes of individual
- task execution control parameters. </p>
- <p class=MsoNormal style='margin-left:35.45pt'><b>void setInterval (unsigned
- long aInterval) </b></p>
- <p class=MsoNormal style='margin-left:35.45pt'><b>void setIterations (long aIterations)
- </b></p>
- <p class=MsoNormal style='margin-left:35.45pt'><b>void setCallback (void
- (*aCallback)()) </b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal><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. If task being modified is active, <b>setIterations </b>will
- make the task be scheduled for execution immediately.</p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal><b> </b></p>
- <p class=MsoNormal><b>TASK SCHEDULER:</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal><b>CREATION:</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='margin-bottom:12.0pt'><b>Scheduler()</b></p>
- <p class=MsoNormal style='margin-left:35.45pt'>Default constructor. </p>
- <p class=MsoNormal style='margin-left:35.45pt'>Takes no parameters. Creates
- task scheduler with default parameters and an empty task queue. </p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal><b>void init()</b></p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>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=MsoNormal style='margin-left:35.45pt'><b>Note: </b>be default (if
- compiled with <span style='font-family:"Courier New"'>_TASK_TIMECRITICAL</span>
- 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=MsoNormal><br>
- <b>void addTask(Task& aTask)</b></p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>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=MsoNormal style='margin-left:35.45pt'><b>Note: </b>Currently, changing
- the execution dynamically is not supported. </p>
- <p class=MsoNormal style='margin-left:35.45pt'>If you need to reorder the queue
- – initialize the scheduler and re-add the tasks in a different order. </p>
- <p class=MsoNormal><br>
- <b>void deleteTask(Task& aTask)</b></p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>Deletes task aTask from the
- execution chain. The chain of remaining tasks is linked together (i.e</p>
- <p class=MsoNormal style='margin-left:35.45pt'>if original task chain is 1 →
- 2 → 3 → 4, deleting 3 will result in 1 → 2 → 4).</p>
- <p class=MsoNormal style='margin-left:35.45pt'><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=MsoNormal style='margin-left:35.45pt'>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=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal><b>void allowSleep(bool aState) </b></p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>Available in API only if compiled
- with <span style='font-family:"Courier New"'>_TASK_TIMECRITICAL</span> 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=MsoNormal style='margin-left:35.45pt'>The <b>default</b> behavior of
- scheduler upon creation is to allow sleep mode. </p>
- <p class=MsoNormal><br>
- <b>void enableAll()</b></p>
- <p class=MsoNormal><b>void disableAll()</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>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=MsoNormal style='margin-bottom:12.0pt'><br>
- <b>Task& currentTask()</b></p>
- <p class=MsoNormal style='margin-left:35.45pt'>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=MsoNormal><br>
- <b>void execute()</b></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='margin-left:35.45pt'>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=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal style='margin-left:35.45pt'> </p>
- <p class=MsoNormal style='page-break-after:avoid'><b>IMPLEMENTATION SCENARIOS
- AND IDEAS:</b></p>
- <p class=MsoNormal> </p>
- <ol style='margin-top:0in' start=1 type=1>
- <li class=MsoNormal><b>EVENT DRIVEN PROGRAMMING</b></li>
- </ol>
- <p class=MsoNormal> </p>
- <p class=MsoNormal>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=MsoNormal> </p>
- <p class=MsoNormal>Example: </p>
- <p class=MsoNormal>In a plant watering system you need to measure soil
- humidity, control pump and display the results</p>
- <p class=MsoNormal>Each of the areas becomes a task:</p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
- margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>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); </span></p>
- <p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
- margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>Scheduler
- <b>taskManager</b>;</span></p>
- <p class=MsoNormal>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=MsoNormal> </p>
- <p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
- margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>Task
- <b>tWaterOff</b> (WATERTIME*SECOND, 1,</span><span style='font-family:"Courier New"'>
- &waterOffCallback);</span></p>
- <p class=MsoNormal>Example of the callback function:</p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>void waterOffCallback() {<br>
- motorOff();<br>
- tWater.enableDelayed();<br>
- }</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'> </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>or</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'> </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>void waterCallback() {<br>
- if (tWater.getIterations()) {</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>// 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>
- }</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>// We could not reach target humidity – something is
- wrong<br>
- motorOff;<br>
- taskManager.disableAll();<br>
- tError.enable();<br>
- }</span></p>
- <p class=MsoNormal><span style='font-family:"Courier New"'> </span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>Your
- sample <b>setup</b>() and <b>loop</b>() (partially) are as follows. </span></p>
- <p class=MsoNormal><b><span style='font-family:"Times New Roman","serif"'>Note:
- </span></b><span style='font-family:"Times New Roman","serif"'>please note that
- tWater is <b>not</b> activated during setup(). It is activated by tMeasure
- callback once the watering conditions are met. </span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>
- </span><span style='font-family:"Courier New"'>setup()</span></p>
- <p class=MsoNormal><span style='font-family:"Courier New"'>
- ...</span></p>
- <p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
- margin-left:35.45pt'><span style='font-family:"Courier New"'>
- 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>
- }</span></p>
- <p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
- margin-left:35.45pt'> </p>
- <ol style='margin-top:0in' start=2 type=1>
- <li class=MsoNormal><b><span style='font-family:"Times New Roman","serif"'>“NATIVE”
- SUPPORT FOR FINITE STATE MACHINE</span></b></li>
- </ol>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal><span style='font-family:"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. </span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>Transition
- from one state to the next is achieved by setting next callback function at the
- end of preceding one. </span></p>
- <p class=MsoNormal><b><span style='font-family:"Times New Roman","serif"'>Note:
- </span></b><span style='font-family:"Times New Roman","serif"'>do not call the
- next callback function. Let the schedule take care of that during the next
- pass. (Thus letting other tasks run). </span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>Example:
- Blinking LED 2 times a second could be achieved this way</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>Task
- tLedBlinker (500, -1, &ledOnCallback);</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>Scheduler
- taskManager;</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'> </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>void
- ledOnCallback() {</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
- turnLedOn();</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
- tLedBlinker.setCallback(&ledOffCallback);</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>}</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'> </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>void
- ledOffCallback() {</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
- turnLedOff();</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
- tLedBlinker.setCallback(&ledOnCallback);</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>}</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'> </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>setup()
- {</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
- taskManager.init();<br>
- taskManager.addTask(tLedBlinker);</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
- </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
- tLedBlinker.enable();</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>}</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'> </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>loop
- () {</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Courier New"'>
- taskManager.execute();</span></p>
- <p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
- margin-left:35.45pt'><span style='font-family:"Courier New"'>}</span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>Obviously
- the example is simple, but gives the idea of how the tasks could be used to go
- through states.</span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <ol style='margin-top:0in' start=3 type=1>
- <li class=MsoNormal><b><span style='font-family:"Times New Roman","serif"'>MULTIPLE
- POSSIBLE CALLBACKS FOR TASK</span></b></li>
- </ol>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>There may
- be a need to select an option for callback function based on certain criteria,
- or randomly. </span></p>
- <p class=MsoNormal><span style='font-family:"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. </span></p>
- <p class=MsoNormal><span style='font-family:"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. </span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>Another
- example of using multiple callbacks:</span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>You may
- need to “initialize” variables for a particular task.</span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'>In this
- case, define a tasks with two callbacks:</span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>Task <b>tWork</b> (T_INTERVAL, -1,
- &workCallbackInit);</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>…</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>void workCallbackInit() {</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'> // do your
- initializationstuff here</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'> </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'> // finally assigne
- the main callback function </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>
- tWork.setCallback(&workCallback);</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>}</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>void workCallback() {</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'> // main callback
- function</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'> …</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>}</span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal><span style='font-family:"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:</span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>void workCallbackInit() {</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'> // do your
- initializationstuff here</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'> </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'> // finally assigne the
- main callback function </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>
- tWork.setCallback(&workCallback);</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'> tWork.enable();</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>}</span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal><span style='font-family:"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. </span></p>
- <p class=MsoNormal> </p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <ol style='margin-top:0in' start=4 type=1>
- <li class=MsoNormal><b><span style='font-family:"Times New Roman","serif"'>INTERRUP-DRIVEN
- EXECUTION SUPPORT </span></b></li>
- </ol>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal><span style='font-family:"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. </span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal><b><span style='font-family:"Times New Roman","serif"'>Example</span></b><span
- style='font-family:"Times New Roman","serif"'>: 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.</span></p>
- <p class=MsoNormal><span style='font-family:"Times New Roman","serif"'> </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>#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;</span></p>
- <p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
- margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'><br>
- pTrigger = LOW;<br>
- delayMicroseconds(4);<br>
- pTrigger = HIGH;<br>
- <br>
- tPing.setInterval (aTimeout);<br>
- <br>
- delayMicroseconds(10);<br>
- pTrigger = LOW; </span></p>
- <p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
- margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>
- tPing.restartDelayed(); // timeout countdown starts now</span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>// will start the pulse clock on the rising edge of
- ECHO pin</span></p>
- <p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
- margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>
- PCintPort::attachInterrupt(ECHOPIN, &pingStartClock, RISING); <br>
- }<br>
- <br>
- </span></p>
- <p class=MsoNormal style='margin-left:35.45pt'><span style='font-size:10.0pt;
- font-family:"Courier New"'>// 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);</span></p>
- <p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
- margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>
- pingDistance = pulseStop - pulseStart;<br>
- pulseBusy = false;<br>
- tPing.disable(); // disable timeout<br>
- }</span></p>
- <p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
- margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>//
- 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>
- }</span></p>
- <p class=MsoNormal style='margin-top:0in;margin-right:0in;margin-bottom:12.0pt;
- margin-left:35.45pt'><span style='font-size:10.0pt;font-family:"Courier New"'>//
- 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>
- }</span></p>
- </div>
- </body>
- </html>
|