CooperativeMultitasking.html 191 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775
  1. <!DOCTYPE html>
  2. <html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
  3. <head>
  4. <meta charset="utf-8" />
  5. <meta name="generator" content="pandoc" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  7. <meta name="author" content="Pat Beirne" />
  8. <title>Cooperative Multitasking</title>
  9. <style>
  10. code{white-space: pre-wrap;}
  11. span.smallcaps{font-variant: small-caps;}
  12. div.columns{display: flex; gap: min(4vw, 1.5em);}
  13. div.column{flex: auto; overflow-x: auto;}
  14. div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
  15. /* The extra [class] is a hack that increases specificity enough to
  16. override a similar rule in reveal.js */
  17. ul.task-list[class]{list-style: none;}
  18. ul.task-list li input[type="checkbox"] {
  19. font-size: inherit;
  20. width: 0.8em;
  21. margin: 0 0.8em 0.2em -1.6em;
  22. vertical-align: middle;
  23. }
  24. .display.math{display: block; text-align: center; margin: 0.5rem auto;}
  25. /* CSS for syntax highlighting */
  26. pre > code.sourceCode { white-space: pre; position: relative; }
  27. pre > code.sourceCode > span { line-height: 1.25; }
  28. pre > code.sourceCode > span:empty { height: 1.2em; }
  29. .sourceCode { overflow: visible; }
  30. code.sourceCode > span { color: inherit; text-decoration: inherit; }
  31. div.sourceCode { margin: 1em 0; }
  32. pre.sourceCode { margin: 0; }
  33. @media screen {
  34. div.sourceCode { overflow: auto; }
  35. }
  36. @media print {
  37. pre > code.sourceCode { white-space: pre-wrap; }
  38. pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
  39. }
  40. pre.numberSource code
  41. { counter-reset: source-line 0; }
  42. pre.numberSource code > span
  43. { position: relative; left: -4em; counter-increment: source-line; }
  44. pre.numberSource code > span > a:first-child::before
  45. { content: counter(source-line);
  46. position: relative; left: -1em; text-align: right; vertical-align: baseline;
  47. border: none; display: inline-block;
  48. -webkit-touch-callout: none; -webkit-user-select: none;
  49. -khtml-user-select: none; -moz-user-select: none;
  50. -ms-user-select: none; user-select: none;
  51. padding: 0 4px; width: 4em;
  52. color: #aaaaaa;
  53. }
  54. pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
  55. div.sourceCode
  56. { }
  57. @media screen {
  58. pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
  59. }
  60. code span.al { color: #ff0000; font-weight: bold; } /* Alert */
  61. code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
  62. code span.at { color: #7d9029; } /* Attribute */
  63. code span.bn { color: #40a070; } /* BaseN */
  64. code span.bu { color: #008000; } /* BuiltIn */
  65. code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
  66. code span.ch { color: #4070a0; } /* Char */
  67. code span.cn { color: #880000; } /* Constant */
  68. code span.co { color: #60a0b0; font-style: italic; } /* Comment */
  69. code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
  70. code span.do { color: #ba2121; font-style: italic; } /* Documentation */
  71. code span.dt { color: #902000; } /* DataType */
  72. code span.dv { color: #40a070; } /* DecVal */
  73. code span.er { color: #ff0000; font-weight: bold; } /* Error */
  74. code span.ex { } /* Extension */
  75. code span.fl { color: #40a070; } /* Float */
  76. code span.fu { color: #06287e; } /* Function */
  77. code span.im { color: #008000; font-weight: bold; } /* Import */
  78. code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
  79. code span.kw { color: #007020; font-weight: bold; } /* Keyword */
  80. code span.op { color: #666666; } /* Operator */
  81. code span.ot { color: #007020; } /* Other */
  82. code span.pp { color: #bc7a00; } /* Preprocessor */
  83. code span.sc { color: #4070a0; } /* SpecialChar */
  84. code span.ss { color: #bb6688; } /* SpecialString */
  85. code span.st { color: #4070a0; } /* String */
  86. code span.va { color: #19177c; } /* Variable */
  87. code span.vs { color: #4070a0; } /* VerbatimString */
  88. code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
  89. </style>
  90. <link rel="stylesheet" href="pandoc.css" />
  91. </head>
  92. <body>
  93. <header id="title-block-header">
  94. <h1 class="title">Cooperative Multitasking</h1>
  95. <p class="author">Pat Beirne</p>
  96. <p class="date">2025/01/15</p>
  97. </header>
  98. <nav id="TOC" role="doc-toc">
  99. <ul>
  100. <li><a href="#part-1-cooperative-multitasking"
  101. id="toc-part-1-cooperative-multitasking">Part 1: Cooperative
  102. Multitasking</a>
  103. <ul>
  104. <li><a href="#intro" id="toc-intro">Intro</a>
  105. <ul>
  106. <li><a href="#abstract" id="toc-abstract">Abstract</a></li>
  107. <li><a href="#audience" id="toc-audience">Audience</a></li>
  108. </ul></li>
  109. <li><a href="#the-problem" id="toc-the-problem">The Problem</a></li>
  110. <li><a href="#first-page" id="toc-first-page">First Page</a></li>
  111. <li><a href="#interrupts" id="toc-interrupts">Interrupts</a></li>
  112. <li><a href="#events" id="toc-events">Events</a></li>
  113. <li><a href="#newevent" id="toc-newevent">newEvent()</a></li>
  114. <li><a href="#dispatch" id="toc-dispatch">Dispatch</a></li>
  115. <li><a href="#tasks" id="toc-tasks">Tasks</a></li>
  116. <li><a href="#state-machine" id="toc-state-machine">State
  117. Machine</a></li>
  118. <li><a href="#another-state-machine"
  119. id="toc-another-state-machine">Another State Machine</a></li>
  120. <li><a href="#dispatcher-details" id="toc-dispatcher-details">Dispatcher
  121. Details</a></li>
  122. <li><a href="#final-implementation" id="toc-final-implementation">Final
  123. Implementation</a></li>
  124. </ul></li>
  125. <li><a href="#part-2" id="toc-part-2">Part 2</a>
  126. <ul>
  127. <li><a href="#variations" id="toc-variations">Variations</a></li>
  128. <li><a href="#working-with-arduino"
  129. id="toc-working-with-arduino">Working with Arduino</a></li>
  130. <li><a href="#tasks-1" id="toc-tasks-1">Tasks</a></li>
  131. <li><a href="#state-machine-examples"
  132. id="toc-state-machine-examples">State Machine Examples</a>
  133. <ul>
  134. <li><a href="#car-window" id="toc-car-window">Car Window</a></li>
  135. <li><a href="#fridge-door" id="toc-fridge-door">Fridge Door</a></li>
  136. <li><a href="#door-opener" id="toc-door-opener">Door Opener</a></li>
  137. <li><a href="#beer-vat" id="toc-beer-vat">Beer Vat</a></li>
  138. <li><a href="#vending-machine" id="toc-vending-machine">Vending
  139. Machine</a></li>
  140. </ul></li>
  141. <li><a href="#events-1" id="toc-events-1">Events</a></li>
  142. <li><a href="#timers" id="toc-timers">Timers</a></li>
  143. <li><a href="#real-code" id="toc-real-code">Real Code</a></li>
  144. <li><a href="#substates" id="toc-substates">Substates</a></li>
  145. <li><a href="#state-machine-initialization"
  146. id="toc-state-machine-initialization">State Machine
  147. Initialization</a></li>
  148. <li><a href="#messages" id="toc-messages">Messages</a>
  149. <ul>
  150. <li><a href="#postmessage" id="toc-postmessage">PostMessage</a></li>
  151. <li><a href="#sendmessage" id="toc-sendmessage">SendMessage</a></li>
  152. <li><a href="#usage" id="toc-usage">Usage</a></li>
  153. </ul></li>
  154. <li><a href="#ideas-for-tasks" id="toc-ideas-for-tasks">Ideas for
  155. Tasks</a></li>
  156. <li><a href="#more-state-machines" id="toc-more-state-machines">More
  157. State Machines</a>
  158. <ul>
  159. <li><a href="#radio-tuner" id="toc-radio-tuner">Radio Tuner</a></li>
  160. </ul></li>
  161. </ul></li>
  162. </ul>
  163. </nav>
  164. <h1 id="part-1-cooperative-multitasking">Part 1: Cooperative
  165. Multitasking</h1>
  166. <!-- ## Introduction -->
  167. <p>Small microcontrollers are often required to handle several tasks,
  168. sometimes with overlapping phases. This paper will lead you through the
  169. creation of a small <strong><em>operating system</em></strong> which can
  170. be implemented on a tiny microcontroller, without the fancy time-slicing
  171. that is offered by sophisticated operating systems like <a
  172. href="https://linux.org">Linux</a> and <a
  173. href="https://freertos.org">FreeRTos</a>.</p>
  174. <p>The core of <em>this</em> technique is covered in <a
  175. href="#part-1-cooperative-multitasking">Part 1</a> of this paper. If you
  176. just want to see how it all comes together, jump to <a
  177. href="#final-implementation">Final Implementaion</a>.</p>
  178. <p><a href="#part-2">Part 2</a> contains enhancements and variations,
  179. probably useful reading if you decide to adopt this programming
  180. technique in your projects.</p>
  181. <h2 id="intro">Intro</h2>
  182. <h3 id="abstract">Abstract</h3>
  183. <p>This paper will take you through the creation of a tiny <em>operating
  184. system</em> that can be implemented on a small microcontroller.</p>
  185. <h3 id="audience">Audience</h3>
  186. <p>These techniques can be applied by anyone with experience in
  187. <strong><em>C</em></strong>, <strong><em>Python</em></strong> or any
  188. modern computer language. It helps to have a passing knowledge of how to
  189. connect a transducer (button, LED, buzzer, etc) to a
  190. microcontroller.</p>
  191. <blockquote>
  192. <p>The <strong><em>Reality Check</em></strong> dropdowns in this article
  193. provide extra, often practical supplementary reading.</p>
  194. </blockquote>
  195. <details>
  196. <summary>
  197. Reality Check
  198. </summary>
  199. <p>The technique described here is also called <strong><em>event driven
  200. programming</em></strong>.</p>
  201. <p>This technique was used in the original Window (1995), including some
  202. of the system calls:
  203. <code>sendMessage(), postMessage() and setTimer()</code>.</p>
  204. <p>This event-driven technique is applicable to a whole host of small
  205. microcontrollers, including</p>
  206. <ul>
  207. <li>MSP430</li>
  208. <li>Cortex M0, M0+ (SAM, STM32, PY32, Cypress, Kinetis, HT32, XMC,
  209. LPC81x)</li>
  210. <li>AtMega, AtTiny</li>
  211. <li>8051 (SiliconLabs, Nuvoton, HT85)</li>
  212. <li>RL78 (Renesas)</li>
  213. <li>Pic 12/14/16</li>
  214. <li>Risc (ch32v)</li>
  215. <li>STM8</li>
  216. </ul>
  217. <p><em>Some of the really tiny ones don’t have enough stack space to
  218. implement these techniques (Puolop PB150, Padauk PxS15x, Bojuxing BJ8P,
  219. Yspring MDT1x, EastSoft HR7P, Holtek Ht68.)</em></p>
  220. <img src="blb.jpg" alt="Here" /> is a typical board hosting 12 buttons,
  221. 12 RGB LEDs, all hosted by an STM32. Every light and button can be
  222. controlled separately and simultaneously, using the technique described
  223. in this paper.
  224. </details>
  225. <h2 id="the-problem">The Problem</h2>
  226. <p>Let’s suppose we want to flash an LED at 1 flash/2 sec, and
  227. independently, respond to a push button by operating a different LED for
  228. 1.5 seconds. Both operations must operate separately. How do we
  229. structure the code for the microcontroller to make this happen?</p>
  230. <h2 id="first-page">First Page</h2>
  231. <p>Let’s look an a pseudocode overview of what we want to do:</p>
  232. <div class="sourceCode" id="cb1"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> initialize<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
  233. <span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> setup_hardware<span class="op">();</span></span>
  234. <span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> setup_interrupts<span class="op">();</span></span>
  235. <span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  236. <span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
  237. <span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>INTERRUPT <span class="dt">void</span> irq<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
  238. <span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a> create_event<span class="op">();</span></span>
  239. <span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a> acknowledge_interrupt<span class="op">();</span></span>
  240. <span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  241. <span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a></span>
  242. <span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> main<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
  243. <span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a> initialize<span class="op">();</span></span>
  244. <span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a></span>
  245. <span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span> <span class="op">(</span><span class="dv">1</span><span class="op">)</span> <span class="op">{</span></span>
  246. <span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event<span class="op">)</span> <span class="op">{</span></span>
  247. <span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a> flashLedTask<span class="op">(</span>event<span class="op">);</span></span>
  248. <span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a> respondToButtonTask<span class="op">(</span>event<span class="op">);</span></span>
  249. <span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  250. <span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  251. <span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  252. <p>That’s about it.</p>
  253. <p>Of course, we will need to write the code for
  254. <code>setup_hardware()</code> and <code>setup_interrupts()</code>. And
  255. <code>flashLedTask()</code> and <code>respondToButtonTask()</code>. And
  256. create the <em>magic</em> that allows <code>event</code> information to
  257. flow. Don’t worry, it will all be laid out in the following pages.</p>
  258. <p>If you’re concerned with complexity, feel free to jump ahead to the
  259. <a href="#final-implementation">final implementation</a> page to see
  260. real, tested, code.</p>
  261. <p>Between here and there, I’ll walk you step-by-step through building
  262. the structure and implementation.</p>
  263. <p>This paper continues after that though, to show you how to expand
  264. upon a build as the project-definition changes. There are also several
  265. examples of state machines, and some discussion of practical matters,
  266. refactoring and project structure.</p>
  267. <h2 id="interrupts">Interrupts</h2>
  268. <p>In order to have a responsive system, it would make sense to use the
  269. <em>interrupt</em> capabilities of these small micrcontrollers.</p>
  270. <p>In the task described, we need to respond to a button press. So let’s
  271. connect the button to an input pin and enable it to repsond to a button
  272. press with interrupt code.</p>
  273. <p>We also need to keep track of time…..so let’s hook up a system timer
  274. to another interrupt.</p>
  275. <p>Each interrupt causes the execution of <em>interrupt handler</em>
  276. code. For this project, it might look somthing like this:</p>
  277. <div class="sourceCode" id="cb2"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span>EVT_NONE<span class="op">,</span> EVT_TICK<span class="op">,</span> EVT_BUTTON<span class="op">};</span></span>
  278. <span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
  279. <span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>INTERRUPT timer_isr<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
  280. <span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> newEvent<span class="op">(</span>EVT_TICK<span class="op">);</span></span>
  281. <span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  282. <span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a></span>
  283. <span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>INTERRUPT button_isr<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
  284. <span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a> newEvent<span class="op">(</span>EVT_BUTTON<span class="op">);</span> <span class="co">// see notes about button bounce and acknowledgement</span></span>
  285. <span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  286. <p>The interrupt handlers are both very simple. They just create a
  287. unique <em>event</em> and let the system know about it. Next, let’s talk
  288. about <em>events</em>.</p>
  289. <details>
  290. <summary>
  291. Reality check
  292. </summary>
  293. <p>In some microcontrollers, interrupts must be <em>acknowledged</em>.
  294. Sometimes that means setting a hardware flag to indicate to the device
  295. that you’re ready for another interrupt of the same type. And in some
  296. cases, there’s no need to ack. Specifically, the SYS_TICK interrupt in
  297. the ARM Cortex processors does <em>not</em> need an ack, so the above
  298. code example for <code>timer_isr()</code> is complete.</p>
  299. <p>When a pushbutton or switch is connected to a microcontroller, the
  300. first bit of activity will cause the interrupt and execute the
  301. <code>button_isr()</code> code. However, real buttons produce about
  302. 5msec of <em>bounce</em> and this will cause subsequent interrupts
  303. unless they are somehow filtered out. There are lots of ways to handle
  304. <em>bounce</em>, and I’ll let you read about that
  305. [elsewhere]](#debouncing). Most techniques boil down to either ignoring
  306. subsequent interrupts (from the same button) for about 5 msec, or
  307. disabling that specific interrupt until the 5msec has passed.</p>
  308. <p>As a general rule, <em>input</em> pins should be observed either by
  309. interrupt service routine (ISR), or scanned periodically by the timer
  310. ISR. <em>Outputs</em> should be controlled in the task code, which we’ll
  311. see below.</p>
  312. </details>
  313. <h2 id="events">Events</h2>
  314. <p>An <em>event</em> in this context is a small bit of information that
  315. appears asynchronously in the system. Implemented, it can be a
  316. <em>byte</em>, or an <em>int</em> or an even larger structure. But in
  317. these small microcontrollers, let’s use a <em>byte</em>.</p>
  318. <div class="sourceCode" id="cb3"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="dt">volatile</span> uint8 event<span class="op">;</span></span></code></pre></div>
  319. <p>These <em>events</em> will be created in interrupt level of the code,
  320. and processed at the main level. We use the <code>event</code> object to
  321. send information between these levels, so we have to mark it <a
  322. href="https://en.wikipedia.org/wiki/Volatile_(computer_programming)"><code>volatile</code></a>.</p>
  323. <p>In this paper, the word <em>message</em> and <em>event</em> are
  324. equivalent. <em>Message</em> has the sense of “a bit of communication
  325. from another part of the program” and <em>event</em> has the sense of
  326. “something external just happened”. At this point in the design, they
  327. both mean the same thing.</p>
  328. <p>By convention, let’s use <em>zero</em> to indicate the absence of an
  329. event/message, and <em>non-zero</em> to represent an event/message.</p>
  330. <div class="sourceCode" id="cb4"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="dt">volatile</span> uint8 event<span class="op">;</span></span>
  331. <span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span>EVT_NONE<span class="op">,</span> EVT_TICK<span class="op">,</span> EVT_BUTTON<span class="op">};</span> <span class="co">// 0,1,2</span></span></code></pre></div>
  332. <details>
  333. <summary>
  334. Reality check
  335. </summary>
  336. <hr>
  337. For this project, let’s suppose the timer ticks happen every 10ms (100
  338. per second).
  339. <hr>
  340. </details>
  341. <p>So now we start to get an idea of what kind of information the
  342. <em>interrupt handler</em> code generates. Now let’s look at how that
  343. information gets sent to the rest of the code:
  344. <code>newEvent()</code>.</p>
  345. <h2 id="newevent">newEvent()</h2>
  346. <p>Here’s a block diagram of the message flow <img
  347. src="dispatch1.jpg" /></p>
  348. <p>How do we send the information (events/messages) from the interrupt
  349. service routine to the <code>main()</code> code? We used shared
  350. memory.</p>
  351. <p>One way would be to have a global <code>volatile uint8</code>
  352. location into which we drop the <em>event</em> information. But having
  353. only one socket for that would be a bit naive; what happens if a timer
  354. tick and a button press happen very close in time? What happens if the
  355. timer tick events start to stack up?</p>
  356. <p>It makes more sense to have an array:
  357. <code>volatile uint8 events[NUM_EVENTS]</code> where NUM_EVENTS is on
  358. the order of 5..10. That would give us 50-100msec to catch up in case
  359. there’s a pileup of events/messages.</p>
  360. <p>At the beginning, before anything happens, we need to make sure the
  361. <code>events[]</code> is full of zeros (EVT_NONE), indicating that it’s
  362. empty.</p>
  363. <p>The <code>newEvent(evt)</code> routine simply adds the
  364. <code>evt</code> to the array <code>events[]</code>.</p>
  365. <p>Something like this might work:</p>
  366. <div class="sourceCode" id="cb5"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> newEvent<span class="op">(</span>uint8r evt<span class="op">)</span> <span class="op">{</span></span>
  367. <span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">static</span> <span class="dt">unsigned</span> uint8 nextEvent<span class="op">;</span></span>
  368. <span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> events<span class="op">[</span>nextEvent<span class="op">++]</span> <span class="op">=</span> evt<span class="op">;</span></span>
  369. <span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>nextEvent <span class="op">==</span> NUM_EVENTS<span class="op">)</span></span>
  370. <span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a> nextEvent <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  371. <span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  372. <details>
  373. <summary>
  374. Reality check
  375. </summary>
  376. <p>There is a problem with the above code. What happens if a
  377. <code>key_isr()</code> is running, and is halfway through its call to
  378. <code>newEvent()</code> when a <code>timer_isr()</code> happens, and
  379. reenters the <code>newEvent()</code> routine. This will get really
  380. messed up. So we need to wrap <em>this particular</em> code in a
  381. critical section.</p>
  382. <p>Here’s a more realistic version:</p>
  383. <div class="sourceCode" id="cb6"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> newEvent<span class="op">(</span><span class="dt">char</span> evt<span class="op">)</span> <span class="op">{</span></span>
  384. <span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">static</span> <span class="dt">unsigned</span> <span class="dt">char</span> nextEvent<span class="op">;</span> <span class="co">// keep track of where we are in queue</span></span>
  385. <span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> disable_irq<span class="op">();</span> <span class="co">// critical section</span></span>
  386. <span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> events<span class="op">[</span>nextEvent<span class="op">++]</span> <span class="op">=</span> evt<span class="op">;</span> <span class="co">// insert event into queue</span></span>
  387. <span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>nextEvent <span class="op">==</span> NUM_EVENTS<span class="op">)</span> <span class="co">// loop back to the start of queue</span></span>
  388. <span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a> nextEvent <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  389. <span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a> enable_irq<span class="op">();</span> <span class="co">// end critical section, probably &lt;100us of blockage</span></span>
  390. <span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  391. </details>
  392. <p>In the next section, we’ll show how the <code>main()</code> code
  393. pulls the events out of the array, and leaves an EVT_NONE in its
  394. place.</p>
  395. <h2 id="dispatch">Dispatch</h2>
  396. <p>The <code>main()</code> code can simply watch the
  397. <code>events[]</code> to see when an entry goes non-zero (!=EVT_NONE).
  398. When that happens, <code>main()</code> will pull out the
  399. <em>event/message</em> from the array, and call the task subroutines. In
  400. this case, <code>flashLedTask()</code> and
  401. <code>respondToButtonTask()</code>.</p>
  402. <p>To see the real code for the dispatcher, <a
  403. href="#dispatcher-details">jump ahead</a>.</p>
  404. <details>
  405. <summary>
  406. Terminology
  407. </summary>
  408. <p>The <code>main()</code> code illustrated here calls the tasks as
  409. subroutines, sending each one a copy of the event number.</p>
  410. <p>As I mentioned earlier, <em>events</em> can also be refered to as
  411. <em>messages</em>. We can also refer to this process “sending a message
  412. to the task”</p>
  413. <p>So, for this paper, these are equivalent</p>
  414. <ul>
  415. <li>calling a task subroutine with the event information</li>
  416. <li>sending a message to a task</li>
  417. </ul>
  418. </details>
  419. <figure>
  420. <img src="dispatch2.jpg" alt="Call task routines with event" />
  421. <figcaption aria-hidden="true">Call task routines with
  422. event</figcaption>
  423. </figure>
  424. <details>
  425. <summary>
  426. Reality check
  427. </summary>
  428. <p>It may seem wasteful to send <em>all</em> events to <em>all</em>
  429. tasks. Probably some tasks don’t care about certain classes of events.
  430. But classifying, sorting and filtering the events takes real time, and
  431. code space, and probably isn’t worth it for these small
  432. microcontrollers.</p>
  433. <p>More sophisticated event systems do, in fact, filter and sort events.
  434. For example, Windows only sends <code>MOUSE_MOVE</code> events to the
  435. code belonging to the window over which the mouse is travelling. All the
  436. other windows don’t get the event, speeding up the whole system.</p>
  437. </details>
  438. <h2 id="tasks">Tasks</h2>
  439. <p>In this environment, the code that impliments a <em>task</em> is
  440. simply a subroutine that accepts an <em>event/message</em>.</p>
  441. <div class="sourceCode" id="cb7"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> taskCode<span class="op">(</span>uint8 event<span class="op">)</span> <span class="op">{</span></span>
  442. <span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span> process the event information <span class="op">...</span></span>
  443. <span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  444. <p>The subroutine should be designed to flow-through as quickly as
  445. possible, without any pauses/waits/delays.</p>
  446. <p>If the problem that you’re trying to solve involves the passage of
  447. time, or any delay, then you must break down the actions into individual
  448. items, and build a <a href="#state-machine">state machine</a>.</p>
  449. <h2 id="state-machine">State Machine</h2>
  450. <p>A <em>state machine</em> in this environment is a subroutine which
  451. can be called many times, and it remembers in which <em>state</em> it
  452. was left from the previous call. Some invocations of this subroutine may
  453. cause it to change state, which can be represented in a net diagram.</p>
  454. <p>Here’s a state diagram for the task which reacts to a button press by
  455. flashing an LED.</p>
  456. <figure>
  457. <img src="rtb_state.png" alt="simple state diagram" />
  458. <figcaption aria-hidden="true">simple state diagram</figcaption>
  459. </figure>
  460. <p>How does the <em>state code</em> remember what state it’s in between
  461. invocations? We can use a <code>static</code> variable. A
  462. <code>static</code> is stored in main memory (<em>not on the
  463. stack</em>), persists between calls and is initialized to zero.</p>
  464. <p>The above diagram can be implemented in this code:</p>
  465. <div class="sourceCode" id="cb8"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span>RTB_IDLE<span class="op">,</span> RTB_ON<span class="op">};</span> <span class="co">// RTB_IDLE=0, RTB_ON=1</span></span>
  466. <span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> uint8 rtbState <span class="op">=</span> RTB_IDLE<span class="op">;</span></span>
  467. <span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> uint16 rtbTimerCount <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  468. <span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> uint16 TIMER_LIMIT <span class="op">=</span> <span class="dv">150</span><span class="op">;</span></span>
  469. <span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a></span>
  470. <span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> respondToButtonTask<span class="op">(</span>uint8 evt<span class="op">)</span> <span class="op">{</span></span>
  471. <span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>rtbState<span class="op">)</span> <span class="op">{</span></span>
  472. <span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> RTB_IDLE<span class="op">:</span></span>
  473. <span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_BUTTON<span class="op">)</span> <span class="op">{</span></span>
  474. <span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_ON<span class="op">;</span></span>
  475. <span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a> rtbTimerCount <span class="op">=</span> TIMER_LIMIT<span class="op">;</span></span>
  476. <span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> ON<span class="op">);</span></span>
  477. <span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  478. <span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  479. <span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> RTB_ON<span class="op">:</span></span>
  480. <span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  481. <span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(--</span>rtbTimerCount <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
  482. <span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> OFF<span class="op">);</span></span>
  483. <span id="cb8-19"><a href="#cb8-19" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_IDLE<span class="op">;</span></span>
  484. <span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  485. <span id="cb8-21"><a href="#cb8-21" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  486. <span id="cb8-22"><a href="#cb8-22" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  487. <span id="cb8-23"><a href="#cb8-23" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  488. <span id="cb8-24"><a href="#cb8-24" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  489. <p>Each time this routine is called, it checks the <em>event</em> that
  490. it was given, and sometimes processes it. And sometimes it changes
  491. state.</p>
  492. <p>Here’s a few things to notice:</p>
  493. <ul>
  494. <li>The code <em>flows through</em>. It does not stop or wait for
  495. anything.</li>
  496. <li>Each arrow in the net diagram corresponds to a phrase in the code.
  497. The <em>tail</em> of the arrow corresponds to an <code>if</code>
  498. statement</li>
  499. <li>The code ignores <em>events</em> that are not relevant.</li>
  500. </ul>
  501. <details>
  502. <summary>
  503. Reality check
  504. </summary>
  505. <p>The <em>state</em> variable must be <code>static</code> or in the
  506. global memory space. <em>NEVER put a state variable on the stack!</em>
  507. i.e. as a local variable.</p>
  508. The tick counter could equally well count up from zero to threshold. See
  509. the discussion about <a href="#timers-as-a-resource">shared timers</a>
  510. </details>
  511. <h2 id="another-state-machine">Another State Machine</h2>
  512. <p>The other task of this project simply flashes the LED on and off.</p>
  513. <p><img src="led_state_simple.png" /></p>
  514. <p>The code for this might be:</p>
  515. <div class="sourceCode" id="cb9"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span>LED_ON<span class="op">,</span> LED_OFF<span class="op">};</span></span>
  516. <span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> uint8 ledState <span class="op">=</span> LED_OFF<span class="op">;</span></span>
  517. <span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> uint16 ledTimerCount <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  518. <span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> uint16 LED_ON_TIME <span class="op">=</span> <span class="dv">100</span><span class="op">;</span></span>
  519. <span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> uint16 LED_OFF_TIME <span class="op">=</span> <span class="dv">100</span><span class="op">;</span></span>
  520. <span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
  521. <span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> ledTask<span class="op">(</span>uint8 evt<span class="op">)</span> <span class="op">{</span></span>
  522. <span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>ledState<span class="op">)</span> <span class="op">{</span></span>
  523. <span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> LED_OFF<span class="op">:</span></span>
  524. <span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  525. <span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(--</span>ledTimerCount <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
  526. <span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> ON<span class="op">);</span></span>
  527. <span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a> ledTimerCount <span class="op">=</span> LED_ON_TIME<span class="op">;</span></span>
  528. <span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a> ledState <span class="op">=</span> LED_ON<span class="op">;</span></span>
  529. <span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  530. <span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  531. <span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  532. <span id="cb9-18"><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> LED_ON<span class="op">:</span></span>
  533. <span id="cb9-19"><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  534. <span id="cb9-20"><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(--</span>ledTimerCount <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
  535. <span id="cb9-21"><a href="#cb9-21" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> OFF<span class="op">);</span></span>
  536. <span id="cb9-22"><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a> ledTimerCount <span class="op">=</span> LED_OFF_TIME<span class="op">;</span></span>
  537. <span id="cb9-23"><a href="#cb9-23" aria-hidden="true" tabindex="-1"></a> ledState <span class="op">=</span> LED_OFF<span class="op">;</span></span>
  538. <span id="cb9-24"><a href="#cb9-24" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  539. <span id="cb9-25"><a href="#cb9-25" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  540. <span id="cb9-26"><a href="#cb9-26" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  541. <span id="cb9-27"><a href="#cb9-27" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  542. <span id="cb9-28"><a href="#cb9-28" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  543. <details>
  544. <summary>
  545. Discussion
  546. </summary>
  547. <p>Perhaps a more accurate state diagram might be:</p>
  548. <p><img src="led_state.png" /></p>
  549. <p>As you build the code from the diagram, I <em>strongly</em> suggest
  550. that you use a <code>switch(currentState) ....case STATE_1</code>
  551. approach to the task routine. If you try and code it with multiple
  552. <code>if(currentState==STATE_1)</code>, you will find yourself in a
  553. tangle of spaghetti; and if you forget a critical <code>else</code>,
  554. nothing will work as you expect.</p>
  555. <div class="sourceCode" id="cb10"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="op">(</span>state<span class="op">==</span><span class="dv">1</span><span class="op">)</span> <span class="op">{</span></span>
  556. <span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">=</span> EVT_1<span class="op">)</span> <span class="op">{</span></span>
  557. <span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> P3OUT <span class="op">=</span> <span class="dv">27</span><span class="op">;</span> <span class="co">// turn on some hardware</span></span>
  558. <span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a> state <span class="op">=</span> <span class="dv">2</span><span class="op">;</span> <span class="co">// and change state</span></span>
  559. <span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  560. <span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> </span>
  561. <span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="op">(</span>state<span class="op">==</span><span class="dv">2</span><span class="op">)</span> <span class="op">{</span> <span class="co">// &lt;&lt;&lt;----- BAD BAD</span></span>
  562. <span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a> P3OUT <span class="op">=</span> <span class="dv">14</span><span class="op">;</span></span>
  563. <span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a> state <span class="op">=</span> <span class="dv">3</span><span class="op">;</span> <span class="co">// &lt;&lt;&lt;--- dont&#39; change state twice in the same event</span></span>
  564. <span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  565. <span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a><span class="op">...</span></span></code></pre></div>
  566. <p>rather</p>
  567. <div class="sourceCode" id="cb11"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="cf">switch</span><span class="op">(</span>state<span class="op">)</span> <span class="op">{</span></span>
  568. <span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="dv">1</span><span class="op">:</span></span>
  569. <span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">=</span> EVT_1<span class="op">)</span> <span class="op">{</span></span>
  570. <span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> P3OUT <span class="op">=</span> <span class="dv">27</span><span class="op">;</span> <span class="co">// turn on some hardware</span></span>
  571. <span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a> state <span class="op">=</span> <span class="dv">2</span><span class="op">;</span></span>
  572. <span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  573. <span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  574. <span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="dv">2</span><span class="op">:</span></span>
  575. <span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a> P3OUT <span class="op">=</span> <span class="dv">14</span><span class="op">;</span></span>
  576. <span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a> state <span class="op">=</span> <span class="dv">3</span><span class="op">;</span></span>
  577. <span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  578. <span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span></span>
  579. <span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  580. <p>As a general rule, try to avoid changing states more than once per
  581. event; this kind of discipline will help with debugging a complex
  582. project.</p>
  583. </details>
  584. <h2 id="dispatcher-details">Dispatcher Details</h2>
  585. <p>The last piece of the puzzle is the <code>main()</code> code which
  586. observes the <code>events[]</code> array and calls the tasks.</p>
  587. <p>The <code>events[]</code> array is designed so that a 0 means ‘no
  588. event’, and the non-zero events are dropped into the array in order…so
  589. pulling them out is pretty straight forward.</p>
  590. <div class="sourceCode" id="cb12"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> main<span class="op">()</span> <span class="op">{</span></span>
  591. <span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a> initialize<span class="op">();</span></span>
  592. <span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a></span>
  593. <span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span><span class="op">(</span><span class="dv">1</span><span class="op">)</span> <span class="op">{</span></span>
  594. <span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> i<span class="op">;</span></span>
  595. <span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span>i<span class="op">=</span><span class="dv">0</span><span class="op">;</span> i<span class="op">&lt;</span>NUM_EVENTS<span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
  596. <span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span> <span class="op">(</span>events<span class="op">[</span>i<span class="op">]==</span>EVT_NONE<span class="op">)</span></span>
  597. <span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a> <span class="op">{}</span></span>
  598. <span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a> ledTask<span class="op">(</span>events<span class="op">[</span>i<span class="op">]);</span></span>
  599. <span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a> respondToButtonTask<span class="op">(</span>events<span class="op">[</span>i<span class="op">]);</span></span>
  600. <span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a> events<span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> EVT_NONE<span class="op">;</span></span>
  601. <span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  602. <span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  603. <span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  604. <p>Each non-zero event is “sent” to each task…..by means of a subroutine
  605. call. Once all the tasks have been invoked, the <code>event</code> is
  606. thrown away and its slot in the array is set to zero.</p>
  607. <details>
  608. <summary>
  609. Reality check
  610. </summary>
  611. <p>The <code>main()</code> code above needs to run with interrupts
  612. enabled.</p>
  613. <p>There’s lots of ways to structure the ‘wait for event’ loop. For
  614. example, when you detect that the <code>events[]</code> array is empty,
  615. you could power-down the microcontroller. In most microprocessors, an
  616. interrupt will wake the CPU again, and deliver a non-zero event into the
  617. array, so you might as well power-down while you’re waiting.</p>
  618. </details>
  619. <h2 id="final-implementation">Final Implementation</h2>
  620. <p>Let’s put all of the above together, for an SMT32F Cortex M0, in
  621. <em>C</em> code.</p>
  622. <div class="sourceCode" id="cb13"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="co">/***** declarations ****/</span></span>
  623. <span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#define NUM_EVENTS </span><span class="dv">10</span></span>
  624. <span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="dt">volatile</span> uint8 events<span class="op">[</span>NUM_EVENTS<span class="op">];</span></span>
  625. <span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a></span>
  626. <span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> newEvent<span class="op">(</span>uint8 e<span class="op">);</span></span>
  627. <span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> ledTask<span class="op">(</span>uint8 evt<span class="op">);</span></span>
  628. <span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> respondToButtonTask<span class="op">(</span>uint8 evt<span class="op">);</span></span>
  629. <span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a></span>
  630. <span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a><span class="co">/********** interrupts **************/</span></span>
  631. <span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a></span>
  632. <span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> timer_isr<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
  633. <span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a> newEvent<span class="op">(</span>EVT_TICK<span class="op">);</span></span>
  634. <span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a> <span class="co">// this interrupt is auto-ack&#39;d</span></span>
  635. <span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  636. <span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a></span>
  637. <span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> button_isr<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
  638. <span id="cb13-17"><a href="#cb13-17" aria-hidden="true" tabindex="-1"></a> newEvent<span class="op">(</span>EVT_BUTTON<span class="op">);</span></span>
  639. <span id="cb13-18"><a href="#cb13-18" aria-hidden="true" tabindex="-1"></a> EXTI<span class="op">-&gt;</span>PR <span class="op">|=</span> KEY_IRQ_ACK_MASK<span class="op">;</span> <span class="co">// the hardware requires that we acknowledge </span></span>
  640. <span id="cb13-19"><a href="#cb13-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  641. <span id="cb13-20"><a href="#cb13-20" aria-hidden="true" tabindex="-1"></a></span>
  642. <span id="cb13-21"><a href="#cb13-21" aria-hidden="true" tabindex="-1"></a><span class="co">/** newEvent</span></span>
  643. <span id="cb13-22"><a href="#cb13-22" aria-hidden="true" tabindex="-1"></a><span class="co"> * add the event to the event queue</span></span>
  644. <span id="cb13-23"><a href="#cb13-23" aria-hidden="true" tabindex="-1"></a><span class="co"> * wrapped in critical section</span></span>
  645. <span id="cb13-24"><a href="#cb13-24" aria-hidden="true" tabindex="-1"></a><span class="co"> * </span></span>
  646. <span id="cb13-25"><a href="#cb13-25" aria-hidden="true" tabindex="-1"></a><span class="co"> * </span><span class="an">@param</span><span class="co"> </span><span class="cv">the</span><span class="co"> event</span></span>
  647. <span id="cb13-26"><a href="#cb13-26" aria-hidden="true" tabindex="-1"></a><span class="co"> */</span></span>
  648. <span id="cb13-27"><a href="#cb13-27" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> newEvent<span class="op">(</span>uint8 e<span class="op">)</span> <span class="op">{</span></span>
  649. <span id="cb13-28"><a href="#cb13-28" aria-hidden="true" tabindex="-1"></a> <span class="dt">static</span> uint8 nextEvent<span class="op">;</span></span>
  650. <span id="cb13-29"><a href="#cb13-29" aria-hidden="true" tabindex="-1"></a> dint<span class="op">();</span> <span class="co">// critical section</span></span>
  651. <span id="cb13-30"><a href="#cb13-30" aria-hidden="true" tabindex="-1"></a> events<span class="op">[</span>nextEvent<span class="op">++]</span> <span class="op">=</span> e<span class="op">;</span></span>
  652. <span id="cb13-31"><a href="#cb13-31" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>nextEvent<span class="op">==</span>NUM_EVENTS<span class="op">)</span></span>
  653. <span id="cb13-32"><a href="#cb13-32" aria-hidden="true" tabindex="-1"></a> nextEvent <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  654. <span id="cb13-33"><a href="#cb13-33" aria-hidden="true" tabindex="-1"></a> eint<span class="op">();</span></span>
  655. <span id="cb13-34"><a href="#cb13-34" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  656. <span id="cb13-35"><a href="#cb13-35" aria-hidden="true" tabindex="-1"></a></span>
  657. <span id="cb13-36"><a href="#cb13-36" aria-hidden="true" tabindex="-1"></a><span class="co">/****** main() and dispatcher *********/</span></span>
  658. <span id="cb13-37"><a href="#cb13-37" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> main<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
  659. <span id="cb13-38"><a href="#cb13-38" aria-hidden="true" tabindex="-1"></a></span>
  660. <span id="cb13-39"><a href="#cb13-39" aria-hidden="true" tabindex="-1"></a> eint<span class="op">();</span></span>
  661. <span id="cb13-40"><a href="#cb13-40" aria-hidden="true" tabindex="-1"></a></span>
  662. <span id="cb13-41"><a href="#cb13-41" aria-hidden="true" tabindex="-1"></a> <span class="co">// dispatcher loop</span></span>
  663. <span id="cb13-42"><a href="#cb13-42" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span><span class="op">(</span><span class="dv">1</span><span class="op">)</span> <span class="op">{</span></span>
  664. <span id="cb13-43"><a href="#cb13-43" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> j<span class="op">;</span></span>
  665. <span id="cb13-44"><a href="#cb13-44" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span>j<span class="op">=</span><span class="dv">0</span><span class="op">;</span> j<span class="op">&lt;</span>NUM_EVENTS<span class="op">;</span> j<span class="op">++)</span> <span class="op">{</span></span>
  666. <span id="cb13-45"><a href="#cb13-45" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span> <span class="op">(</span>events<span class="op">[</span>j<span class="op">]==</span>EVT_NONE<span class="op">)</span></span>
  667. <span id="cb13-46"><a href="#cb13-46" aria-hidden="true" tabindex="-1"></a> <span class="op">{}</span></span>
  668. <span id="cb13-47"><a href="#cb13-47" aria-hidden="true" tabindex="-1"></a> ledTask<span class="op">(</span>events<span class="op">[</span>j<span class="op">]);</span></span>
  669. <span id="cb13-48"><a href="#cb13-48" aria-hidden="true" tabindex="-1"></a> respondToButtonTask<span class="op">(</span>events<span class="op">[</span>j<span class="op">]);</span></span>
  670. <span id="cb13-49"><a href="#cb13-49" aria-hidden="true" tabindex="-1"></a> events<span class="op">[</span>j<span class="op">]</span> <span class="op">=</span> EVT_NONE<span class="op">;</span></span>
  671. <span id="cb13-50"><a href="#cb13-50" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  672. <span id="cb13-51"><a href="#cb13-51" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  673. <span id="cb13-52"><a href="#cb13-52" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  674. <span id="cb13-53"><a href="#cb13-53" aria-hidden="true" tabindex="-1"></a></span>
  675. <span id="cb13-54"><a href="#cb13-54" aria-hidden="true" tabindex="-1"></a><span class="co">/*********** task code, with states ************/</span></span>
  676. <span id="cb13-55"><a href="#cb13-55" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span>LED_ON<span class="op">,</span> LED_OFF<span class="op">};</span></span>
  677. <span id="cb13-56"><a href="#cb13-56" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span>RTB_IDLE<span class="op">,</span> RTB_ON<span class="op">};</span> <span class="co">// states</span></span>
  678. <span id="cb13-57"><a href="#cb13-57" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> uint8 rtbState <span class="op">=</span> RTB_IDLE<span class="op">;</span></span>
  679. <span id="cb13-58"><a href="#cb13-58" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> uint16 rtbTimerCount <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  680. <span id="cb13-59"><a href="#cb13-59" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> uint16 LED_ON_TIME <span class="op">=</span> <span class="dv">150</span><span class="op">;</span></span>
  681. <span id="cb13-60"><a href="#cb13-60" aria-hidden="true" tabindex="-1"></a></span>
  682. <span id="cb13-61"><a href="#cb13-61" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> respondToButtonTask<span class="op">(</span>uint8 evt<span class="op">)</span> <span class="op">{</span></span>
  683. <span id="cb13-62"><a href="#cb13-62" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>rtbState<span class="op">)</span> <span class="op">{</span></span>
  684. <span id="cb13-63"><a href="#cb13-63" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> RTB_IDLE<span class="op">:</span></span>
  685. <span id="cb13-64"><a href="#cb13-64" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_BUTTON<span class="op">)</span> <span class="op">{</span></span>
  686. <span id="cb13-65"><a href="#cb13-65" aria-hidden="true" tabindex="-1"></a> rtbTimerCount <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  687. <span id="cb13-66"><a href="#cb13-66" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_ON<span class="op">;</span></span>
  688. <span id="cb13-67"><a href="#cb13-67" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> LED_ON<span class="op">);</span></span>
  689. <span id="cb13-68"><a href="#cb13-68" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  690. <span id="cb13-69"><a href="#cb13-69" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  691. <span id="cb13-70"><a href="#cb13-70" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> RTB_ON<span class="op">:</span></span>
  692. <span id="cb13-71"><a href="#cb13-71" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  693. <span id="cb13-72"><a href="#cb13-72" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(++</span>rtbTimerCount <span class="op">&gt;</span> LED_ON_TIME<span class="op">)</span> <span class="op">{</span></span>
  694. <span id="cb13-73"><a href="#cb13-73" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> LED_OFF<span class="op">);</span></span>
  695. <span id="cb13-74"><a href="#cb13-74" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_IDLE<span class="op">;</span></span>
  696. <span id="cb13-75"><a href="#cb13-75" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  697. <span id="cb13-76"><a href="#cb13-76" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  698. <span id="cb13-77"><a href="#cb13-77" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  699. <span id="cb13-78"><a href="#cb13-78" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  700. <span id="cb13-79"><a href="#cb13-79" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  701. <span id="cb13-80"><a href="#cb13-80" aria-hidden="true" tabindex="-1"></a></span>
  702. <span id="cb13-81"><a href="#cb13-81" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> uint16 LED_ON_TIME <span class="op">=</span> <span class="dv">150</span><span class="op">;</span></span>
  703. <span id="cb13-82"><a href="#cb13-82" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> uint16 LED_OFF_TIME <span class="op">=</span> <span class="dv">50</span><span class="op">;</span></span>
  704. <span id="cb13-83"><a href="#cb13-83" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> uint8 ledState <span class="op">=</span> LED_OFF<span class="op">;</span></span>
  705. <span id="cb13-84"><a href="#cb13-84" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> uint16 ledTimerCount <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  706. <span id="cb13-85"><a href="#cb13-85" aria-hidden="true" tabindex="-1"></a></span>
  707. <span id="cb13-86"><a href="#cb13-86" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> ledTask<span class="op">(</span>uint8 evt<span class="op">)</span> <span class="op">{</span></span>
  708. <span id="cb13-87"><a href="#cb13-87" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>ledState<span class="op">)</span> <span class="op">{</span></span>
  709. <span id="cb13-88"><a href="#cb13-88" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> LED_OFF<span class="op">:</span></span>
  710. <span id="cb13-89"><a href="#cb13-89" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  711. <span id="cb13-90"><a href="#cb13-90" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(++</span>ledTimerCount <span class="op">&gt;</span> LED_OFF_TIME<span class="op">)</span> <span class="op">{</span></span>
  712. <span id="cb13-91"><a href="#cb13-91" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED2<span class="op">,</span> LED_ON<span class="op">);</span></span>
  713. <span id="cb13-92"><a href="#cb13-92" aria-hidden="true" tabindex="-1"></a> ledTimerCount <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  714. <span id="cb13-93"><a href="#cb13-93" aria-hidden="true" tabindex="-1"></a> ledState <span class="op">=</span> LED_ON<span class="op">;</span></span>
  715. <span id="cb13-94"><a href="#cb13-94" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  716. <span id="cb13-95"><a href="#cb13-95" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  717. <span id="cb13-96"><a href="#cb13-96" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  718. <span id="cb13-97"><a href="#cb13-97" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> LED_ON<span class="op">:</span></span>
  719. <span id="cb13-98"><a href="#cb13-98" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  720. <span id="cb13-99"><a href="#cb13-99" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(++</span>ledTimerCount <span class="op">&gt;</span> LED_ON_TIME<span class="op">)</span> <span class="op">{</span></span>
  721. <span id="cb13-100"><a href="#cb13-100" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED2<span class="op">,</span> LED_OFF<span class="op">);</span></span>
  722. <span id="cb13-101"><a href="#cb13-101" aria-hidden="true" tabindex="-1"></a> ledTimerCount <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  723. <span id="cb13-102"><a href="#cb13-102" aria-hidden="true" tabindex="-1"></a> ledState <span class="op">=</span> LED_OFF<span class="op">;</span></span>
  724. <span id="cb13-103"><a href="#cb13-103" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  725. <span id="cb13-104"><a href="#cb13-104" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  726. <span id="cb13-105"><a href="#cb13-105" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  727. <span id="cb13-106"><a href="#cb13-106" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  728. <span id="cb13-107"><a href="#cb13-107" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  729. <p>This is the end of the main presentation. With the above techniques,
  730. you can make a tiny microprocessor appear to multitask.</p>
  731. <p>For further tips, read the next section. The interesting topics
  732. are:</p>
  733. <ul>
  734. <li><a href="#state-machine-examples">more state code examples</a>
  735. <ul>
  736. <li>with implementation</li>
  737. </ul></li>
  738. <li><a href="#state-machine-initialization">how to initialize a state
  739. machine</a></li>
  740. <li><a href="#messages">inter-task communication</a></li>
  741. <li><a href="#timers">unified timers</a></li>
  742. </ul>
  743. <details>
  744. <summary>
  745. Reality Check
  746. </summary>
  747. <p>What’s missing from this code sample is the initialization of the
  748. hardware……..some kind of <code>setup()</code> routine. I left it out
  749. because it’s going to vary so much between processors, and only
  750. distracts from the point of this paper. If you want a detailed, tested
  751. copy of this code, see <a href="build/demo.c">here</a></p>
  752. The above example only shows 2 tasks, so all the formal structure may
  753. seem a bit silly. But once you have the infrastructure in place, you can
  754. easily handle <em>dozens</em> of tasks, even on sub-$1 processors.
  755. </details>
  756. <h1 id="part-2">Part 2</h1>
  757. <h2 id="variations">Variations</h2>
  758. <style>
  759. .imageleft {float: left;}
  760. .imageright {float: right;}
  761. </style>
  762. <p>Now that the infrastructure is in place, it’s easy to expand or
  763. modify the code for changes in the project definition.</p>
  764. <p>For example, suppose we want the <code>respondToButtonTask()</code>
  765. to restart the LED timer on each key press:</p>
  766. <p><img src="rtb_state_2.png" class="imageleft" /></p>
  767. <div class="sourceCode" id="cb14"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> rtbTask<span class="op">(</span>uint8 event<span class="op">)</span> <span class="op">{</span></span>
  768. <span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>rtbState<span class="op">)</span> <span class="op">{</span></span>
  769. <span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> RTB_IDLE<span class="op">:</span></span>
  770. <span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_BUTTON<span class="op">)</span> <span class="op">{</span></span>
  771. <span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> LED_ON<span class="op">);</span></span>
  772. <span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_ON<span class="op">;</span></span>
  773. <span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a> rtbTimer <span class="op">=</span> RTB_TIMEOUT<span class="op">;</span></span>
  774. <span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  775. <span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  776. <span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> RTB_ON<span class="op">:</span></span>
  777. <span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_BUTTON<span class="op">)</span> <span class="op">{</span> </span>
  778. <span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a> rtbTimer <span class="op">=</span> RTB_TIMEOUT<span class="op">;</span></span>
  779. <span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  780. <span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  781. <span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(--</span>rtbTimer <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
  782. <span id="cb14-16"><a href="#cb14-16" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> LED_OFF<span class="op">);</span></span>
  783. <span id="cb14-17"><a href="#cb14-17" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_IDLE<span class="op">;</span></span>
  784. <span id="cb14-18"><a href="#cb14-18" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  785. <span id="cb14-19"><a href="#cb14-19" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  786. <span id="cb14-20"><a href="#cb14-20" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  787. <span id="cb14-21"><a href="#cb14-21" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  788. <span id="cb14-22"><a href="#cb14-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  789. <hr>
  790. <p>Or have a 2nd press of the button cause the LED to extinguish
  791. early:</p>
  792. <p><img src="rtb_state_3.png" class="imageleft" /></p>
  793. <div class="sourceCode" id="cb15"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> rtbTask<span class="op">(</span>uint8 event<span class="op">)</span> <span class="op">{</span></span>
  794. <span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>rtbState<span class="op">)</span> <span class="op">{</span></span>
  795. <span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> RTB_IDLE<span class="op">:</span></span>
  796. <span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_BUTTON<span class="op">)</span> <span class="op">{</span></span>
  797. <span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> LED_ON<span class="op">);</span></span>
  798. <span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_ON<span class="op">;</span></span>
  799. <span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a> rtbTimer <span class="op">=</span> RTB_TIMEOUT<span class="op">;</span></span>
  800. <span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  801. <span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  802. <span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> RTB_ON<span class="op">:</span></span>
  803. <span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_BUTTON<span class="op">)</span> <span class="op">{</span> </span>
  804. <span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> LED_OFF<span class="op">);</span></span>
  805. <span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_IDLE<span class="op">;</span></span>
  806. <span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  807. <span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  808. <span id="cb15-16"><a href="#cb15-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(--</span>rtbTimer <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
  809. <span id="cb15-17"><a href="#cb15-17" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> LED_OFF<span class="op">);</span></span>
  810. <span id="cb15-18"><a href="#cb15-18" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_IDLE<span class="op">;</span></span>
  811. <span id="cb15-19"><a href="#cb15-19" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  812. <span id="cb15-20"><a href="#cb15-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  813. <span id="cb15-21"><a href="#cb15-21" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  814. <span id="cb15-22"><a href="#cb15-22" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  815. <span id="cb15-23"><a href="#cb15-23" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  816. <hr>
  817. <p>How about have the button start a flash sequence, and a 2nd press
  818. stops it: (see also <a href="#substates">substates</a>)</p>
  819. <p><img src="rtb_state_4.png" class="imageright" /></p>
  820. <div class="sourceCode" id="cb16"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> rtbTask<span class="op">(</span>uint8 event<span class="op">)</span> <span class="op">{</span></span>
  821. <span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>rtbState<span class="op">)</span> <span class="op">{</span></span>
  822. <span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> RTB_IDLE<span class="op">:</span></span>
  823. <span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_BUTTON<span class="op">)</span> <span class="op">{</span></span>
  824. <span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> LED_ON<span class="op">);</span></span>
  825. <span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_ON<span class="op">;</span></span>
  826. <span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a> rtbTimer <span class="op">=</span> RTB_TIMEOUT<span class="op">;</span></span>
  827. <span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  828. <span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  829. <span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> RTB_ON<span class="op">:</span></span>
  830. <span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_BUTTON<span class="op">)</span> <span class="op">{</span> </span>
  831. <span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> LED_OFF<span class="op">);</span></span>
  832. <span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_IDLE<span class="op">;</span></span>
  833. <span id="cb16-14"><a href="#cb16-14" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  834. <span id="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  835. <span id="cb16-16"><a href="#cb16-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(--</span>rtbTimer <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
  836. <span id="cb16-17"><a href="#cb16-17" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> LED_OFF<span class="op">);</span></span>
  837. <span id="cb16-18"><a href="#cb16-18" aria-hidden="true" tabindex="-1"></a> rtbTimer <span class="op">=</span> RTB_FLASH_TIME<span class="op">;</span></span>
  838. <span id="cb16-19"><a href="#cb16-19" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_OFF<span class="op">;</span></span>
  839. <span id="cb16-20"><a href="#cb16-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  840. <span id="cb16-21"><a href="#cb16-21" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  841. <span id="cb16-22"><a href="#cb16-22" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  842. <span id="cb16-23"><a href="#cb16-23" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> RTB_OFF<span class="op">:</span></span>
  843. <span id="cb16-24"><a href="#cb16-24" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_BUTTON<span class="op">)</span> <span class="op">{</span> </span>
  844. <span id="cb16-25"><a href="#cb16-25" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> LED_OFF<span class="op">);</span></span>
  845. <span id="cb16-26"><a href="#cb16-26" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_IDLE<span class="op">;</span></span>
  846. <span id="cb16-27"><a href="#cb16-27" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  847. <span id="cb16-28"><a href="#cb16-28" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  848. <span id="cb16-29"><a href="#cb16-29" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(--</span>rtbTimer <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
  849. <span id="cb16-30"><a href="#cb16-30" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> LED_ON<span class="op">);</span></span>
  850. <span id="cb16-31"><a href="#cb16-31" aria-hidden="true" tabindex="-1"></a> rtbTimer <span class="op">=</span> RTB_FLASH_TIME<span class="op">;</span></span>
  851. <span id="cb16-32"><a href="#cb16-32" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_ON<span class="op">;</span></span>
  852. <span id="cb16-33"><a href="#cb16-33" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  853. <span id="cb16-34"><a href="#cb16-34" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  854. <span id="cb16-35"><a href="#cb16-35" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  855. <span id="cb16-36"><a href="#cb16-36" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  856. <span id="cb16-37"><a href="#cb16-37" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  857. <hr>
  858. <p>Each of these diagrams corresponds to trivial changes in the state
  859. code.</p>
  860. <h2 id="working-with-arduino">Working with Arduino</h2>
  861. <p>If you’re from the Arduino world, you have no doubt seen the
  862. similarity between this OS plan and the Arduino infrastructure.</p>
  863. <div class="sourceCode" id="cb17"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a>setup<span class="op">()</span> </span>
  864. <span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a> <span class="op">{}</span> <span class="co">// initialize and start up the devices and services</span></span>
  865. <span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a></span>
  866. <span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>loop<span class="op">()</span></span>
  867. <span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a> <span class="op">{}</span> <span class="co">// code for continuous operation</span></span></code></pre></div>
  868. <p>You can certainly merge this paper’s operating system into the
  869. Arduino architecture:</p>
  870. <div class="sourceCode" id="cb18"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span> events<span class="op">[];</span></span>
  871. <span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a></span>
  872. <span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>interrupt_service_routines<span class="op">()</span> <span class="op">{</span></span>
  873. <span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a> newEvent<span class="op">(</span>evt<span class="op">);</span> <span class="co">// insert events/messages into events[]</span></span>
  874. <span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> </span>
  875. <span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a></span>
  876. <span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">int</span> nextEvent<span class="op">;</span></span>
  877. <span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> newEvent<span class="op">(</span><span class="dt">char</span> evt<span class="op">)</span> </span>
  878. <span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a> <span class="op">{}</span> <span class="co">// same as above; put evt into the events[]</span></span>
  879. <span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a></span>
  880. <span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a>setup<span class="op">()</span></span>
  881. <span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a> <span class="op">{}</span></span>
  882. <span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a></span>
  883. <span id="cb18-14"><a href="#cb18-14" aria-hidden="true" tabindex="-1"></a>loop<span class="op">()</span> <span class="op">{</span></span>
  884. <span id="cb18-15"><a href="#cb18-15" aria-hidden="true" tabindex="-1"></a> <span class="dt">static</span> <span class="dt">int</span> nextTaskEvent<span class="op">;</span></span>
  885. <span id="cb18-16"><a href="#cb18-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>events<span class="op">[</span>nextTaskEvent<span class="op">]!=</span>EVT_NONE<span class="op">)</span> <span class="op">{</span> <span class="co">// check for non-zero events[],</span></span>
  886. <span id="cb18-17"><a href="#cb18-17" aria-hidden="true" tabindex="-1"></a> task1<span class="op">(</span>events<span class="op">[</span>nextTaskEvent<span class="op">]);</span> <span class="co">// and call the task routines</span></span>
  887. <span id="cb18-18"><a href="#cb18-18" aria-hidden="true" tabindex="-1"></a> task2<span class="op">(</span>events<span class="op">[</span>nextTaskEvent<span class="op">]);</span></span>
  888. <span id="cb18-19"><a href="#cb18-19" aria-hidden="true" tabindex="-1"></a> events<span class="op">[</span>nextTaskEvent<span class="op">)</span> <span class="op">=</span> EVT_NONE<span class="op">;</span> <span class="co">// free the slot, fill with 0</span></span>
  889. <span id="cb18-20"><a href="#cb18-20" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(++</span>nextTaskEvent <span class="op">&gt;</span> NUM_EVENTS<span class="op">)</span></span>
  890. <span id="cb18-21"><a href="#cb18-21" aria-hidden="true" tabindex="-1"></a> nextTaskEvent <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> <span class="co">// and loop through the array</span></span>
  891. <span id="cb18-22"><a href="#cb18-22" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  892. <span id="cb18-23"><a href="#cb18-23" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> </span>
  893. <span id="cb18-24"><a href="#cb18-24" aria-hidden="true" tabindex="-1"></a></span>
  894. <span id="cb18-25"><a href="#cb18-25" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> task1<span class="op">(</span><span class="dt">char</span> evt<span class="op">)</span> <span class="op">{}</span></span>
  895. <span id="cb18-26"><a href="#cb18-26" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> task2<span class="op">(</span><span class="dt">char</span> evt<span class="op">)</span> <span class="op">{}</span></span>
  896. <span id="cb18-27"><a href="#cb18-27" aria-hidden="true" tabindex="-1"></a> </span></code></pre></div>
  897. <h2 id="tasks-1">Tasks</h2>
  898. <p>The fundamental guideline for tasks is that <em>they do not
  899. stop</em>. Control flows through and out the bottom, returning to the
  900. dispatcher quickly.</p>
  901. <details>
  902. <summary>
  903. Reality Check
  904. </summary>
  905. <p>In practical terms, if you have a timer tick that runs at every 10ms,
  906. and about 5 tasks, then if you can keep each task under 2ms, you won’t
  907. lose any events.</p>
  908. <p>If a task occasionally runs into the 10’s of msec, the event queue
  909. will handle buffering the events until they can be processed.</p>
  910. Under no circumstances should a task take more than 100msec. Use a new
  911. state, and return from the tast. Process the new state later.
  912. <hr>
  913. </details>
  914. <h2 id="state-machine-examples">State Machine Examples</h2>
  915. <h3 id="car-window">Car Window</h3>
  916. <p>Suppose we want to control the power window on a car? For this
  917. problem, we have an up/down button, a motor to drive the window up or
  918. down, and a motor-overload sensor to detect when the motor is straining.
  919. So the buttons &amp; overload sensor are inputs, and the motor drive is
  920. outputs.</p>
  921. <p>When the user presses the “up” button, we should start the motor
  922. moving upward. When the overload sensor detects a strain, then either
  923. the window is all the way up….or it has encountered a finger or hand; in
  924. either case, we need to turn the motor drive off.</p>
  925. <p>Here’s a possible state diagram. <img src="window_state.png"
  926. alt="window motor control" /></p>
  927. <p>And here’s the matching code. Note the correspondence between the
  928. diagram and the code: arrows leaving a state correspond to an
  929. <code>if()</code> phrase.</p>
  930. <div class="sourceCode" id="cb19"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span>WINDOW_IDLE<span class="op">,</span> WINDOW_UP<span class="op">,</span> WINDOW_DOWN<span class="op">};</span></span>
  931. <span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> uint8 windowState <span class="op">=</span> WINDOW_IDLE<span class="op">;</span></span>
  932. <span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a></span>
  933. <span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> windowTask<span class="op">(</span>uint8 evt<span class="op">)</span> <span class="op">{</span></span>
  934. <span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>windowState<span class="op">)</span> <span class="op">{</span></span>
  935. <span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> WINDOW_IDLE<span class="op">:</span></span>
  936. <span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_BUTTON_UP<span class="op">)</span> <span class="op">{</span></span>
  937. <span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>MOTOR<span class="op">,</span> UP<span class="op">);</span></span>
  938. <span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a> windowState <span class="op">=</span> WINDOW_UP<span class="op">;</span></span>
  939. <span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  940. <span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_BUTTON_DOWN<span class="op">)</span> <span class="op">{</span></span>
  941. <span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>MOTOR<span class="op">,</span> DOWN<span class="op">);</span></span>
  942. <span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a> windowState <span class="op">=</span> WINDOW_DOWN<span class="op">;</span></span>
  943. <span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  944. <span id="cb19-15"><a href="#cb19-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  945. <span id="cb19-16"><a href="#cb19-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> WINDOW_UP<span class="op">:</span></span>
  946. <span id="cb19-17"><a href="#cb19-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_MOTOR_SENSE <span class="op">||</span> </span>
  947. <span id="cb19-18"><a href="#cb19-18" aria-hidden="true" tabindex="-1"></a> evt <span class="op">==</span> EVT_BUTTON_RELEASE<span class="op">)</span> <span class="op">{</span></span>
  948. <span id="cb19-19"><a href="#cb19-19" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>MOTOR<span class="op">,</span> OFF<span class="op">);</span></span>
  949. <span id="cb19-20"><a href="#cb19-20" aria-hidden="true" tabindex="-1"></a> windowState <span class="op">=</span> WINDOW_IDLE<span class="op">;</span></span>
  950. <span id="cb19-21"><a href="#cb19-21" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  951. <span id="cb19-22"><a href="#cb19-22" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  952. <span id="cb19-23"><a href="#cb19-23" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> WINDOW_DOWN<span class="op">:</span></span>
  953. <span id="cb19-24"><a href="#cb19-24" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_MOTOR_SENSE <span class="op">||</span> </span>
  954. <span id="cb19-25"><a href="#cb19-25" aria-hidden="true" tabindex="-1"></a> evt <span class="op">==</span> EVT_BUTTON_RELEASE<span class="op">)</span> <span class="op">{</span></span>
  955. <span id="cb19-26"><a href="#cb19-26" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>MOTOR<span class="op">,</span> OFF<span class="op">);</span></span>
  956. <span id="cb19-27"><a href="#cb19-27" aria-hidden="true" tabindex="-1"></a> windowState <span class="op">=</span> WINDOW_IDLE<span class="op">;</span></span>
  957. <span id="cb19-28"><a href="#cb19-28" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  958. <span id="cb19-29"><a href="#cb19-29" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  959. <span id="cb19-30"><a href="#cb19-30" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  960. <p>Now, suppose the problem definition is changed: if the user presses
  961. the “up” button, the motor should only operate while the button is
  962. pressed; stop on release. But if the user presses the “up” button a
  963. second time within 1 second of the first release, the motor should drive
  964. the window all the way up (auto-close).</p>
  965. <p>Here is a possible state diagram. Notice the significant re-use of
  966. code from the previous version.</p>
  967. <figure>
  968. <img src="window_complex.png"
  969. alt="window control with auto open/close, (_ma) motor activated (_ms) motor stopped" />
  970. <figcaption aria-hidden="true">window control with auto open/close,
  971. (_ma) motor activated (_ms) motor stopped</figcaption>
  972. </figure>
  973. <details>
  974. <summary>
  975. Reality Check
  976. </summary>
  977. <p>This is such a simple task, with only a few I/O pins involved. In
  978. theory, a cheap microcontroller could control a dozen windows, each
  979. appearing to operate independantly.</p>
  980. <p>In the code, one wouldn’t need to create a dozen tasks……just create
  981. an index into the same code and invoke it in a way that makes it appear
  982. as an independent task:</p>
  983. <pre><code>void main(void) {
  984. eint();
  985. while(1) {
  986. for (i=0; i&lt;NUM_EVENTS; i++) {
  987. while (events[i]==EVT_NONE)
  988. {}
  989. taskWindow(events[i],0);
  990. taskWindow(events[i],1);
  991. // ...
  992. taskWindow(events[i],NUM_WINDOWS-1);
  993. events[i] = EVT_NONE;
  994. }
  995. }
  996. }
  997. // window management task
  998. int windowState[NUM_WINDOWS];
  999. void taskWindow(char event, int windowIndex) {
  1000. // find the state from the windowState[windowIndex]
  1001. // run through the state machine
  1002. // any I/O will require an array of I/O addresses, use &#39;windowIndex&#39;
  1003. switch(windowState[windowIndex]) {
  1004. case WS_IDLE:
  1005. ...
  1006. ...
  1007. }
  1008. }</code></pre>
  1009. </details>
  1010. <h3 id="fridge-door">Fridge Door</h3>
  1011. <p>A simple state machine can control the interior light of a fridge.
  1012. Here’s the use-case:</p>
  1013. <p>The problem has one input (door open) and two outputs (light and
  1014. audible alarm). If the door is open, turn on the light and start a timer
  1015. for 90 seconds. If the door is still open at the end of the 90 seconds,
  1016. start an audible alarm. If the door closes, stop the timer and turn off
  1017. the light and alarm. And if the door closes during the 90 seconds, turn
  1018. off the light.</p>
  1019. <p>Here is the state diagram.</p>
  1020. <p><img src="fridge_state.png" /></p>
  1021. <p>And here is the corresponding code.</p>
  1022. <div class="sourceCode" id="cb21"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span>FRIDGE_CLOSED<span class="op">,</span> FRIDGE_OPEN<span class="op">,</span> FRIDGE_BEEPING<span class="op">};</span></span>
  1023. <span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>uint8 fridgeState<span class="op">;</span></span>
  1024. <span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>uint16 fridgeTimer<span class="op">;</span></span>
  1025. <span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> uint16 FRIDGE_OPEN_LIMIT <span class="op">=</span> <span class="dv">9000</span><span class="op">;</span> <span class="co">// 90 seconds at 10msec tick</span></span>
  1026. <span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> fridgeTask<span class="op">(</span><span class="dt">char</span> event<span class="op">)</span> <span class="op">{</span></span>
  1027. <span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>fridgeState<span class="op">)</span> <span class="op">{</span></span>
  1028. <span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> FRIDGE_CLOSED<span class="op">:</span></span>
  1029. <span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_OPEN<span class="op">)</span> <span class="op">{</span></span>
  1030. <span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a> set_io<span class="op">(</span>LIGHT<span class="op">,</span> ON<span class="op">);</span></span>
  1031. <span id="cb21-10"><a href="#cb21-10" aria-hidden="true" tabindex="-1"></a> fridgeTimer <span class="op">=</span> FRIDGE_OPEN_LIMIT<span class="op">;</span></span>
  1032. <span id="cb21-11"><a href="#cb21-11" aria-hidden="true" tabindex="-1"></a> fridgeState <span class="op">=</span> FRIDGE_OPEN<span class="op">;</span></span>
  1033. <span id="cb21-12"><a href="#cb21-12" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1034. <span id="cb21-13"><a href="#cb21-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1035. <span id="cb21-14"><a href="#cb21-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> FRIDGE_OPEN<span class="op">:</span></span>
  1036. <span id="cb21-15"><a href="#cb21-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_CLOSE<span class="op">)</span> <span class="op">{</span></span>
  1037. <span id="cb21-16"><a href="#cb21-16" aria-hidden="true" tabindex="-1"></a> set_io<span class="op">(</span>LIGHT<span class="op">,</span> OFF<span class="op">);</span></span>
  1038. <span id="cb21-17"><a href="#cb21-17" aria-hidden="true" tabindex="-1"></a> fridgeState <span class="op">=</span> FRIDGE_CLOSED<span class="op">;</span></span>
  1039. <span id="cb21-18"><a href="#cb21-18" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1040. <span id="cb21-19"><a href="#cb21-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  1041. <span id="cb21-20"><a href="#cb21-20" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(--</span>fridgeTimer <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
  1042. <span id="cb21-21"><a href="#cb21-21" aria-hidden="true" tabindex="-1"></a> set_io<span class="op">(</span>ALARM<span class="op">,</span> ON<span class="op">);</span></span>
  1043. <span id="cb21-22"><a href="#cb21-22" aria-hidden="true" tabindex="-1"></a> fridgeState <span class="op">=</span> FRIDGE_BEEPING<span class="op">;</span></span>
  1044. <span id="cb21-23"><a href="#cb21-23" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1045. <span id="cb21-24"><a href="#cb21-24" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1046. <span id="cb21-25"><a href="#cb21-25" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1047. <span id="cb21-26"><a href="#cb21-26" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> FRIDGE_BEEPING<span class="op">:</span></span>
  1048. <span id="cb21-27"><a href="#cb21-27" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_CLOSE<span class="op">)</span> <span class="op">{</span></span>
  1049. <span id="cb21-28"><a href="#cb21-28" aria-hidden="true" tabindex="-1"></a> set_io<span class="op">(</span>ALARM<span class="op">,</span> OFF<span class="op">);</span></span>
  1050. <span id="cb21-29"><a href="#cb21-29" aria-hidden="true" tabindex="-1"></a> set_io<span class="op">(</span>LIGHT<span class="op">,</span> OFF<span class="op">);</span></span>
  1051. <span id="cb21-30"><a href="#cb21-30" aria-hidden="true" tabindex="-1"></a> fridgeState <span class="op">=</span> FRIDGE_CLOSED<span class="op">;</span></span>
  1052. <span id="cb21-31"><a href="#cb21-31" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1053. <span id="cb21-32"><a href="#cb21-32" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1054. <span id="cb21-33"><a href="#cb21-33" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1055. <span id="cb21-34"><a href="#cb21-34" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  1056. <h4 id="refactor-for-changestate">Refactor for
  1057. <code>changeState()</code></h4>
  1058. <p>Notice on the state diagram, the arrows heads and tails cluster, and
  1059. similar actions happen for multiple arrows. Perhaps we should write a
  1060. function that just deals with all the actions required when leaving or
  1061. entering a state. Then the task code would only have to manage the
  1062. <em>arrows</em> of the state diagram. Like this:</p>
  1063. <div class="sourceCode" id="cb22"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="co">// this outer code deals with the arrows on the state diagram</span></span>
  1064. <span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> fridgeTask<span class="op">(</span><span class="dt">char</span> event<span class="op">)</span> <span class="op">{</span></span>
  1065. <span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span> <span class="op">(</span>fridgeState<span class="op">)</span> <span class="op">{</span></span>
  1066. <span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> FRIDGE_CLOSED<span class="op">:</span></span>
  1067. <span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_OPEN<span class="op">)</span> changeFridgeState<span class="op">(</span>FRIDGE_OPEN<span class="op">);</span></span>
  1068. <span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1069. <span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> FRIDGE_OPEN<span class="op">:</span></span>
  1070. <span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_CLOSE<span class="op">)</span> changeFridgeState<span class="op">(</span>FRIDGE_CLOSED<span class="op">);</span></span>
  1071. <span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_FRIDGE_TIMEOUT<span class="op">)</span> changeFridgeState<span class="op">(</span>FRIDGE_BEEPING<span class="op">);</span></span>
  1072. <span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1073. <span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> FRIDGE_BEEPING<span class="op">:</span></span>
  1074. <span id="cb22-12"><a href="#cb22-12" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_CLOSE<span class="op">)</span> changeFridgeState<span class="op">(</span>FRIDGE_CLOSED<span class="op">);</span></span>
  1075. <span id="cb22-13"><a href="#cb22-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1076. <span id="cb22-14"><a href="#cb22-14" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1077. <span id="cb22-15"><a href="#cb22-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  1078. <p>while the inner code deals with the actions required for
  1079. <em>entry</em> and <em>exit</em> from each state</p>
  1080. <div class="sourceCode" id="cb23"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> changeFridgeState<span class="op">(</span><span class="dt">char</span> newState<span class="op">)</span> <span class="op">{</span></span>
  1081. <span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">static</span> <span class="dt">char</span> oldState <span class="op">=</span> FRIDGE_CLOSED<span class="op">;</span></span>
  1082. <span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a> <span class="co">// do all the state-leaving actions</span></span>
  1083. <span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>oldState<span class="op">)</span> <span class="op">{</span></span>
  1084. <span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> FRIDGE_CLOSED<span class="op">:</span></span>
  1085. <span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a> set_io<span class="op">(</span>LIGHT<span class="op">,</span> ON<span class="op">);</span></span>
  1086. <span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a> setTimer<span class="op">(</span>FRIDGE_TIMER<span class="op">,</span> FRIDGE_OPEN_LIMIT<span class="op">);</span></span>
  1087. <span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1088. <span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> FRIDGE_OPEN<span class="op">:</span></span>
  1089. <span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1090. <span id="cb23-11"><a href="#cb23-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> FRIDGE_BEEPING<span class="op">:</span></span>
  1091. <span id="cb23-12"><a href="#cb23-12" aria-hidden="true" tabindex="-1"></a> set_io<span class="op">(</span>ALARM<span class="op">,</span> OFF<span class="op">);</span></span>
  1092. <span id="cb23-13"><a href="#cb23-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1093. <span id="cb23-14"><a href="#cb23-14" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1094. <span id="cb23-15"><a href="#cb23-15" aria-hidden="true" tabindex="-1"></a> <span class="co">// change state</span></span>
  1095. <span id="cb23-16"><a href="#cb23-16" aria-hidden="true" tabindex="-1"></a> fridgeState <span class="op">=</span> oldState <span class="op">=</span> newState<span class="op">;</span></span>
  1096. <span id="cb23-17"><a href="#cb23-17" aria-hidden="true" tabindex="-1"></a> <span class="co">// and do the state-entry code</span></span>
  1097. <span id="cb23-18"><a href="#cb23-18" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>newState<span class="op">)</span> <span class="op">{</span></span>
  1098. <span id="cb23-19"><a href="#cb23-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> FRIDGE_CLOSED<span class="op">:</span></span>
  1099. <span id="cb23-20"><a href="#cb23-20" aria-hidden="true" tabindex="-1"></a> set_io<span class="op">(</span>LIGHT<span class="op">,</span> OFF<span class="op">);</span></span>
  1100. <span id="cb23-21"><a href="#cb23-21" aria-hidden="true" tabindex="-1"></a> setTimer<span class="op">(</span>FRIDGE_TIMER<span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
  1101. <span id="cb23-22"><a href="#cb23-22" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1102. <span id="cb23-23"><a href="#cb23-23" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> FRIDGE_OPEN<span class="op">:</span></span>
  1103. <span id="cb23-24"><a href="#cb23-24" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1104. <span id="cb23-25"><a href="#cb23-25" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> FRIDGE_BEEPING<span class="op">:</span></span>
  1105. <span id="cb23-26"><a href="#cb23-26" aria-hidden="true" tabindex="-1"></a> set_io<span class="op">(</span>ALARM<span class="op">,</span> ON<span class="op">);</span></span>
  1106. <span id="cb23-27"><a href="#cb23-27" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1107. <span id="cb23-28"><a href="#cb23-28" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1108. <span id="cb23-29"><a href="#cb23-29" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  1109. <h3 id="door-opener">Door Opener</h3>
  1110. <p>Suppose we have a power lock on a door, using a solenoid, and an RFID
  1111. tag detector on the “outside” and a push button on the “inside”. There
  1112. is also a WiFi connection to a server, by which we report door openings.
  1113. When the RFID tag sends us a message, it will contain a serial number.
  1114. If the number matches a known record, then operate the door-opener
  1115. solenoid for 4 seconds. If the “inside” button is pushed, operate the
  1116. door-opener for 4 seconds; if the “inside” button is pressed during the
  1117. 4 seconds, restart the 4 second timer.</p>
  1118. <p>After the door is locked, send a report to the master control via the
  1119. WiFi.</p>
  1120. <p>Here’s the state diagram:</p>
  1121. <figure>
  1122. <img src="door.png" alt="RFID operated door lock" />
  1123. <figcaption aria-hidden="true">RFID operated door lock</figcaption>
  1124. </figure>
  1125. <p>I use <code>EVT_</code> type events to indicate that they originate
  1126. in hardware, probably at the interrupt level; and <code>MSG_</code> type
  1127. events to indicate they come from a software source, perhaps a sibling
  1128. task.</p>
  1129. <p>Suppose now that the serial number needs to be verified by a central
  1130. service. So when an RFID tag is detected, send a request to the master
  1131. control and wait for an ACK or NAK response. In the case of an ACK, open
  1132. the door solenoid for 4 seconds. The rest of the problem is as stated
  1133. above.</p>
  1134. <p>Here’s the modified state diagram:</p>
  1135. <figure>
  1136. <img src="door2.png" alt="RFID operated door, with remove key verify" />
  1137. <figcaption aria-hidden="true">RFID operated door, with remove key
  1138. verify</figcaption>
  1139. </figure>
  1140. <h3 id="beer-vat">Beer Vat</h3>
  1141. <p>Suppose we have to move a servo motor to lift the lid from a brewing
  1142. vat, to release excess pressure.</p>
  1143. <p>Inputs: pressure valve, manual operation button Outputs: servo, LED,
  1144. beeper</p>
  1145. <p>If high pressure is detected, flash the LED for 10 seconds, then
  1146. operate the beeper for 5 seconds, then operate servo; hold it open for 5
  1147. seconds and return the servo, LED and beeper to idle.</p>
  1148. <p>If the manual operation button is pressed, go directly to “operate
  1149. servo” as above. <img src="beer_vat.png"
  1150. alt="state machine for beer vat pressure release valve" /></p>
  1151. <p>If the manual button is pressed while the lid is open, close
  1152. immediately.</p>
  1153. <h3 id="vending-machine">Vending Machine</h3>
  1154. <p>When idle, wait for payment tap. If selection button is pressed
  1155. before payment, display cost to inform the user for 3 seconds.</p>
  1156. <p>After payment tap, request the user select item.</p>
  1157. <p>Operate dispense motor.</p>
  1158. <p>Wait for object to be removed from output bin.</p>
  1159. <figure>
  1160. <img src="vending.png" alt="states for vending machine" />
  1161. <figcaption aria-hidden="true">states for vending machine</figcaption>
  1162. </figure>
  1163. <h2 id="events-1">Events</h2>
  1164. <p>In all the above, events were implemented as a simple
  1165. <code>unsigned char</code>, allowing 255 different event types.</p>
  1166. <p>There’s no reason we couldn’t use an <code>unsigned short</code> or
  1167. even an <code>int</code>. Further, a 16 bit event number could be
  1168. designed to be 8 bits of event type, and 8 bits of supplementary event
  1169. information:</p>
  1170. <div class="sourceCode" id="cb24"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">typedef</span> <span class="kw">struct</span> Event <span class="op">{</span></span>
  1171. <span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">unsigned</span> <span class="dt">char</span> type<span class="op">;</span></span>
  1172. <span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">unsigned</span> <span class="dt">char</span> info<span class="op">;</span></span>
  1173. <span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> Event<span class="op">;</span></span>
  1174. <span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a></span>
  1175. <span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a>Event e <span class="op">=</span> <span class="op">{</span>MSG_KEYPRESS<span class="op">,</span> KEY_A<span class="op">};</span></span></code></pre></div>
  1176. <p>In the old Windows system, <em>events/messages</em> were realized as
  1177. a 16 bit number, with an extra 32 bit number glued to it for extra
  1178. information.</p>
  1179. <div class="sourceCode" id="cb25"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="kw">typedef</span> <span class="kw">struct</span> MSG <span class="op">{</span></span>
  1180. <span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a> UINT message<span class="op">;</span></span>
  1181. <span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a> LPARAM lParam<span class="op">;</span></span>
  1182. <span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a><span class="op">};</span> <span class="co">// some extra detail removed</span></span></code></pre></div>
  1183. For example, <code>WM_CHAR=0x0102</code> indicates that a key was
  1184. pressed, with the extra 32bit <code>lParam</code> carrying the
  1185. information about <em>which</em> key.
  1186. <hr>
  1187. <h2 id="timers">Timers</h2>
  1188. <p>The simplest state timer is made with a static variable associated
  1189. with the state code.</p>
  1190. <p>To start the timer, simply initialize the static variable. On timer
  1191. ticks, decrement (or increment if you prefer) this variable until it
  1192. hits a limit, and then make a state change.</p>
  1193. <p>For instance, to create a timer that waits 100 timer ticks, you could
  1194. use:</p>
  1195. <div class="sourceCode" id="cb26"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">int</span> state<span class="op">;</span></span>
  1196. <span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">int</span> stateTimer<span class="op">;</span></span>
  1197. <span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> stateCode<span class="op">(</span><span class="dt">char</span> event<span class="op">)</span> <span class="op">{</span></span>
  1198. <span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>state<span class="op">)</span> <span class="op">{</span></span>
  1199. <span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> STATE_IDLE<span class="op">:</span></span>
  1200. <span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">=</span> EVENT_TRIGGER<span class="op">)</span> <span class="op">{</span></span>
  1201. <span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a> stateTimer <span class="op">=</span> <span class="dv">100</span><span class="op">;</span></span>
  1202. <span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a> state <span class="op">=</span> STATE_DELAY<span class="op">;</span></span>
  1203. <span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1204. <span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1205. <span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> STATE_DELAY<span class="op">:</span></span>
  1206. <span id="cb26-12"><a href="#cb26-12" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">=</span> EVENT_TICK<span class="op">)</span> <span class="op">{</span></span>
  1207. <span id="cb26-13"><a href="#cb26-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(--</span>stateTimer <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
  1208. <span id="cb26-14"><a href="#cb26-14" aria-hidden="true" tabindex="-1"></a> <span class="co">// the timer is finished</span></span>
  1209. <span id="cb26-15"><a href="#cb26-15" aria-hidden="true" tabindex="-1"></a> state <span class="op">=</span> STATE_NEXT<span class="op">;</span></span>
  1210. <span id="cb26-16"><a href="#cb26-16" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1211. <span id="cb26-17"><a href="#cb26-17" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1212. <span id="cb26-18"><a href="#cb26-18" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1213. <span id="cb26-19"><a href="#cb26-19" aria-hidden="true" tabindex="-1"></a> <span class="co">// ....</span></span>
  1214. <span id="cb26-20"><a href="#cb26-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1215. <span id="cb26-21"><a href="#cb26-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  1216. <span id="cb26-22"><a href="#cb26-22" aria-hidden="true" tabindex="-1"></a></span>
  1217. <span id="cb26-23"><a href="#cb26-23" aria-hidden="true" tabindex="-1"></a></span>
  1218. <span id="cb26-24"><a href="#cb26-24" aria-hidden="true" tabindex="-1"></a>In the above example<span class="op">,</span> you could equally well have set the timer to start at zero</span>
  1219. <span id="cb26-25"><a href="#cb26-25" aria-hidden="true" tabindex="-1"></a>and increment until it hits the desired limit <span class="op">(</span><span class="dv">100</span> in this <span class="cf">case</span><span class="op">).</span></span>
  1220. <span id="cb26-26"><a href="#cb26-26" aria-hidden="true" tabindex="-1"></a></span>
  1221. <span id="cb26-27"><a href="#cb26-27" aria-hidden="true" tabindex="-1"></a>In a moderate sized project<span class="op">,</span> timers like this will proliferate throughout the code<span class="op">,</span></span>
  1222. <span id="cb26-28"><a href="#cb26-28" aria-hidden="true" tabindex="-1"></a>making it awkward to read<span class="op">.</span> One solution to this is to centralize the timers<span class="op">.</span></span>
  1223. <span id="cb26-29"><a href="#cb26-29" aria-hidden="true" tabindex="-1"></a></span>
  1224. <span id="cb26-30"><a href="#cb26-30" aria-hidden="true" tabindex="-1"></a>In all the above examples<span class="op">,</span> the `timer_irq<span class="op">()</span>` code is trivial<span class="op">,</span> just `newEvent<span class="op">(</span>EVT_TICK<span class="op">)</span>`<span class="op">.</span></span>
  1225. <span id="cb26-31"><a href="#cb26-31" aria-hidden="true" tabindex="-1"></a>Suppose we add code to the `timer_irq<span class="op">()</span>` so that it can process timer counting on</span>
  1226. <span id="cb26-32"><a href="#cb26-32" aria-hidden="true" tabindex="-1"></a>behalf of the tasks<span class="op">......</span></span>
  1227. <span id="cb26-33"><a href="#cb26-33" aria-hidden="true" tabindex="-1"></a></span>
  1228. <span id="cb26-34"><a href="#cb26-34" aria-hidden="true" tabindex="-1"></a><span class="pp">#</span><span class="er">## Timers as a Resource</span></span>
  1229. <span id="cb26-35"><a href="#cb26-35" aria-hidden="true" tabindex="-1"></a></span>
  1230. <span id="cb26-36"><a href="#cb26-36" aria-hidden="true" tabindex="-1"></a>Let<span class="ch">&#39;s</span><span class="er"> create a centralized service called `setTimer(timer_index, timer_count)`. </span></span>
  1231. <span id="cb26-37"><a href="#cb26-37" aria-hidden="true" tabindex="-1"></a></span>
  1232. <span id="cb26-38"><a href="#cb26-38" aria-hidden="true" tabindex="-1"></a>A task can call this service with a unique `timer_index` and a requested count<span class="op">.</span> The</span>
  1233. <span id="cb26-39"><a href="#cb26-39" aria-hidden="true" tabindex="-1"></a>`timer_irq<span class="op">()</span>` will then count out the ticks on behalf of the task<span class="op">,</span> and when the tick</span>
  1234. <span id="cb26-40"><a href="#cb26-40" aria-hidden="true" tabindex="-1"></a>count is finished<span class="op">,</span> the `timer_irq<span class="op">()</span>` code can generate a unique event<span class="op">,</span> perhaps</span>
  1235. <span id="cb26-41"><a href="#cb26-41" aria-hidden="true" tabindex="-1"></a>`EVT_TIMER_n`<span class="op">.</span> </span>
  1236. <span id="cb26-42"><a href="#cb26-42" aria-hidden="true" tabindex="-1"></a></span>
  1237. <span id="cb26-43"><a href="#cb26-43" aria-hidden="true" tabindex="-1"></a>So the state code can then look something like this<span class="op">:</span></span>
  1238. <span id="cb26-44"><a href="#cb26-44" aria-hidden="true" tabindex="-1"></a></span>
  1239. <span id="cb26-45"><a href="#cb26-45" aria-hidden="true" tabindex="-1"></a>```C</span>
  1240. <span id="cb26-46"><a href="#cb26-46" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">int</span> state<span class="op">;</span></span>
  1241. <span id="cb26-47"><a href="#cb26-47" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> stateCode<span class="op">(</span><span class="dt">char</span> event<span class="op">)</span> <span class="op">{</span></span>
  1242. <span id="cb26-48"><a href="#cb26-48" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>state<span class="op">)</span> <span class="op">{</span></span>
  1243. <span id="cb26-49"><a href="#cb26-49" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> STATE_IDLE<span class="op">:</span></span>
  1244. <span id="cb26-50"><a href="#cb26-50" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">=</span> EVENT_TRIGGER<span class="op">)</span> <span class="op">{</span></span>
  1245. <span id="cb26-51"><a href="#cb26-51" aria-hidden="true" tabindex="-1"></a> setTimer<span class="op">(</span>TIMER_1<span class="op">,</span><span class="dv">100</span><span class="op">);</span></span>
  1246. <span id="cb26-52"><a href="#cb26-52" aria-hidden="true" tabindex="-1"></a> state <span class="op">=</span> STATE_DELAY<span class="op">;</span></span>
  1247. <span id="cb26-53"><a href="#cb26-53" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1248. <span id="cb26-54"><a href="#cb26-54" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1249. <span id="cb26-55"><a href="#cb26-55" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> STATE_DELAY<span class="op">:</span></span>
  1250. <span id="cb26-56"><a href="#cb26-56" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">=</span> EVENT_TIMER_1<span class="op">)</span> <span class="op">{</span></span>
  1251. <span id="cb26-57"><a href="#cb26-57" aria-hidden="true" tabindex="-1"></a> <span class="co">// the timer is finished</span></span>
  1252. <span id="cb26-58"><a href="#cb26-58" aria-hidden="true" tabindex="-1"></a> state <span class="op">=</span> STATE_NEXT<span class="op">;</span></span>
  1253. <span id="cb26-59"><a href="#cb26-59" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1254. <span id="cb26-60"><a href="#cb26-60" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1255. <span id="cb26-61"><a href="#cb26-61" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1256. <span id="cb26-62"><a href="#cb26-62" aria-hidden="true" tabindex="-1"></a> <span class="co">// ....</span></span>
  1257. <span id="cb26-63"><a href="#cb26-63" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1258. <span id="cb26-64"><a href="#cb26-64" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  1259. <p>This makes the state code much simpler to read, hiding all the
  1260. increments/decrements and limit testing.</p>
  1261. <p>The overhead for this ends up in the <code>timer_irq()</code> code,
  1262. and might look something like this:</p>
  1263. <div class="sourceCode" id="cb27"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">unsigned</span> <span class="dt">int</span> timers<span class="op">[</span>NUM_TIMERS<span class="op">];</span></span>
  1264. <span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#define EVT_TIMER_OFFSET </span><span class="dv">100</span></span>
  1265. <span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span>EVENT_TIMER_1<span class="op">=</span>EVT_TIMER_OFFSET<span class="op">,</span> EVENT_TIMER_2<span class="op">,</span> EVENT_TIMER_3<span class="op">};</span> <span class="co">// 100, 101...</span></span>
  1266. <span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span>TIMER_1<span class="op">,</span> TIMER_2<span class="op">,</span> TIMER_3<span class="op">};</span> <span class="co">// 0,1,2,....</span></span>
  1267. <span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a></span>
  1268. <span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> timer_irq<span class="op">()</span> <span class="op">{</span></span>
  1269. <span id="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a> newEvent<span class="op">(</span>EVT_TICK<span class="op">);</span> <span class="co">// the main tick, fires every time</span></span>
  1270. <span id="cb27-8"><a href="#cb27-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span>i<span class="op">=</span><span class="dv">0</span><span class="op">;</span> i<span class="op">&lt;</span>NUM_TIMERS<span class="op">)</span> <span class="op">{</span> <span class="co">// the system timers, fires on completion</span></span>
  1271. <span id="cb27-9"><a href="#cb27-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>timers<span class="op">[</span>i<span class="op">]&gt;</span><span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
  1272. <span id="cb27-10"><a href="#cb27-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(--</span>timers<span class="op">[</span>i<span class="op">]==</span><span class="dv">0</span><span class="op">)</span></span>
  1273. <span id="cb27-11"><a href="#cb27-11" aria-hidden="true" tabindex="-1"></a> newEvent<span class="op">(</span>i <span class="op">+</span> EVT_TIMER_OFFSET<span class="op">);</span></span>
  1274. <span id="cb27-12"><a href="#cb27-12" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1275. <span id="cb27-13"><a href="#cb27-13" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1276. <span id="cb27-14"><a href="#cb27-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  1277. <span id="cb27-15"><a href="#cb27-15" aria-hidden="true" tabindex="-1"></a></span>
  1278. <span id="cb27-16"><a href="#cb27-16" aria-hidden="true" tabindex="-1"></a><span class="co">/* common service, available to all tasks */</span></span>
  1279. <span id="cb27-17"><a href="#cb27-17" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> setTimer<span class="op">(</span><span class="dt">int</span> timerIndex<span class="op">,</span> <span class="dt">unsigned</span> <span class="dt">int</span> timerCount<span class="op">)</span> <span class="op">{</span></span>
  1280. <span id="cb27-18"><a href="#cb27-18" aria-hidden="true" tabindex="-1"></a> timers<span class="op">[</span>timerIndex<span class="op">]</span> <span class="op">=</span> timerCount<span class="op">;</span></span>
  1281. <span id="cb27-19"><a href="#cb27-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  1282. <details>
  1283. <summary>
  1284. Reality Check
  1285. </summary>
  1286. <p>On a typical microcontroller running at 24MHz, with 5 timers, this
  1287. adds about 2 microseconds of extra time to the <code>timer_irq()</code>
  1288. code, which typically runs every 10 or 100msec. It considerably
  1289. simplifies the task code, makes it more legible and probably reduces
  1290. bugs that may appear by duplication of code.</p>
  1291. <p>Another possible design for timers is to have the main
  1292. <code>timer_isr()</code> increment a global atomic
  1293. <code>voloatile int timer</code> variable, and the tasks can observe
  1294. this timer and set a target based on that.</p>
  1295. <div class="sourceCode" id="cb28"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="dt">volatile</span> <span class="dt">int</span> timer<span class="op">;</span> <span class="co">// on most microcontrollers, access to an int</span></span>
  1296. <span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a> <span class="co">// will be atomic</span></span>
  1297. <span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a>INTERRUPT timer_isr<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
  1298. <span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a> timer<span class="op">++;</span></span>
  1299. <span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a> newEvent<span class="op">(</span>EVT_TICK<span class="op">);</span></span>
  1300. <span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  1301. <span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a></span>
  1302. <span id="cb28-8"><a href="#cb28-8" aria-hidden="true" tabindex="-1"></a><span class="co">// .... state code ...</span></span>
  1303. <span id="cb28-9"><a href="#cb28-9" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">int</span> targetTime<span class="op">;</span></span>
  1304. <span id="cb28-10"><a href="#cb28-10" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> stateCode<span class="op">(</span>uint8 event<span class="op">)</span> <span class="op">{</span></span>
  1305. <span id="cb28-11"><a href="#cb28-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>state<span class="op">)</span> <span class="op">{</span></span>
  1306. <span id="cb28-12"><a href="#cb28-12" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> STATE1<span class="op">:</span></span>
  1307. <span id="cb28-13"><a href="#cb28-13" aria-hidden="true" tabindex="-1"></a> <span class="co">//..... set a target</span></span>
  1308. <span id="cb28-14"><a href="#cb28-14" aria-hidden="true" tabindex="-1"></a> targetTimer <span class="op">=</span> time <span class="op">+</span> DELAY_TIME<span class="op">;</span></span>
  1309. <span id="cb28-15"><a href="#cb28-15" aria-hidden="true" tabindex="-1"></a> state <span class="op">=</span> state2<span class="op">;</span></span>
  1310. <span id="cb28-16"><a href="#cb28-16" aria-hidden="true" tabindex="-1"></a> <span class="co">//.....</span></span>
  1311. <span id="cb28-17"><a href="#cb28-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> STATE2<span class="op">:</span></span>
  1312. <span id="cb28-18"><a href="#cb28-18" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  1313. <span id="cb28-19"><a href="#cb28-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>time <span class="op">==</span> targetTimer<span class="op">)</span> <span class="op">{</span></span>
  1314. <span id="cb28-20"><a href="#cb28-20" aria-hidden="true" tabindex="-1"></a> <span class="co">//.... we&#39;ve waited long enough</span></span>
  1315. <span id="cb28-21"><a href="#cb28-21" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1316. <span id="cb28-22"><a href="#cb28-22" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1317. <span id="cb28-23"><a href="#cb28-23" aria-hidden="true" tabindex="-1"></a> <span class="co">//...</span></span>
  1318. <span id="cb28-24"><a href="#cb28-24" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1319. <span id="cb28-25"><a href="#cb28-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  1320. </details>
  1321. <h2 id="real-code">Real Code</h2>
  1322. <p>Here is an example of a complete and tested project on a small
  1323. STM32F030 board. Open all the little arrows to see the complete
  1324. code.</p>
  1325. <details>
  1326. <summary>
  1327. board specific defines
  1328. </summary>
  1329. <div class="sourceCode" id="cb29"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&quot;stm32f030.h&quot;</span></span>
  1330. <span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a></span>
  1331. <span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a><span class="co">/****** project hardware ******/</span></span>
  1332. <span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a><span class="co">// on this demo board, there is a push button on PB13 and</span></span>
  1333. <span id="cb29-5"><a href="#cb29-5" aria-hidden="true" tabindex="-1"></a><span class="co">// an LED on PA4 and PF5</span></span>
  1334. <span id="cb29-6"><a href="#cb29-6" aria-hidden="true" tabindex="-1"></a></span>
  1335. <span id="cb29-7"><a href="#cb29-7" aria-hidden="true" tabindex="-1"></a><span class="pp">#define LED </span><span class="bn">0x10</span><span class="pp"> </span><span class="co">// port A bit 4 these LED are LOW=lit-up</span></span>
  1336. <span id="cb29-8"><a href="#cb29-8" aria-hidden="true" tabindex="-1"></a><span class="pp">#define LED2 </span><span class="bn">0x50020</span><span class="pp"> </span><span class="co">// port F bit 5</span></span>
  1337. <span id="cb29-9"><a href="#cb29-9" aria-hidden="true" tabindex="-1"></a>GPIO_TypeDef <span class="op">*</span> GROUP<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span>GPIOA<span class="op">,</span> GPIOB<span class="op">,</span> GPIOC<span class="op">,</span> GPIOD<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> GPIOF<span class="op">};</span> <span class="co">// 0,0x10000,0x20000, etc</span></span>
  1338. <span id="cb29-10"><a href="#cb29-10" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> gpio_set<span class="op">(</span>uint32 bitPosition<span class="op">,</span> <span class="dt">bool</span> value<span class="op">)</span> <span class="op">{</span></span>
  1339. <span id="cb29-11"><a href="#cb29-11" aria-hidden="true" tabindex="-1"></a> vu32<span class="op">*</span> group <span class="op">=</span> <span class="op">&amp;((</span>GROUP<span class="op">[</span>bitPosition <span class="op">&gt;&gt;</span> <span class="dv">16</span><span class="op">])-&gt;</span>ODR<span class="op">);</span></span>
  1340. <span id="cb29-12"><a href="#cb29-12" aria-hidden="true" tabindex="-1"></a> bitPosition <span class="op">&amp;=</span> <span class="bn">0xFFFF</span><span class="op">;</span></span>
  1341. <span id="cb29-13"><a href="#cb29-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>value<span class="op">)</span></span>
  1342. <span id="cb29-14"><a href="#cb29-14" aria-hidden="true" tabindex="-1"></a> <span class="op">*</span>group <span class="op">|=</span> bitPosition<span class="op">;</span></span>
  1343. <span id="cb29-15"><a href="#cb29-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span></span>
  1344. <span id="cb29-16"><a href="#cb29-16" aria-hidden="true" tabindex="-1"></a> <span class="op">*</span>group <span class="op">&amp;=</span> <span class="op">~</span>bitPosition<span class="op">;</span></span>
  1345. <span id="cb29-17"><a href="#cb29-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  1346. </details>
  1347. <div class="sourceCode" id="cb30"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="co">/***** events ****/</span></span>
  1348. <span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#define NUM_EVENTS </span><span class="dv">10</span></span>
  1349. <span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a><span class="dt">volatile</span> uint8 events<span class="op">[</span>NUM_EVENTS<span class="op">];</span></span>
  1350. <span id="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span> EVT_NONE<span class="op">,</span></span>
  1351. <span id="cb30-5"><a href="#cb30-5" aria-hidden="true" tabindex="-1"></a> EVT_TICK<span class="op">,</span></span>
  1352. <span id="cb30-6"><a href="#cb30-6" aria-hidden="true" tabindex="-1"></a> EVT_BUTTON<span class="op">};</span></span>
  1353. <span id="cb30-7"><a href="#cb30-7" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> newEvent<span class="op">(</span>uint8 e<span class="op">);</span></span>
  1354. <span id="cb30-8"><a href="#cb30-8" aria-hidden="true" tabindex="-1"></a></span>
  1355. <span id="cb30-9"><a href="#cb30-9" aria-hidden="true" tabindex="-1"></a><span class="co">/********** tasks ***********/</span></span>
  1356. <span id="cb30-10"><a href="#cb30-10" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> ledTask<span class="op">(</span>uint8 evt<span class="op">);</span></span>
  1357. <span id="cb30-11"><a href="#cb30-11" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> respondToButtonTask<span class="op">(</span>uint8 evt<span class="op">);</span></span>
  1358. <span id="cb30-12"><a href="#cb30-12" aria-hidden="true" tabindex="-1"></a></span>
  1359. <span id="cb30-13"><a href="#cb30-13" aria-hidden="true" tabindex="-1"></a><span class="co">/********** interrupts **************/</span></span>
  1360. <span id="cb30-14"><a href="#cb30-14" aria-hidden="true" tabindex="-1"></a><span class="dt">volatile</span> uint32 tick<span class="op">;</span> <span class="co">// increasing at 100 ticks/sec</span></span>
  1361. <span id="cb30-15"><a href="#cb30-15" aria-hidden="true" tabindex="-1"></a> <span class="co">// takes a year to roll-over</span></span>
  1362. <span id="cb30-16"><a href="#cb30-16" aria-hidden="true" tabindex="-1"></a></span>
  1363. <span id="cb30-17"><a href="#cb30-17" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> timer_isr<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
  1364. <span id="cb30-18"><a href="#cb30-18" aria-hidden="true" tabindex="-1"></a> tick<span class="op">++;</span></span>
  1365. <span id="cb30-19"><a href="#cb30-19" aria-hidden="true" tabindex="-1"></a> newEvent<span class="op">(</span>EVT_TICK<span class="op">);</span></span>
  1366. <span id="cb30-20"><a href="#cb30-20" aria-hidden="true" tabindex="-1"></a> <span class="co">// this interrupt is auto-ack&#39;d</span></span>
  1367. <span id="cb30-21"><a href="#cb30-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  1368. <span id="cb30-22"><a href="#cb30-22" aria-hidden="true" tabindex="-1"></a></span>
  1369. <span id="cb30-23"><a href="#cb30-23" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> button_isr<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
  1370. <span id="cb30-24"><a href="#cb30-24" aria-hidden="true" tabindex="-1"></a> newEvent<span class="op">(</span>EVT_BUTTON<span class="op">);</span></span>
  1371. <span id="cb30-25"><a href="#cb30-25" aria-hidden="true" tabindex="-1"></a> EXTI<span class="op">-&gt;</span>PR <span class="op">|=</span> <span class="bn">0x3001</span><span class="op">;</span> <span class="co">// ack it </span></span>
  1372. <span id="cb30-26"><a href="#cb30-26" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  1373. <span id="cb30-27"><a href="#cb30-27" aria-hidden="true" tabindex="-1"></a></span>
  1374. <span id="cb30-28"><a href="#cb30-28" aria-hidden="true" tabindex="-1"></a><span class="co">/** newEvent</span></span>
  1375. <span id="cb30-29"><a href="#cb30-29" aria-hidden="true" tabindex="-1"></a><span class="co"> * add the event to the event queue</span></span>
  1376. <span id="cb30-30"><a href="#cb30-30" aria-hidden="true" tabindex="-1"></a><span class="co"> * wrapped in critical section</span></span>
  1377. <span id="cb30-31"><a href="#cb30-31" aria-hidden="true" tabindex="-1"></a><span class="co"> * </span></span>
  1378. <span id="cb30-32"><a href="#cb30-32" aria-hidden="true" tabindex="-1"></a><span class="co"> * </span><span class="an">@param</span><span class="co"> </span><span class="cv">the</span><span class="co"> event</span></span>
  1379. <span id="cb30-33"><a href="#cb30-33" aria-hidden="true" tabindex="-1"></a><span class="co"> */</span></span>
  1380. <span id="cb30-34"><a href="#cb30-34" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> newEvent<span class="op">(</span><span class="dt">char</span> e<span class="op">)</span> <span class="op">{</span></span>
  1381. <span id="cb30-35"><a href="#cb30-35" aria-hidden="true" tabindex="-1"></a> <span class="dt">static</span> uint nextEvent<span class="op">;</span></span>
  1382. <span id="cb30-36"><a href="#cb30-36" aria-hidden="true" tabindex="-1"></a> dint<span class="op">();</span> <span class="co">// critical section</span></span>
  1383. <span id="cb30-37"><a href="#cb30-37" aria-hidden="true" tabindex="-1"></a> events<span class="op">[</span>nextEvent<span class="op">++]</span> <span class="op">=</span> e<span class="op">;</span></span>
  1384. <span id="cb30-38"><a href="#cb30-38" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>nextEvent<span class="op">==</span>NUM_EVENTS<span class="op">)</span></span>
  1385. <span id="cb30-39"><a href="#cb30-39" aria-hidden="true" tabindex="-1"></a> nextEvent <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  1386. <span id="cb30-40"><a href="#cb30-40" aria-hidden="true" tabindex="-1"></a> eint<span class="op">();</span></span>
  1387. <span id="cb30-41"><a href="#cb30-41" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  1388. </details>
  1389. <details>
  1390. <summary>
  1391. hardware initialization
  1392. </summary>
  1393. <div class="sourceCode" id="cb31"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="co">/***** init ******/</span></span>
  1394. <span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a><span class="co">/* called by newlib startup */</span></span>
  1395. <span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> _init<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
  1396. <span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// startup code</span></span>
  1397. <span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a></span>
  1398. <span id="cb31-6"><a href="#cb31-6" aria-hidden="true" tabindex="-1"></a> <span class="co">// use default clocks</span></span>
  1399. <span id="cb31-7"><a href="#cb31-7" aria-hidden="true" tabindex="-1"></a> <span class="co">// turn on all the GPIO&#39;s</span></span>
  1400. <span id="cb31-8"><a href="#cb31-8" aria-hidden="true" tabindex="-1"></a> RCC<span class="op">-&gt;</span>AHBENR <span class="op">=</span> <span class="bn">0x005e0014</span><span class="op">;</span></span>
  1401. <span id="cb31-9"><a href="#cb31-9" aria-hidden="true" tabindex="-1"></a> <span class="co">// enable SysCfg</span></span>
  1402. <span id="cb31-10"><a href="#cb31-10" aria-hidden="true" tabindex="-1"></a> RCC<span class="op">-&gt;</span>APB2ENR <span class="op">=</span> <span class="bn">0x00004801</span><span class="op">;</span></span>
  1403. <span id="cb31-11"><a href="#cb31-11" aria-hidden="true" tabindex="-1"></a></span>
  1404. <span id="cb31-12"><a href="#cb31-12" aria-hidden="true" tabindex="-1"></a></span>
  1405. <span id="cb31-13"><a href="#cb31-13" aria-hidden="true" tabindex="-1"></a> <span class="co">// enable the two LEDs as outputs</span></span>
  1406. <span id="cb31-14"><a href="#cb31-14" aria-hidden="true" tabindex="-1"></a> GPIOA<span class="op">-&gt;</span>MODER <span class="op">=</span> <span class="op">(</span>GPIOA<span class="op">-&gt;</span>MODER <span class="op">&amp;</span> <span class="bn">0xFFFFFCFF</span><span class="op">)</span> <span class="op">|</span> <span class="bn">0x00000100</span><span class="op">;</span> <span class="co">// port A bit 4</span></span>
  1407. <span id="cb31-15"><a href="#cb31-15" aria-hidden="true" tabindex="-1"></a> GPIOF<span class="op">-&gt;</span>MODER <span class="op">=</span> <span class="op">(</span>GPIOF<span class="op">-&gt;</span>MODER <span class="op">&amp;</span> <span class="bn">0xFFFFF3FF</span><span class="op">)</span> <span class="op">|</span> <span class="bn">0x00000400</span><span class="op">;</span> <span class="co">// port F bit 5</span></span>
  1408. <span id="cb31-16"><a href="#cb31-16" aria-hidden="true" tabindex="-1"></a> <span class="co">// and the push button as input + pulldown</span></span>
  1409. <span id="cb31-17"><a href="#cb31-17" aria-hidden="true" tabindex="-1"></a> GPIOB<span class="op">-&gt;</span>PUPDR <span class="op">=</span> <span class="op">(</span>GPIOB<span class="op">-&gt;</span>PUPDR <span class="op">&amp;</span> <span class="bn">0xF3FFFFFF</span><span class="op">)</span> <span class="op">|</span> <span class="bn">0x08000000</span><span class="op">;</span> <span class="co">// pulldown on 13</span></span>
  1410. <span id="cb31-18"><a href="#cb31-18" aria-hidden="true" tabindex="-1"></a></span>
  1411. <span id="cb31-19"><a href="#cb31-19" aria-hidden="true" tabindex="-1"></a> <span class="co">// keep the clocking system simple: just use the 8MHz HSI everywhere</span></span>
  1412. <span id="cb31-20"><a href="#cb31-20" aria-hidden="true" tabindex="-1"></a> SysTick<span class="op">-&gt;</span>LOAD <span class="op">=</span> <span class="dv">10000</span><span class="op">;</span> <span class="co">// 10 msec</span></span>
  1413. <span id="cb31-21"><a href="#cb31-21" aria-hidden="true" tabindex="-1"></a> SysTick<span class="op">-&gt;</span>VAL <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  1414. <span id="cb31-22"><a href="#cb31-22" aria-hidden="true" tabindex="-1"></a> SysTick<span class="op">-&gt;</span>CTRL <span class="op">=</span> <span class="dv">3</span><span class="op">;</span> <span class="co">// count at 1usec, use interrupts</span></span>
  1415. <span id="cb31-23"><a href="#cb31-23" aria-hidden="true" tabindex="-1"></a> </span>
  1416. <span id="cb31-24"><a href="#cb31-24" aria-hidden="true" tabindex="-1"></a> <span class="co">/* to configure an interrupt on the stm32f0xx,</span></span>
  1417. <span id="cb31-25"><a href="#cb31-25" aria-hidden="true" tabindex="-1"></a><span class="co"> - enable the EXTI-&gt;IMR for the pin</span></span>
  1418. <span id="cb31-26"><a href="#cb31-26" aria-hidden="true" tabindex="-1"></a><span class="co"> - set EXTI-&gt;RTSR for select rising edge</span></span>
  1419. <span id="cb31-27"><a href="#cb31-27" aria-hidden="true" tabindex="-1"></a><span class="co"> - set the SYSCFG-&gt;EXTICRx pin to route it </span></span>
  1420. <span id="cb31-28"><a href="#cb31-28" aria-hidden="true" tabindex="-1"></a><span class="co"> - enable the gating bit in the NVIC register </span></span>
  1421. <span id="cb31-29"><a href="#cb31-29" aria-hidden="true" tabindex="-1"></a><span class="co"> - don&#39;t forget to ack each interrupt at EXTI-&gt;PR</span></span>
  1422. <span id="cb31-30"><a href="#cb31-30" aria-hidden="true" tabindex="-1"></a><span class="co"> */</span></span>
  1423. <span id="cb31-31"><a href="#cb31-31" aria-hidden="true" tabindex="-1"></a> EXTI<span class="op">-&gt;</span>IMR <span class="op">=</span> <span class="bn">0x2000</span><span class="op">;</span> <span class="co">// enable interrupt from line 13</span></span>
  1424. <span id="cb31-32"><a href="#cb31-32" aria-hidden="true" tabindex="-1"></a> EXTI<span class="op">-&gt;</span>RTSR <span class="op">=</span> <span class="bn">0x2000</span><span class="op">;</span> <span class="co">// interrupt on rising edge</span></span>
  1425. <span id="cb31-33"><a href="#cb31-33" aria-hidden="true" tabindex="-1"></a> SYSCFG<span class="op">-&gt;</span>EXTICR<span class="op">[</span><span class="dv">3</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x0010</span><span class="op">;</span> <span class="co">// select prot B for exti-13</span></span>
  1426. <span id="cb31-34"><a href="#cb31-34" aria-hidden="true" tabindex="-1"></a> NVIC<span class="op">-&gt;</span>ISER<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">=</span> <span class="bn">0x00E1</span><span class="op">;</span> <span class="co">// enable in NVIC: gpio &amp; watchdog</span></span>
  1427. <span id="cb31-35"><a href="#cb31-35" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  1428. </details>
  1429. <div class="sourceCode" id="cb32"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> main<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
  1430. <span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a></span>
  1431. <span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a> eint<span class="op">();</span></span>
  1432. <span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a></span>
  1433. <span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a> <span class="co">// dispatcher loop</span></span>
  1434. <span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span><span class="op">(</span><span class="dv">1</span><span class="op">)</span> <span class="op">{</span></span>
  1435. <span id="cb32-7"><a href="#cb32-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> j<span class="op">;</span></span>
  1436. <span id="cb32-8"><a href="#cb32-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> <span class="op">(</span>j<span class="op">=</span><span class="dv">0</span><span class="op">;</span> j<span class="op">&lt;</span>NUM_EVENTS<span class="op">;</span> j<span class="op">++)</span> <span class="op">{</span></span>
  1437. <span id="cb32-9"><a href="#cb32-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span> <span class="op">(</span>events<span class="op">[</span>j<span class="op">]==</span>EVT_NONE<span class="op">)</span></span>
  1438. <span id="cb32-10"><a href="#cb32-10" aria-hidden="true" tabindex="-1"></a> <span class="op">{}</span></span>
  1439. <span id="cb32-11"><a href="#cb32-11" aria-hidden="true" tabindex="-1"></a> ledTask<span class="op">(</span>events<span class="op">[</span>j<span class="op">]);</span></span>
  1440. <span id="cb32-12"><a href="#cb32-12" aria-hidden="true" tabindex="-1"></a> respondToButtonTask<span class="op">(</span>events<span class="op">[</span>j<span class="op">]);</span></span>
  1441. <span id="cb32-13"><a href="#cb32-13" aria-hidden="true" tabindex="-1"></a> events<span class="op">[</span>j<span class="op">]</span> <span class="op">=</span> EVT_NONE<span class="op">;</span></span>
  1442. <span id="cb32-14"><a href="#cb32-14" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1443. <span id="cb32-15"><a href="#cb32-15" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1444. <span id="cb32-16"><a href="#cb32-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  1445. <span id="cb32-17"><a href="#cb32-17" aria-hidden="true" tabindex="-1"></a></span>
  1446. <span id="cb32-18"><a href="#cb32-18" aria-hidden="true" tabindex="-1"></a><span class="co">/*********** task code, with states ************/</span></span>
  1447. <span id="cb32-19"><a href="#cb32-19" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span>LED_ON<span class="op">,</span> LED_OFF<span class="op">};</span></span>
  1448. <span id="cb32-20"><a href="#cb32-20" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span>RTB_IDLE<span class="op">,</span> RTB_ON<span class="op">};</span> <span class="co">// states</span></span>
  1449. <span id="cb32-21"><a href="#cb32-21" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> uint8 rtbState <span class="op">=</span> RTB_IDLE<span class="op">;</span></span>
  1450. <span id="cb32-22"><a href="#cb32-22" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> uint16 rtbTimerCount <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  1451. <span id="cb32-23"><a href="#cb32-23" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> uint16 BUTTON_LED_ON_TIME <span class="op">=</span> <span class="dv">150</span><span class="op">;</span></span>
  1452. <span id="cb32-24"><a href="#cb32-24" aria-hidden="true" tabindex="-1"></a></span>
  1453. <span id="cb32-25"><a href="#cb32-25" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> respondToButtonTask<span class="op">(</span>uint8 evt<span class="op">)</span> <span class="op">{</span></span>
  1454. <span id="cb32-26"><a href="#cb32-26" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>rtbState<span class="op">)</span> <span class="op">{</span></span>
  1455. <span id="cb32-27"><a href="#cb32-27" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> RTB_IDLE<span class="op">:</span></span>
  1456. <span id="cb32-28"><a href="#cb32-28" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_BUTTON<span class="op">)</span> <span class="op">{</span></span>
  1457. <span id="cb32-29"><a href="#cb32-29" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_ON<span class="op">;</span></span>
  1458. <span id="cb32-30"><a href="#cb32-30" aria-hidden="true" tabindex="-1"></a> rtbTimerCount <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  1459. <span id="cb32-31"><a href="#cb32-31" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> LED_ON<span class="op">);</span></span>
  1460. <span id="cb32-32"><a href="#cb32-32" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1461. <span id="cb32-33"><a href="#cb32-33" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1462. <span id="cb32-34"><a href="#cb32-34" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> RTB_ON<span class="op">:</span></span>
  1463. <span id="cb32-35"><a href="#cb32-35" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  1464. <span id="cb32-36"><a href="#cb32-36" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(++</span>rtbTimerCount <span class="op">&gt;</span> BUTTON_LED_ON_TIME<span class="op">)</span> <span class="op">{</span></span>
  1465. <span id="cb32-37"><a href="#cb32-37" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED<span class="op">,</span> LED_OFF<span class="op">);</span></span>
  1466. <span id="cb32-38"><a href="#cb32-38" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_IDLE<span class="op">;</span></span>
  1467. <span id="cb32-39"><a href="#cb32-39" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1468. <span id="cb32-40"><a href="#cb32-40" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1469. <span id="cb32-41"><a href="#cb32-41" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1470. <span id="cb32-42"><a href="#cb32-42" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1471. <span id="cb32-43"><a href="#cb32-43" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  1472. <span id="cb32-44"><a href="#cb32-44" aria-hidden="true" tabindex="-1"></a></span>
  1473. <span id="cb32-45"><a href="#cb32-45" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> uint16 LED_ON_TIME <span class="op">=</span> <span class="dv">150</span><span class="op">;</span></span>
  1474. <span id="cb32-46"><a href="#cb32-46" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> uint16 LED_OFF_TIME <span class="op">=</span> <span class="dv">50</span><span class="op">;</span></span>
  1475. <span id="cb32-47"><a href="#cb32-47" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> uint8 ledState <span class="op">=</span> LED_OFF<span class="op">;</span></span>
  1476. <span id="cb32-48"><a href="#cb32-48" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> uint16 ledTimerCount <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  1477. <span id="cb32-49"><a href="#cb32-49" aria-hidden="true" tabindex="-1"></a></span>
  1478. <span id="cb32-50"><a href="#cb32-50" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> ledTask<span class="op">(</span>uint8 evt<span class="op">)</span> <span class="op">{</span></span>
  1479. <span id="cb32-51"><a href="#cb32-51" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>ledState<span class="op">)</span> <span class="op">{</span></span>
  1480. <span id="cb32-52"><a href="#cb32-52" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> LED_OFF<span class="op">:</span></span>
  1481. <span id="cb32-53"><a href="#cb32-53" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  1482. <span id="cb32-54"><a href="#cb32-54" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(++</span>ledTimerCount <span class="op">&gt;</span> LED_OFF_TIME<span class="op">)</span> <span class="op">{</span></span>
  1483. <span id="cb32-55"><a href="#cb32-55" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED2<span class="op">,</span> LED_ON<span class="op">);</span></span>
  1484. <span id="cb32-56"><a href="#cb32-56" aria-hidden="true" tabindex="-1"></a> ledTimerCount <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  1485. <span id="cb32-57"><a href="#cb32-57" aria-hidden="true" tabindex="-1"></a> ledState <span class="op">=</span> LED_ON<span class="op">;</span></span>
  1486. <span id="cb32-58"><a href="#cb32-58" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1487. <span id="cb32-59"><a href="#cb32-59" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1488. <span id="cb32-60"><a href="#cb32-60" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1489. <span id="cb32-61"><a href="#cb32-61" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> LED_ON<span class="op">:</span></span>
  1490. <span id="cb32-62"><a href="#cb32-62" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>evt <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  1491. <span id="cb32-63"><a href="#cb32-63" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(++</span>ledTimerCount <span class="op">&gt;</span> LED_ON_TIME<span class="op">)</span> <span class="op">{</span></span>
  1492. <span id="cb32-64"><a href="#cb32-64" aria-hidden="true" tabindex="-1"></a> gpio_set<span class="op">(</span>LED2<span class="op">,</span> LED_OFF<span class="op">);</span></span>
  1493. <span id="cb32-65"><a href="#cb32-65" aria-hidden="true" tabindex="-1"></a> ledTimerCount <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  1494. <span id="cb32-66"><a href="#cb32-66" aria-hidden="true" tabindex="-1"></a> ledState <span class="op">=</span> LED_OFF<span class="op">;</span></span>
  1495. <span id="cb32-67"><a href="#cb32-67" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1496. <span id="cb32-68"><a href="#cb32-68" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1497. <span id="cb32-69"><a href="#cb32-69" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1498. <span id="cb32-70"><a href="#cb32-70" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1499. <span id="cb32-71"><a href="#cb32-71" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  1500. <details>
  1501. <summary>
  1502. vector table
  1503. </summary>
  1504. <div class="sourceCode" id="cb33"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="co">/* vector table */</span></span>
  1505. <span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#define STACK_TOP </span><span class="bn">0x20002000</span></span>
  1506. <span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> default_isr<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{}</span></span>
  1507. <span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">void</span> _start<span class="op">(</span><span class="dt">void</span><span class="op">);</span></span>
  1508. <span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a></span>
  1509. <span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> <span class="op">(*</span>myvectors<span class="op">[])(</span><span class="dt">void</span><span class="op">)</span> __attribute__ <span class="op">((</span>section<span class="op">(</span><span class="st">&quot;.vectors&quot;</span><span class="op">)))=</span> <span class="op">{</span></span>
  1510. <span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a> <span class="op">(</span><span class="dt">void</span><span class="op">(*)(</span><span class="dt">void</span><span class="op">))</span> STACK_TOP<span class="op">,</span> <span class="co">// stack pointer</span></span>
  1511. <span id="cb33-8"><a href="#cb33-8" aria-hidden="true" tabindex="-1"></a> _start<span class="op">,</span> <span class="co">// code entry point</span></span>
  1512. <span id="cb33-9"><a href="#cb33-9" aria-hidden="true" tabindex="-1"></a> default_isr<span class="op">,</span> <span class="co">// handle non-maskable interrupts</span></span>
  1513. <span id="cb33-10"><a href="#cb33-10" aria-hidden="true" tabindex="-1"></a> default_isr<span class="op">,</span> <span class="co">// handle hard faults</span></span>
  1514. <span id="cb33-11"><a href="#cb33-11" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span> <span class="co">/* 10...1f */</span></span>
  1515. <span id="cb33-12"><a href="#cb33-12" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span> <span class="co">/* 20...2f */</span></span>
  1516. <span id="cb33-13"><a href="#cb33-13" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span>timer_isr<span class="op">,</span> <span class="co">/* 30...3f */</span></span>
  1517. <span id="cb33-14"><a href="#cb33-14" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span></span>
  1518. <span id="cb33-15"><a href="#cb33-15" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span>button_isr<span class="op">,</span>button_isr<span class="op">,</span>button_isr<span class="op">,</span> <span class="co">/* 50...5f */</span></span>
  1519. <span id="cb33-16"><a href="#cb33-16" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span> <span class="co">/* 60...6f */</span></span>
  1520. <span id="cb33-17"><a href="#cb33-17" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span> <span class="co">/* 70...7f */</span></span>
  1521. <span id="cb33-18"><a href="#cb33-18" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span> <span class="co">/* 80...8f */</span></span>
  1522. <span id="cb33-19"><a href="#cb33-19" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span> <span class="co">/* 90...9f */</span></span>
  1523. <span id="cb33-20"><a href="#cb33-20" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span> <span class="co">/* a0...af */</span></span>
  1524. <span id="cb33-21"><a href="#cb33-21" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span> <span class="co">/* b0...bf */</span></span>
  1525. <span id="cb33-22"><a href="#cb33-22" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span> <span class="co">/* c0...cf */</span></span>
  1526. <span id="cb33-23"><a href="#cb33-23" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span> <span class="co">/* d0...df */</span></span>
  1527. <span id="cb33-24"><a href="#cb33-24" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span> <span class="co">/* e0...ef */</span></span>
  1528. <span id="cb33-25"><a href="#cb33-25" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span> <span class="co">/* f0...ff */</span></span>
  1529. <span id="cb33-26"><a href="#cb33-26" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span> <span class="co">/* 100.10f */</span></span>
  1530. <span id="cb33-27"><a href="#cb33-27" aria-hidden="true" tabindex="-1"></a> <span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span> <span class="co">/* 110.11f */</span></span>
  1531. <span id="cb33-28"><a href="#cb33-28" aria-hidden="true" tabindex="-1"></a><span class="op">};</span></span></code></pre></div>
  1532. </details>
  1533. <h2 id="substates">Substates</h2>
  1534. <p>For things like flashing LED’s, you could create two states, and
  1535. toggle between them, like this:</p>
  1536. <p><img src="rtb_state_4.png" /></p>
  1537. <hr>
  1538. <p>Or, you could simply have an internal (static, not-on-the-stack)
  1539. variable which can keep track of the LED toggle. The state diagram then
  1540. simplifies:</p>
  1541. <div class="sourceCode" id="cb34"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a>uint8 rtbState <span class="op">=</span> RTB_IDLE<span class="op">;</span> <span class="co">// major state, RTB_IDLE/RTB_FLASHING</span></span>
  1542. <span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a>uint8 rtbSubState <span class="op">=</span> RTB_FLASH_OFF<span class="op">;</span> <span class="co">// minor state, toggles LED on/off</span></span></code></pre></div>
  1543. <p>Alternatively, you could use the <em>timer counter</em> variable, and
  1544. make changes at the half-way point through the count. This simplifies
  1545. the substate design to this:</p>
  1546. <p><img src="rtb_state_5.png" class="imageright" /></p>
  1547. <div class="sourceCode" id="cb35"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> uint16 FLASH_CYCLE_TIME <span class="dv">150</span><span class="op">;</span></span>
  1548. <span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> uint16 FLASH_ON_TIME <span class="dv">40</span><span class="op">;</span></span>
  1549. <span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a>uint8 rtbState <span class="op">=</span> STATE_IDLE<span class="op">;</span></span>
  1550. <span id="cb35-4"><a href="#cb35-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> rtbTaskCode<span class="op">(</span><span class="dt">char</span> event<span class="op">)</span> <span class="op">{</span></span>
  1551. <span id="cb35-5"><a href="#cb35-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">static</span> uint16 flashCount<span class="op">=</span><span class="dv">0</span><span class="op">;</span></span>
  1552. <span id="cb35-6"><a href="#cb35-6" aria-hidden="true" tabindex="-1"></a></span>
  1553. <span id="cb35-7"><a href="#cb35-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>taskState<span class="op">)</span> <span class="op">{</span></span>
  1554. <span id="cb35-8"><a href="#cb35-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> RTB_IDLE<span class="op">:</span></span>
  1555. <span id="cb35-9"><a href="#cb35-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_BUTTON<span class="op">)</span> <span class="op">{</span></span>
  1556. <span id="cb35-10"><a href="#cb35-10" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> STATE_FLASHING<span class="op">;</span></span>
  1557. <span id="cb35-11"><a href="#cb35-11" aria-hidden="true" tabindex="-1"></a> flashCount <span class="op">=</span> FLASH_CYCLE_TIME<span class="op">;</span></span>
  1558. <span id="cb35-12"><a href="#cb35-12" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1559. <span id="cb35-13"><a href="#cb35-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1560. <span id="cb35-14"><a href="#cb35-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> STATE_FLASHING<span class="op">:</span></span>
  1561. <span id="cb35-15"><a href="#cb35-15" aria-hidden="true" tabindex="-1"></a> <span class="co">// count down flashCount, toggle LED halfway through</span></span>
  1562. <span id="cb35-16"><a href="#cb35-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  1563. <span id="cb35-17"><a href="#cb35-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(--</span>flashCount <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
  1564. <span id="cb35-18"><a href="#cb35-18" aria-hidden="true" tabindex="-1"></a> setLED<span class="op">(</span>OFF<span class="op">);</span></span>
  1565. <span id="cb35-19"><a href="#cb35-19" aria-hidden="true" tabindex="-1"></a> flashCount <span class="op">=</span> FLASH_CYCLE_TIME<span class="op">;</span></span>
  1566. <span id="cb35-20"><a href="#cb35-20" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>flashCount <span class="op">==</span> FLASH_ON_TIME<span class="op">)</span> <span class="op">{</span></span>
  1567. <span id="cb35-21"><a href="#cb35-21" aria-hidden="true" tabindex="-1"></a> setLED<span class="op">(</span>ON<span class="op">);</span></span>
  1568. <span id="cb35-22"><a href="#cb35-22" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1569. <span id="cb35-23"><a href="#cb35-23" aria-hidden="true" tabindex="-1"></a> <span class="co">// ... make sure to turn LED off when leaving this state</span></span>
  1570. <span id="cb35-24"><a href="#cb35-24" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_BUTTON<span class="op">)</span> <span class="op">{</span></span>
  1571. <span id="cb35-25"><a href="#cb35-25" aria-hidden="true" tabindex="-1"></a> setLED<span class="op">(</span>OFF<span class="op">);</span></span>
  1572. <span id="cb35-26"><a href="#cb35-26" aria-hidden="true" tabindex="-1"></a> rtbState <span class="op">=</span> RTB_IDLE<span class="op">;</span></span>
  1573. <span id="cb35-27"><a href="#cb35-27" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span> </span>
  1574. <span id="cb35-28"><a href="#cb35-28" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1575. <span id="cb35-29"><a href="#cb35-29" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1576. <span id="cb35-30"><a href="#cb35-30" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1577. <span id="cb35-31"><a href="#cb35-31" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  1578. <h2 id="state-machine-initialization">State Machine Initialization</h2>
  1579. <p>Notice that there’s no initialization of states in this code. It
  1580. <em>would</em> be very handy if we knew when to initialize all the
  1581. lights and buzzers and match up the various states. Perhaps the
  1582. <code>main()</code> code could add a single event into the event queue
  1583. at power-up, perhaps <code>EVT_INIT</code>. It might be added like
  1584. this:</p>
  1585. <div class="sourceCode" id="cb36"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> main<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
  1586. <span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a> newEvent<span class="op">(</span>EVT_INIT<span class="op">);</span> <span class="co">// early, before interrupts, so we know it&#39;s first in line</span></span>
  1587. <span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a> eint<span class="op">();</span></span>
  1588. <span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span><span class="op">(</span><span class="dv">1</span><span class="op">)</span> <span class="op">{</span></span>
  1589. <span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span> dispatcher code <span class="op">...</span></span>
  1590. <span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1591. <span id="cb36-7"><a href="#cb36-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  1592. <p>Then, in the state code, you can catch that event and set up whatever
  1593. might be required</p>
  1594. <div class="sourceCode" id="cb37"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a>uint8 myState<span class="op">;</span></span>
  1595. <span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> stateCode<span class="op">(</span>uint8 event<span class="op">)</span> <span class="op">{</span></span>
  1596. <span id="cb37-3"><a href="#cb37-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event<span class="op">==</span>EVT_INIT<span class="op">)</span> <span class="op">{</span></span>
  1597. <span id="cb37-4"><a href="#cb37-4" aria-hidden="true" tabindex="-1"></a> <span class="co">// ... do setup code</span></span>
  1598. <span id="cb37-5"><a href="#cb37-5" aria-hidden="true" tabindex="-1"></a> myState <span class="op">=</span> FIRST_STATE<span class="op">;</span></span>
  1599. <span id="cb37-6"><a href="#cb37-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span><span class="op">;</span></span>
  1600. <span id="cb37-7"><a href="#cb37-7" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1601. <span id="cb37-8"><a href="#cb37-8" aria-hidden="true" tabindex="-1"></a> <span class="co">// ... regular state machine code</span></span>
  1602. <span id="cb37-9"><a href="#cb37-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  1603. <h2 id="messages">Messages</h2>
  1604. <p>Now that we have an event/dispatcher system, we can also also use it
  1605. to send information asychronously between tasks. For example, if a
  1606. keyboard processing task needs to inform its siblings, it can create
  1607. <em>messages</em> which can be injected into the event queue.</p>
  1608. <p>Notice the change of terminology, where <em>message</em> indicates
  1609. that the entry was created by code procesing, rather than an
  1610. interrupt.</p>
  1611. <h3 id="postmessage">PostMessage</h3>
  1612. <p>We need a service routine to add messages to the event queue:
  1613. <code>postMessage()</code>. This call is very smimilar
  1614. <code>newEvent()</code> which should only be called from interrupts.</p>
  1615. <figure>
  1616. <img src="postMessage.png"
  1617. alt="cd-eject task uses postMessage() to broadcast a message" />
  1618. <figcaption aria-hidden="true">cd-eject task uses postMessage() to
  1619. broadcast a message</figcaption>
  1620. </figure>
  1621. <div class="sourceCode" id="cb38"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> postMessage<span class="op">(</span>uint8 message<span class="op">);</span></span></code></pre></div>
  1622. <p>Notice that <code>postMessage</code> can’t return any information,
  1623. because it’s not processed immediately; the <em>message</em> is added to
  1624. the <em>event queue</em> to be processed at a later time.</p>
  1625. <details>
  1626. <summary>
  1627. Reality Check
  1628. </summary>
  1629. In this tiny system, <code>postMessage()</code> is exactly the same as
  1630. <code>newEvent()</code>. The reason that I use different names is that
  1631. some more sophisticated operating systems require that these two
  1632. functions are <em>not</em> identical.
  1633. </details>
  1634. <h3 id="sendmessage">SendMessage</h3>
  1635. <p>In some cases we may want the sibling task to process the information
  1636. immediately. This means:</p>
  1637. <ul>
  1638. <li>we can be assured that the sibling task has fully processed the
  1639. information</li>
  1640. <li>does not involve the dispatcher; but does require extra room on the
  1641. stack</li>
  1642. <li>we <em>could</em> get a return value from the sibling task; since
  1643. it’s implemented as a subroutine, it’s allowed to return a value</li>
  1644. </ul>
  1645. <figure>
  1646. <img src="sendMessage.png"
  1647. alt="cd-eject task uses sendMessage() to call a sibling task" />
  1648. <figcaption aria-hidden="true">cd-eject task uses sendMessage() to call
  1649. a sibling task</figcaption>
  1650. </figure>
  1651. <p>This of course means that the prototype for task functions would
  1652. change from</p>
  1653. <div class="sourceCode" id="cb39"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> taskCode<span class="op">(</span>uint8 event<span class="op">);</span></span>
  1654. <span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a>to</span>
  1655. <span id="cb39-3"><a href="#cb39-3" aria-hidden="true" tabindex="-1"></a>uint8 taskCode<span class="op">(</span>uint8 event<span class="op">);</span></span></code></pre></div>
  1656. <p>The service routine to send a message like this would look like:</p>
  1657. <div class="sourceCode" id="cb40"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a>uint8 SendMessage<span class="op">(</span>int8 taskPointer<span class="op">(</span>uint8<span class="op">),</span> uint8 message<span class="op">)</span> <span class="op">{</span></span>
  1658. <span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> taskPointer<span class="op">(</span>message<span class="op">);</span></span>
  1659. <span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  1660. <h3 id="usage">Usage</h3>
  1661. <p>Why might one want to send a <em>message</em> between tasks?</p>
  1662. <p>Suppose you have a rotary encoder, which sends quadrant signals,
  1663. which need to be interpreted as <em>clockwise</em> and <em>counter
  1664. clockwise</em>. You could have one task devoted to determining the
  1665. direction of the knob (and <a href="#debouncing">debouncing</a>), and
  1666. have it send clean EVT_CW and EVT_CCW <em>messages</em> to its sibgling
  1667. tasks.</p>
  1668. <p>Another possible use of <em>messages</em> is to create alternate
  1669. souces of input. For example, a device which has a temperature set by
  1670. “up/down” buttons on a front panel could receive the same controls from
  1671. an infra-red remote, or even a serial port (perhaps for testing).</p>
  1672. <p>And why <code>sendMessage()</code>? Perhaps you need to have a
  1673. sibling task change states, or process information <em>before</em> you
  1674. continue in your task. Imagine there is a slave WiFi chip that needs to
  1675. be powered up <em>before</em> you send it a request….you could use
  1676. <code>sendMessage()</code> to activate the power, and then continue,
  1677. knowing that your peripheral is available.</p>
  1678. <h2 id="ideas-for-tasks">Ideas for Tasks</h2>
  1679. <p>I taught this coding technique at the college level, and a typical
  1680. end-of-term assignment was to code up a simulated automobile
  1681. entertainment system, which included about 6-10 concurrent tasks:</p>
  1682. <ul>
  1683. <li>task blue light to show bluetooth connectivity</li>
  1684. <li>volume up/down sense and display</li>
  1685. <li>radio channel select buttons
  1686. <ul>
  1687. <li>step single freq, or high-speed scan</li>
  1688. </ul></li>
  1689. <li>power on/off management</li>
  1690. <li>remote control of volume/radio-select from the steering wheel (uart
  1691. link)</li>
  1692. <li>backlight for night-time viewing (auto sense from a light
  1693. sensor)</li>
  1694. <li>service-required LED, flashing</li>
  1695. <li>a beeper to confirm keypresses (30ms) and alarm (700ms/100ms)</li>
  1696. <li>a clock up/down set button
  1697. <ul>
  1698. <li>3 buttons: “set min/hr” and “+” and “-”</li>
  1699. </ul></li>
  1700. </ul>
  1701. <p>Each list item above corresponds to one task. My students were able
  1702. to code this up with about 35k of source, which compiles to about 8k of
  1703. code and 256B of RAM (on an STM32)</p>
  1704. <h2 id="more-state-machines">More State Machines</h2>
  1705. <h3 id="radio-tuner">Radio Tuner</h3>
  1706. <p>Suppose we have a <code>+</code> and <code>-</code> button for tuning
  1707. a radio. A press of either will move the radio frequency by one step. If
  1708. the button is held for more than 0.5 seconds, the radio should change to
  1709. a rapid scroll through all available frequencies.</p>
  1710. <p>Suppose we have events coming at 100msec, and that the radio
  1711. frequencies are 88.7 up to 107.9, with steps at 0.1. And finally,
  1712. suppose there are 5 available events:</p>
  1713. <div class="sourceCode" id="cb41"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span>EVT_NONE<span class="op">,</span> EVT_TICK<span class="op">,</span> EVT_UP_PRESS<span class="op">,</span> EVT_UP_RELEASE<span class="op">,</span> EVT_DN_PRESS<span class="op">,</span> EVT_DN_RELEASE<span class="op">};</span></span></code></pre></div>
  1714. <figure>
  1715. <img src="radio_tuner.png" alt="state machine for radio tuner" />
  1716. <figcaption aria-hidden="true">state machine for radio
  1717. tuner</figcaption>
  1718. </figure>
  1719. <div class="sourceCode" id="cb42"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> <span class="dt">float</span> MIN_FREQ<span class="op">=</span><span class="fl">88.7</span><span class="op">,</span> MAX_FREQ<span class="op">=</span><span class="fl">107.9</span><span class="op">,</span> INC_FREQ<span class="op">=</span><span class="dv">0</span><span class="er">.1</span><span class="op">;</span></span>
  1720. <span id="cb42-2"><a href="#cb42-2" aria-hidden="true" tabindex="-1"></a><span class="dt">float</span> radioFreq <span class="op">=</span> MIN_FREQ<span class="op">;</span></span>
  1721. <span id="cb42-3"><a href="#cb42-3" aria-hidden="true" tabindex="-1"></a>uint16 radioTimer <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
  1722. <span id="cb42-4"><a href="#cb42-4" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> uint16 radioTimeout <span class="op">=</span> <span class="dv">5</span><span class="op">;</span> <span class="co">// 0.5 seconds</span></span>
  1723. <span id="cb42-5"><a href="#cb42-5" aria-hidden="true" tabindex="-1"></a></span>
  1724. <span id="cb42-6"><a href="#cb42-6" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="op">{</span>IDLE<span class="op">,</span> FREQ_UP<span class="op">,</span> FREQ_UP_FAST<span class="op">,</span> FREQ_DN<span class="op">,</span> FREQ_DN_FAST<span class="op">};</span></span>
  1725. <span id="cb42-7"><a href="#cb42-7" aria-hidden="true" tabindex="-1"></a>uint8 state <span class="op">=</span> IDLE<span class="op">;</span></span>
  1726. <span id="cb42-8"><a href="#cb42-8" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> radioTask<span class="op">(</span>uint8 event<span class="op">)</span> <span class="op">{</span></span>
  1727. <span id="cb42-9"><a href="#cb42-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span><span class="op">(</span>state<span class="op">)</span> <span class="op">{</span></span>
  1728. <span id="cb42-10"><a href="#cb42-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> IDLE<span class="op">:</span></span>
  1729. <span id="cb42-11"><a href="#cb42-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_UP_PRESS<span class="op">)</span> <span class="op">{</span></span>
  1730. <span id="cb42-12"><a href="#cb42-12" aria-hidden="true" tabindex="-1"></a> radioFreq <span class="op">+=</span> INC_FREQ<span class="op">;</span></span>
  1731. <span id="cb42-13"><a href="#cb42-13" aria-hidden="true" tabindex="-1"></a> checkRadioFreq<span class="op">();</span></span>
  1732. <span id="cb42-14"><a href="#cb42-14" aria-hidden="true" tabindex="-1"></a> radioTimer <span class="op">=</span> radioTimeout<span class="op">;</span></span>
  1733. <span id="cb42-15"><a href="#cb42-15" aria-hidden="true" tabindex="-1"></a> state <span class="op">=</span> FREQ_UP<span class="op">;</span></span>
  1734. <span id="cb42-16"><a href="#cb42-16" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1735. <span id="cb42-17"><a href="#cb42-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_DN_PRESS<span class="op">)</span> <span class="op">{</span></span>
  1736. <span id="cb42-18"><a href="#cb42-18" aria-hidden="true" tabindex="-1"></a> radioFreq <span class="op">-=</span> INC_FREQ<span class="op">;</span></span>
  1737. <span id="cb42-19"><a href="#cb42-19" aria-hidden="true" tabindex="-1"></a> checkRadioFreq<span class="op">();</span></span>
  1738. <span id="cb42-20"><a href="#cb42-20" aria-hidden="true" tabindex="-1"></a> radioTimer <span class="op">=</span> radioTimeout<span class="op">;</span></span>
  1739. <span id="cb42-21"><a href="#cb42-21" aria-hidden="true" tabindex="-1"></a> state <span class="op">=</span> FREQ_DN<span class="op">;</span></span>
  1740. <span id="cb42-22"><a href="#cb42-22" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1741. <span id="cb42-23"><a href="#cb42-23" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1742. <span id="cb42-24"><a href="#cb42-24" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> FREQ_UP<span class="op">:</span></span>
  1743. <span id="cb42-25"><a href="#cb42-25" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_UP_RELEASE<span class="op">)</span> </span>
  1744. <span id="cb42-26"><a href="#cb42-26" aria-hidden="true" tabindex="-1"></a> state <span class="op">=</span> IDLE<span class="op">;</span></span>
  1745. <span id="cb42-27"><a href="#cb42-27" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  1746. <span id="cb42-28"><a href="#cb42-28" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(--</span>radioTimer <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> </span>
  1747. <span id="cb42-29"><a href="#cb42-29" aria-hidden="true" tabindex="-1"></a> state <span class="op">=</span> FREQ_UP_FAST<span class="op">;</span></span>
  1748. <span id="cb42-30"><a href="#cb42-30" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1749. <span id="cb42-31"><a href="#cb42-31" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1750. <span id="cb42-32"><a href="#cb42-32" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> FREQ_UP_FAST<span class="op">:</span></span>
  1751. <span id="cb42-33"><a href="#cb42-33" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_TICK<span class="op">)</span> <span class="op">{</span></span>
  1752. <span id="cb42-34"><a href="#cb42-34" aria-hidden="true" tabindex="-1"></a> radioFreq <span class="op">+=</span> INC_FREQ<span class="op">;</span></span>
  1753. <span id="cb42-35"><a href="#cb42-35" aria-hidden="true" tabindex="-1"></a> checkRadioFreq<span class="op">();</span></span>
  1754. <span id="cb42-36"><a href="#cb42-36" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1755. <span id="cb42-37"><a href="#cb42-37" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>event <span class="op">==</span> EVT_UP_RELEASE<span class="op">)</span> </span>
  1756. <span id="cb42-38"><a href="#cb42-38" aria-hidden="true" tabindex="-1"></a> state <span class="op">=</span> IDLE<span class="op">;</span></span>
  1757. <span id="cb42-39"><a href="#cb42-39" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span><span class="op">;</span></span>
  1758. <span id="cb42-40"><a href="#cb42-40" aria-hidden="true" tabindex="-1"></a> <span class="co">// and the same for FREQ_DN and FREQ_DN_FAST</span></span>
  1759. <span id="cb42-41"><a href="#cb42-41" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
  1760. <span id="cb42-42"><a href="#cb42-42" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
  1761. <span id="cb42-43"><a href="#cb42-43" aria-hidden="true" tabindex="-1"></a></span>
  1762. <span id="cb42-44"><a href="#cb42-44" aria-hidden="true" tabindex="-1"></a><span class="co">// manage rollover</span></span>
  1763. <span id="cb42-45"><a href="#cb42-45" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> checkRadioFreq<span class="op">()</span> <span class="op">{</span></span>
  1764. <span id="cb42-46"><a href="#cb42-46" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>radioFreq <span class="op">&gt;</span> MAX_FREQ<span class="op">)</span></span>
  1765. <span id="cb42-47"><a href="#cb42-47" aria-hidden="true" tabindex="-1"></a> radioFreq <span class="op">=</span> MIN_FREQ<span class="op">;</span></span>
  1766. <span id="cb42-48"><a href="#cb42-48" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="op">(</span>radioFreq <span class="op">&lt;</span> MIN_FREQ<span class="op">)</span></span>
  1767. <span id="cb42-49"><a href="#cb42-49" aria-hidden="true" tabindex="-1"></a> radioFreq <span class="op">=</span> MAX_FREQ<span class="op">;</span></span>
  1768. <span id="cb42-50"><a href="#cb42-50" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
  1769. <p>This may seem like a lot of code, but it compiles to something quite
  1770. small. It is non-blocking, and easily maintained and modified. And it
  1771. works.</p>
  1772. </body>
  1773. </html>