Anda di halaman 1dari 31

QP state machine frameworks for Arduino

Application Note Event-Driven Arduino Programming with QP


Document Revision E September 2 !2

Copyright Quantum Leaps, LLC info@quantum-leaps com www state-machine com

"able o# $ontents
! %ntroduction&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ! # # A$out Arduino% # # & '"ent-dri"en programming with Arduino% & # ( )he structure of the QP*C++ e"ent-dri"en framework for Arduino% ( 2 'etting Started&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ( & # ,oftware -nstallation . & & !unning the /ining Philosophers Pro$lem 0/PP1 '2ample 3 & ( !unning the P'L-CA4 Crossing '2ample 5 & 6 7enerating the P'L-CA4 ,ketch with the Q8% 8odeling )ool ## & . 8odifying the '2amples to !educe Power Consumption #& ) "he Structure o# an Arduino S*etch #or QP&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& !) ( # )he setup01 function #( ( & )he Application -nterface 0'"ents and ,ignals1 #. ( ( )he ,tate 8achines #3 + ,oard Support Pac*age -,SP. #or Arduino&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& !/ 6 # 9,P -nitiali:ation #5 6 & -nterrupts #5 6 ( -dle Processing &; 6 6 Assertion <andler Q=onAssert01 &# ( QP0$11 2ibrar3 #or Arduino&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 22 . # )he qp=port h <eader >ile && . & )he qp=port cpp >ile &( . ( )he qp cpp >ile &6 4 5sing Preemptive Q6 6ernel&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 2( ? # !e-configuring the QP*C++ Li$rary to @se Preempti"e QA Aernel &? ? & )he qp=dpp=qk '2ample &? ? ( !unning the qp=dpp=qk '2ample &3 7 Related Documents and Re#erences&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 28 8 $ontact %n#ormation&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 2/

Copyright Quantum Leaps, LLC All !ights !eser"ed

%ntroduction
)his document descri$es how to apply the event-driven programming paradigm with modern state machines to de"elop software for Arduino% ,pecifically, you will learn how to $uild responsi"e, ro$ust, and power-efficient Arduino programs with the open source QP%*C++ acti"e o$Bect framework, which is like a modern real-time operating s3stem 0!)C,1 specifically designed for e2ecuting e"ent-dri"en, encapsulated state machines 0acti"e o$Bects1 Dou will also see how to take Arduino programming to the ne2t le"el $y using the the free Q8% modeling tool to generate Arduino code automaticall3 from state diagrams

!&!

About Arduino
Arduino% 0see www arduino cc1 is an open-source electronics prototyping platform, designed to make digital electronics more accessi$le to non-specialists in multidisciplinary proBects )he hardware consists of a simple Arduino printed circuit $oard with an Atmel AE! microcontroller and standardi:ed pin-headers for e2tensi$ility )he Arduino microcontroller is programmed using the C++ language 0with some simplifications, modifications, and Arduino-specific li$raries1, and a Fa"a-$ased integrated de"elopment en"ironment 0called Processing1 that runs on a desktop computer 0Gindows, Linu2, or 8ac1 Arduino $oards can $e purchased pre-assem$led at relati"ely low cost 0H&;-H.;1 Alternati"ely, hardware design information is freely a"aila$le for those who would like to assem$le an Arduino $oard $y themsel"es Arduino microcontroller $oards are e2tensi$le $y means of Arduino IshieldsJ, which are printed circuit $oards that sit on top of an Arduino microcontroller $oard, and plug into the standardi:ed pin-headers 0see >igure #1 8any such Arduino shields are a"aila$le for connecti"ity 0@,9, CA4, 'thernet, wireless, etc 1, 7P,, motor control, ro$otics, and many other functions A steadily growing list of Arduino shields is maintained at shieldlist org ;igure !: A stac* o# Arduino shields

N9"E: )his document assumes that you ha"e a $asic familiarity with the Arduino en"ironment and you know how to write and run simple programs for Arduino

Copyright Quantum Leaps, LLC All !ights !eser"ed

! of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino

!&2

Event-driven programming with Arduino


)raditionally, Arduino programs are written in a se<uential manner Ghene"er an Arduino program needs to synchroni:e with some e2ternal e"ent, such as a $utton press, arri"al of a character through the serial port, or a time delay, it e2plicitly waits in-line for the occurrence of the e"ent Gaiting Iin-lineJ means that the Arduino processor spends all of its cycles constantly checking for some condition in a tight loop 0called the polling loop1 >or e2ample, in almost e"ery Arduino program you see many polling loops like the code snippet $elow, or function calls, like delay() that contain implicit polling loops insideK 2isting !: Se<uential programming e=ample void loop() { while (digitalRead(buttonPin) != HIGH) ; // wait for the button pre ! ! ! // pro"e the button pre while (#erial!available() == $) ; // wait for a "hara"ter fro% the "har "h = #erial!read(); // obtain the "hara"ter ! ! ! // pro"e the "hara"ter delay(&$$$); // i%pli"it polling loop (wait for &$$$% ) ! ! ! // pro"e the ti%eout' e!g!' wit"h an ()* on erial port

Although this approach is functional in many situations, it doesnLt work "ery well when there are multiple possi$le sources of e"ents whose arri"al times and order you cannot predict and where it is important to handle the e"ents in a timely manner )he fundamental pro$lem is that while a sequential program is waiting for one kind of e"ent 0e g , a $utton press1, it is not doing any other work and is not responsive to other e"ents 0e g , characters from the serial port1 Another $ig pro$lem with the sequential program structure is wastefulness in terms of power dissipation !egardless of how much or how little actual work is $eing done, the Arduino processor is always running at top speed, which drains the $attery quickly and pre"ents you from making truly long-lasting $atterypowered de"ices
N9"E: -f you intend to use Arduino in a $attery operated de"ice, you should seriously consider the e"ent-dri"en programming option Please also see the upcoming ,ection & .

>or these and other reasons e2perienced programmers turn to the long-know design strategy called event-driven programming, which requires a distinctly different way of thinking than con"entional sequential programs All e"ent-dri"en programs are naturally di"ided into the application, which actually handles the e"ents, and the super"isory e"ent-dri"en infrastructure 0 #ramewor*1, which waits for e"ents and dispatches them to the application )he control resides in the e"ent-dri"en framework, so from the application standpoint, the control is inverted compared to a traditional sequential program 2isting 2: "he simplest event-driven program structure& "he highlighted code conceptuall3 belongs to the event-driven #ramewor*& void loop() { if (event&()) event&Handler(); if (event-()) event-Handler(); ! ! ! + // // // // // event& o""urred, pro"e event& event- o""urred, pro"e eventhandle other event

Copyright Quantum Leaps, LLC All !ights !eser"ed

2 of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino An e"ent-dri"en framework can $e "ery simple -n fact, many proBects in the Arduino Playground * )utorials and !esources * Protothreading, )iming M 8illis section pro"ide e2amples of rudimentary e"entdri"en frameworks )he general structure of all these rudimentary frameworks is shown in Listing & )he framework in this case consists of the main Arduino loop and the if statements that check for e"ents '"ents are effecti"ely polled during each pass through the main loop, $ut the main loop does not get into tight polling su$-loops Calls to functions that poll internally 0like delay()1 are not allowed, $ecause they would slow down the main loop and defeat the main purpose of e"ent-dri"en programming 0responsi"eness1 )he application in this case consists of all the e"ent handler functions 0event&Handler(), event-Handler(), etc 1 Again, the critical difference from sequential programming here is that the e"ent handler functions are not allowed to poll for e"ents, $ut must consist essentially of linear code that quickly returns control to the framework after handling each e"ent )his arrangement allows the e"ent-dri"en program to remain responsive to all e"ents all the time, $ut it is also the $iggest challenge of the e"ent-dri"en programming style, $ecause the application 0the e"ent handler functions1 must $e designed such that for each new e"ent the corresponding e"ent handler can pick up where it left off for the last e"ent 0A sequential program has much less of this pro$lem, $ecause it can hang on in tight polling loops around certain places in the code and process the e"ents in the conte2ts Bust following the polling loops )his arrangement allows a sequential program to mo"e naturally from one e"ent to the ne2t 1 @nfortunately, the Bust descri$ed main challenge of e"ent-dri"en programming often leads to >spaghetti? code )he e"ent handler functions start off pretty simple, $ut then if.s and el e-s must $e added inside the handler functions to handle the conte=t properly >or e2ample, if you design a "ending machine, you cannot process the Idispense productJ $utton-press e"ent until the full payment has $een collected )his means that somewhere inside the di pen eProdu"t/uttonPre Handler() function you need an if. statement that tests the payment status $ased on some glo$al "aria$le, which is set in the e"ent handler function for payment e"ents Con"ersely, the payment status "aria$le must $e changed after dispensing the product or you will allow dispensing products without collecting su$sequent payments <opefully you see how this design quickly leads to do:ens of glo$al "aria$les and hundreds of tests 0 if.s and el e-s1 spread across the e"ent handler functions, until no human $eing has an idea what e2actly happens for any gi"en e"ent, $ecause the e"ent-handler code resem$les a $owl of tangled spaghetti An e2ample of spaghetti code Bust starting to de"elop is the ,topwatch proBect a"aila$le from the Arduino Playground Luckily, generations of programmers $efore you ha"e disco"ered an effecti"e way of sol"ing the IspaghettiJ code pro$lem )he solution is $ased on the concept of a state machine, or actually a set of colla$orating state machines that preser"e the conte2t from one e"ent to the ne2t using the concept of state )his document descri$es this most ad"anced and powerful way of com$ining the e"ent-dri"en programming paradigm with modern state machines

!&)

"he structure o# the QP0$11 event-driven #ramewor* #or Arduino


)he rudimentary e2amples of e"ent-dri"en programs currently a"aila$le from the Arduino Playground are "ery simple, $ut they donLt pro"ide a true e"ent-dri"en programming en"ironment for a num$er of reasons >irst, the simple frameworks donLt perform queuing of e"ents, so e"ents can get lost if an e"ent happens more than once $efore the main loop comes around to check for this e"ent or when an e"ent is generated in the loop ,econd, the primiti"e e"ent-dri"en frameworks ha"e no safeguards against corruption of the glo$al data shared among the e"ent-handlers $y the interrupt ser"ice routines 0-,!s1, which can preempt the main loop at any time And finally, the simple frameworks are not suita$le for e2ecuting state machines due to the early filtering $y e"ent-type, which does not lea"e room for state machine0s1 to make decisions $ased on the internal state >igure & shows the structure of the QP framework for Arduino, which does pro"ide all the essential elements for safe and efficient e"ent-dri"en programming As usual, the software is structured in an endless e"ent loop )he most important element of the design is the presence of multiple event <ueues with a unique priority and a state machine assigned to each queue )he queues are constantly monitored $y the vanilla scheduler, which $y e"ery pass through the loop picks up the highest-priority

Copyright Quantum Leaps, LLC All !ights !eser"ed

) of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino not-empty queue After finding the queue, the scheduler e2tracts the e"ent from the queue and sends it to the state machine associated with this queue, which is called dispatching of an e"ent to the state machine
N9"E: )he e"ent queue, state machine, and a unique priority is collecti"ely called an active ob@ect

)he design guarantees that the di pat"h() operation for each state machine always runs to completion and returns to the main Arduino loop $efore any other e"ent can $e processed )he scheduler applies all necessary safeguards to protect the integrity of the e"ents, the queues, and the scheduler itself from corruption $y asynchronous interrupts that can preempt the main loop and post e"ents to the queues at any time ;igure 2: Event-driven QP0$11 #ramewor* with multiple event <ueues and state machines

find highest-priority non-empty queue

all queues empty 0idle condition1 >vanilla? scheduler priority O n-# priority O # priority O ; idle processing e O queue get01N dispatch0e1N

priority O n

&&&
e O queue get01N dispatch0e1N e O queue get01N dispatch0e1N

&&& &&&

N9"E: )he I"anillaJ scheduler shown in >igure & is an e2ample of a cooperative scheduler, $ecause state machines naturally cooperate to implicitly yield to each other at the end of each run-tocompletion step )he QP*C++ framework contains also a more ad"anced, fully preemptive real-time kernel called QA )he QA kernel can $e also used with Arduino when you define the macro QK_PREEMPTIVE in the 0p1port!h header file ,ee ,ection ? for more information

)he framework shown in >igure & also "ery easily detects the condition when all e"ent queues are empty )his situation is called the idle condition of the system -n this case, the scheduler calls idle processing 0specifically, the function 2344onIdle()1, which puts the processor to a low-power sleep mode and can $e customi:ed to turn off the peripherals inside the microcontroller or on the Arduino shields After the processor is put to sleep, the code stops e2ecuting, so the main Arduino loop stops completely Cnly an e2ternal interrupt can wake up the processor, $ut this is e2actly what you want $ecause at this point only an interrupt can pro"ide a new e"ent to the system >inally, please also note that the framework shown in >igure & can achie"e good real-time performance, $ecause the indi"idual run-to-completion 0!)C1 steps of each state machine are typically short 0e2ecution time counted in microseconds1

Copyright Quantum Leaps, LLC All !ights !eser"ed

+ of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino

'etting Started
)o focus the discussion, this Application 4ote uses the Arduino @4C $oard $ased on the Atmel Atmega(&PP microcontroller 0see >igure (1 )he e2ample code has $een compiled with the Arduino !& -/' 0the latest as of this writing1, which is a"aila$le for a free download from the Arduino we$site )he following discussion assumes that you ha"e downloaded and installed the Arduino -/' on your computer ;igure ): Arduino 5N9 board ,tandard Arduino pin-header @ser L'/ !eset $utton Atmega(&PP microcontroller

@,9 Connector to the host PC

,tandard Arduino pin-header

2&!

So#tware %nstallation
)he e2ample code is distri$uted in a single Q-P archi"e 0p1arduino!5ip )he contents of this archi"e is shown in Listing ( 2isting ): $ontents o# the <pAarduino&Bip archive 0p1arduino!5ip . the "ode a""o%panying thi appli"ation note 6.do"/ . do"u%entation 7 6.891)vent.*riven18rduino!pdf : thi do"u%ent 7 6.891*PP!pdf : *ining Philo opher Proble% e;a%ple appli"ation 7 6.891P)(I<89!pdf : P)de trian (Ight <=9trolled (P)(I<89) "ro ing e;a%ple 7 6.e;a%ple / ==> goe to the ?8rduino>/e;a%ple / folder 7 6.0p/ . 2P e;a%ple 7 7 6.0p1dpp/ : *ining Philo opher Proble% (*PP) e;a%ple 7 7 7 6.b p!"pp . /oard #upport Pa"@age i%ple%entation for *PP 7 7 7 6.b p!h . /oard #upport Pa"@age interfa"e for *PP 7 7 7 6.dpp!0% . Ahe 2B %odel of the *PP appli"ation 7 7 7 6.dpp!h . *PP interfa"e (generated "ode) 7 7 7 6.philo!"pp . Philo opher a"tive obCe"t (generated "ode) 7 7 7 6.table!"pp . Aable 8"tive obCe"t (generated "ode) 7 7 7 6.0p1dpp!ino . 2P/*PP 8rduino @et"h (generated "ode) 7 7 7

Copyright Quantum Leaps, LLC All !ights !eser"ed

( of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino 7 7 6.0p1dpp10@/ 7 7 7 6.b p!"pp 7 7 7 6.b p!h 7 7 7 6.dpp!0% 7 7 7 6.dpp!h 7 7 7 6.philo!"pp 7 7 7 6.table!"pp 7 7 7 6.0p1dpp10@!ino 7 7 7 7 7 6.0p1peli"an/ 7 7 7 6.b p!"pp 7 7 7 6.b p!h 7 7 7 6.peli"an!0% 7 7 7 6.peli"an!"pp 7 7 7 6.peli"an!h 7 7 7 6.0p1peli"an!ino 7 6.librarie / 7 6.0p/ 7 7 6."opying!t;t 7 7 6.GP(-!AFA 7 7 6.0p!"pp 7 7 6.0p1port!"pp 7 7 6.0p1port!h : . . . . . . . : . . . . . . *PP e;a%ple with the pree%ptive 2D @ernel (#e"tion E) /oard #upport Pa"@age i%ple%entation for *PP /oard #upport Pa"@age interfa"e for *PP Ahe 2B %odel of the *PP appli"ation *PP interfa"e ( ignal ' event ' global ) Philo opher a"tive obCe"t Aable 8"tive obCe"t 2P/*PP 8rduino @et"h (pree%ptive 2D "onfiguration) P)de trian (Ight <=9trolled (P)(I<89) "ro ing e;a%ple /oard #upport Pa"@age i%ple%entation for P)(I<89 /oard #upport Pa"@age interfa"e for P)(I<89 Ahe 2B %odel of the P)(<I89 "ro ing appli"ation P)(I<89 a"tive obCe"t (generated "ode) P)(I<89 interfa"e (generated "ode) 2P/P)(<I89 8rduino @et"h (generated "ode)

==> goe to the ?8rduino>/librarie / folder . 2P library . ter% of "opying thi "ode . GP( ver ion - open our"e li"en e . 2P/<66 platfor%.independent i%ple%entation . 2P/<66 port for 8rduino i%ple%entation . 2P/<66 port for 8rduino interfa"e

)he complete QP*C++ li$rary code consists of Bust three source filesK 0p1port!h, 0p1port!"pp, and 0p!"pp )he QP li$rary is accompanied with four e2amplesK 0p1dpp, 0p1peli"an, 0%1peli"an' and 0p1dpp10@! )he Arduino sketch 0p1dpp demonstrates the classic /ining Philosopher Pro$lem 0/PP1 with multiple state machines )he sketch 0p1peli"an demonstrates a P'destrian L-ght CC4trolled 0P'L-CA41 crossing )he e2ample 0%1peli"an contains the Q8 model of the P'L-CA4 crossing and generates complete code automatically ;igure +: 5nBipping qp_arduino.zip into the Arduino director3& Cou need to con#irm that 3ou want to merge the #olders examples and libraries&

Copyright Quantum Leaps, LLC All !ights !eser"ed

4 of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino Dou need to un:ip the 0p1arduino!5ip archi"e into the Arduino directory 0e g , arduino.&!$G1 As shown in >igure 6, on Gindows you can simply open the Q-P file with the Gindows '2plorer, select the two directories 0librarie / and e;a%ple /1 and drag 0or copy-and-paste1 them to the Arduino directory ,ince Arduino already has the librarie / and e;a%ple / folders, you need to confirm that you want to merge them

2&2

Running the Dining Philosophers Problem -DPP. E=ample


!unning the QP e2amples on the Arduino $oard is "ery easy As shown in >igure ., the QP e2amples are integrated with the other Arduino e2amples in the Arduino -/', so you Bust choose the 0p1dpp e2ample

;igure (: 9pening -le#t. and veri#3ing -right. the DPP e=ample in the Arduino %DE&

At this point you must connect the Arduino $oard to your computer "ia a @,9 ca$le )he Arduino $oard is powered from the @,9 connector 0see >igure (1, so you donLt need to attach e2ternal power Dou upload the code to the Arduino microcontroller $y pressing the @pload $utton Please note that the upload can take se"eral seconds to complete After the upload completes, your Arduino starts e2ecuting the e2ample Dou should see the @ser L'/ 0see >igure (1 start to glow with low intensity 0not full on1 )he @ser L'/ is rapidly turned on and off in the Arduino idle loop, which appears as a constant glow to a human eye )o see the actual output from the /PP e2ample, you need to open the the Arduino Serial Donitor $y pressing the ,erial 8onitor $utton or $y selecting the menu )ools R ,erial 8onitor in the Arduino -/' After the ,erial 8onitor opens up, please make sure that it is configured for !!(2 baud rate Copyright Quantum Leaps, LLC All !ights !eser"ed 7 of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino


N9"E: )he design and implementation of the /ining Philosopher Pro$lem application, including state machines, is descri$ed in the Application 4ote I/ining Philosopher Pro$lemJ 0see !elated /ocuments and !eferences1

;igure 4: DPP e=ample output to the Arduino Serial Donitor& Da*e sure that the Serial Donitor is set up #or !!(2 baud rate&

,erial 8onitor 9utton

)o understand what the messages in the ,erial 8onitor window mean, you need to know whatLs going in the /ining Philosopher Pro$lem 0/PP1 -t is specified as followsK >i"e philosophers are gathered around a ta$le with a $ig plate of spaghetti in the middle 0see >igure 31 9etween each two philosophers is a fork )he spaghetti is so slippery that a philosopher needs two forks to eat it )he life of a philosopher consists of alternate periods of thinking and eating Ghen a philosopher wants to eat, he tries to acquire forks -f successful in acquiring forks, he eats for a while, then puts down the forks and continues to think )he key issue is that a finite set of tasks 0philosophers1 is sharing a finite set of resources 0forks1, and each resource can $e used $y only one task at a time Copyright Quantum Leaps, LLC All !ights !eser"ed

;igure 7: Dining Philosopher Problem with #ive philosophers numbered &&+&

( 6

&

# ;

8 of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino

2&)

Running the PE2%$AN $rossing E=ample


)he P'destrian L-ght CC4trolled 0P'L-CA41 crossing e2ample is stared in the similar way as the /PP e2ample, e2cept you select the 0p1peli"an e2ample from the Arduino e2amples in the Arduino -/', as shown in >igure P

;igure 8: 9pening -le#t. and veri#3ing -right. the PE2%$AN crossing e=ample in the Arduino %DE&

9efore you can test the e2ample, you need to understand the how it is ;igure /: Pedestrian 2igtht $9Ntrolled -PE2%$AN. crossing& supposed to work ,o, the P'L-CA4 crossing operates as followsK )he crossing 0see >igure 51 starts with cars ena$led 0green light for cars1 and pedestrians disa$led 0I/onLt GalkJ signal for pedestrians1 )o acti"ate the traffic light change a pedestrian must push the $utton at the crossing, which generates the P'/,=GA-)-47 e"ent -n response, oncoming cars get the yellow light, which after a few seconds changes to red light 4e2t, pedestrians get the IGalkJ signal, which shortly thereafter changes to the flashing I/onLt GalkJ signal After the I/ontL GalkJ signal stops flashing, cars get the green light again After this cycle, the traffic lights donLt respond to the P'/,=GA-)-47 $utton Copyright Quantum Leaps, LLC All !ights !eser"ed / of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino press immediately, although the $utton Iremem$ersJ that it has $een pressed )he traffic light controller always gi"es the cars a minimum of se"eral seconds of green light $efore repeating the traffic light change cycle Cne additional feature is that at any time an operator can take the P'L-CA4 crossing offline 0$y pro"iding the C>> e"ent1 -n the IofflineJ mode the cars get the flashing red light and the pedestrians get the flashing I/onLt GalkJ signal At any time the operator can turn the crossing $ack online 0$y pro"iding the C4 e"ent1

;igure ! : PE2%$AN crossing e=ample output to the Arduino Serial Donitor& Cou in@ect events to the application b3 sending *e3 stro*es : EpE #or PEDSAFA%"%N'G E#E #or 9;; and EoE #or 9N&

,erial 8onitor 9utton

)ype LpL and press ,end

N9"E: )he design and implementation of the P'L-CA4 crossing application, including the P'L-CA4 state machine, is descri$ed in the Application 4ote IP'L-CA4 Crossing ApplicationJ 0see !elated /ocuments and !eferences1

Copyright Quantum Leaps, LLC All !ights !eser"ed

! of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino

2&+

'enerating the PE2%$AN S*etch with the QD Dodeling "ool


'ach e2ample contains a Q8% model, which is a file with the e2tension !0% >or e2ample, ?0p1arduino!5ip>/e;a%ple /0p/0p1peli"an/0p1peli"an!0%, see Listing (1 )hese models and the Q8 modeling tool takes Arduino programming to the ne2t le"el -nstead of coding the state machines $y hand, you draw them with the free Q8% modeling tool, attach simple action code to states and transitions, and you generate the complete Arduino sketch automaticallySliterally $y a press of a $utton 0see >igure ##1 ;igure !!: PE2%$AN crossing model opened in the QD graphical modeling tool&

Press to generate P'L-CA4 sketch automatically

N9"E: )o start working with the Q8% modeling tool, you need to download the tool from statemachine com Q8% is currently supported on Gindows and Linu2 hosts Q8% is #ree to download and #ree to use 0see also !elated /ocuments and !eferences1

After you download and install Q8, you open the pro"ided model 0located in ?0p1arduino!5ip>/e;a%ple /0p/0%1peli"an/peli"an!0%1 and press the I7enerate CodeJ $utton, as shown in >igure ## Q8 will then generate the complete Arduino sketch that you open in the Arduino -/' as any other sketch

Copyright Quantum Leaps, LLC All !ights !eser"ed

!! of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino

2&(

Dodi#3ing the E=amples to Reduce Power $onsumption


As mentioned in ,ection # &, the QP*C++ framework allows you to take ad"antage of the Arduino processorLs low-power sleep mode, which is the only way to achie"e really low-power design 9oth pro"ided e2amples can $e "ery easily modified to switch to the sleep mode when no e"ents are a"aila$le -n fact, the code is already pro"ided for you, so all you need to do is Bust to ena$le this code As shown in >igure #&, you select the file b p!"pp 09oard ,upport Package1 and uncomment the definition of the #8H)1P=I)R macro

;igure !2: Dodi#3ing QP e=amples to run in low-power mode

,elect $sp cp and uncomment the definition of ,AE'=PCG'!

After you recompile the code and download to Arduino, you will see that the @ser L'/ is no longer glowing Actually, it is glowing, $ut only for a few microseconds out of e"ery #; milliseconds, so you cannot see it )his "ery low $rightness of the @ser L'/ means that the Arduino 9ackground loop uses "ery little power, yet the application performs e2actly as $eforeT )he upcoming ,ection 6 # e2plains what e2actly happens when you define the macro #8H)1P=I)R in b p!"pp

Copyright Quantum Leaps, LLC All !ights !eser"ed

!2 of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino

"he Structure o# an Arduino S*etch #or QP


'"ery e"ent-dri"en Arduino sketch for QP consists of four rough groupsK setup, e"ents, acti"e o$Bects, and $oard support package 09,P1 )ypically, the main sketch file 0the !ino file1 contains the Aruino etup() function ,ince the e"ents are shared, they are defined in a header file 0the !h file1 Acti"e o$Bects are defined in source files 0the !"pp files1, one acti"e o$Bect per file )he following sections descri$e these elements in more detail

)&!

"he setup() #unction


Listing 6 shows an e2ample Arduino sketch for QP )his sketch defines only the etup() function )he e2planation section immediately following the listing highlights the main points

2isting +: "3pical Arduino s*etch #or QP -#ile qp_dpp.ino. (&) Jin"lude ?0p1port!h> (-) Jin"lude Kdpp!hK (L) Jin"lude Kb p!hK (M) (Q) (E) (S) // (o"al. "ope obCe"t ....................................................... tati" 2)vt "on t Nl1table2ueue#toO91PHI(=P; tati" 2)vt "on t Nl1philo2ueue#toO91PHI(=PO91PHI(=P; tati" 2#ub "r(i t l1 ub "r#toOB8F1PR/1#IGP; tati" Aable)vt l1 %lPool#toO-N91PHI(=P; // torage for the %all event pool

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! (T) void etup() { (U) /#P1init(); // initiali5e the /#P (&$) (&&) (&-) 2344init(); // initiali5e the fra%ewor@ and the underlying RA @ernel // initiali5e event pool !!! i5eof(l1 %lPool#to)' i5eof(l1 %lPool#toO$P)); // init publi h. ub "ribe

2344poolInit(l1 %lPool#to'

2344p Init(l1 ub "r#to' 21*IB(l1 ub "r#to));

(&L) (&M) + 0#1 0&1 0(1

// tart the a"tive obCe"t !!! uintT1t n; for (n = $; n ? 91PHI(=; 66n) { 8=1PhiloOnP.> tart((uintT1t)(n 6 &)' l1philo2ueue#toOnP' 21*IB(l1philo2ueue#toOnP)); + 8=1Aable.> tart((uintT1t)(91PHI(= 6 &)' l1table2ueue#to' 21*IB(l1table2ueue#to));

'ach sketch for QP imports the QP li$rary port to Arduino 0the ?0p1port!h> header file1 )he application header file 0dpp!h in this case1 contains the definition of signals and e"ents for the application )his file is shared among most files in the sketch )he header file $sp!h contains the facilities pro"ided $y the 9oard ,upport Package )his file is also shared among most files in the sketch !) of 2/

Copyright Quantum Leaps, LLC All !ights !eser"ed

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino 06-.1 )he application must pro"ide storage for e"ent queues of all acti"e o$Bects used in the application <ere the storage is pro"ided at compile time through the statically allocated arrays of immuta$le 0const1 pointers to e"ents 0?1 -f the application uses the pu$lish-su$scri$e e"ent deli"ery mechanism supported $y QP, the application must pro"ide the storage for the su$scri$er lists )he su$scri$er lists remem$er which acti"e o$Bects ha"e su$scri$ed to which e"ents )he si:e of the su$scri$er data$ase depends on the num$er of pu$lished e"ents B8F1PR/1#IG found in the application header file )he application must also pro"ide storage for the e"ent pools that the QP framework uses for fast and deterministic dynamic allocation of e"ents 'ach e"ent pool can pro"ide only fi2ed-si:e memory $locks )o a"oid wasting the precious memory 0!A81 $y using massi"ely o"ersi:ed pools, the QP framework can manage up to three e"ent pools of different si:es )he /PP application uses only one pool, which can hold Aable)vt e"ents and e"ents without parameters 02)vt1 Dou pro"ide only the definition of the Arduino etup() function Dou donLt define the loop() function, $ecause it is pro"ided in the framework 0see ,ection . &1 )he function /#P1init() initiali:es the Arduino $oard for this application and is defined in the b p!"pp file

031

0P1 051

0#;1 )he function 2344init() initiali:es the Q> framework and you need to call it $efore any other Q> ser"ices 0##1 )he function 2344poolInit() initiali:es the e"ent pool )he parameters of this function areK the pointer to eh e"ent pool storage, the si:e of this storage, and the $lock-si:e of the this pool Dou can call this function up to three times to initiali:e up to three e"ent pools )he su$sequent calls to 2344poolInit() must $e made in the increasing order of $lock-si:e >or instance, the small $locksi:e pool must $e initiali:ed $efore the medium $lock-si:e pool 0#&1 )he function 2344p Init() initiali:es the pu$lish-su$scri$e e"ent deli"ery mechanism of QP )he parameters of this function areK the pointer to the su$scri$er-list array and the dimension of this array
N9"E: )he utility macro 21*IB() pro"ides the dimension of a one-dimensional array aOP computed as i5eof(a)/ i5eof(aO$P), which is a compile-time constant

0#(-#61 )he function tart() is defined in the framework class 28"tive and tells the framework to start managing an acti"e o$Bect as part of the application )he function takes the following parametersK the pointer to the acti"e o$Bect, the priority of the acti"e o$Bect, the pointer to its e"ent queue, the dimension 0length1 of that queue )he acti"e o$Bect priorities in QP are num$ered from # to 231B8F18<AIH), inclusi"e, where a higher priority num$er denotes higher urgency of the acti"e o$Bect )he constant 231B8F18<AIH) is defined in the QP port header file 0f1port!h 0see ,ection . #1
N9"E: At this point you ha"e pro"ided the QP framework with all the storage and acti"e o$Bect information it needs to manage your application )he ne2t step of e2ecution of the Arduino sketch is the call to the loop() function, which is defined in the QP port to Arduino 0so you do not define this function1 As descri$ed in the upcoming ,ection . &, the loop() function e2ecutes the main e"entloop shown in >igure &

Copyright Quantum Leaps, LLC All !ights !eser"ed

!+ of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino

)&2

"he Application %nter#ace -Events and Signals.


An event represents occurrence that is interesting to the system An e"ent consists of two parts )he part of the e"ent called the signal con"eys the type of the occurrence 0what happened1 >or e2ample, in the /PP application the )8A1#IG signal represents the permission to eat to a Philosopher acti"e o$Bect, whereas HR9GRV1#IG con"eys to the )a$le acti"e o$Bect that a Philosopher wants to eat An e"ent can also contain additional quantitati"e information a$out the occurrence in the form of event parameters >or e2ample, the HR9GRV1#IG signal is accompanied $y the num$er of the Philosopher -n QP e"ents are represented as instances of the 2)vt class pro"ided $y the framework ,pecifically, the 2)vt class contains the mem$er sig, to represent the signal of that e"ent '"ent parameters are added in the su$classes of 2)vt, that is classes that inherit from 2)vt 9ecause e"ents are shared among most of the application components, it is con"enient to declare them in a separate header file 0e g , dpp!h for the /PP application1 Listing . shows the interface for the /PP application )he e2planation section immediately following the listing highlights the main points 2isting (: "he application header #ile #or DPP -#ile dpp.h. (&) usin !namespa"e!QP#//a (-) enu% *PP#ignal { (L) )8A1#IG = 21R#)R1#IG' *=9)1#IG' A)RBI98A)1#IG' (M) B8F1PR/1#IG' (Q) (E) HR9GRV1#IG' B8F1#IG u%e the 2P na%e pa"e for all file in thi appli"ation

// publi hed by Aable to let a philo opher eat // publi hed by Philo opher when done eating // publi hed by /#P to ter%inate the appli"ation // the la t publi hed ignal // po ted fro% hungry Philo opher to Aable // the la t ignal

+;

tru"t Aable)vt 4 publi" 2)vt { uintT1t philo9u%; +; enu% { 91PHI(= = Q +;

// philo opher nu%ber // nu%ber of philo opher

0#1

)his directi"e esta$lishes the default namespace to $e QP, meaning that all elements not qualified e2plicitly are assumed to come from the namespace QP
N9"E: ,tarting from QP "ersion 6 . 22, the directi"e Iu ing na%e pa"e 2PJ is necessary to

use the QP framework without e2plicitly adding the prefi2 I 2P44J to e"ery element coming from the framework )his directi"e is also necessary for compati$ility with the code generated $y the Q8 tool "ersion & & 22 or higher 0&1 0(1 -n QP, e"ent signals are enumerated constants Placing all signals in a single enumeration is particularly con"enient to a"oid inad"ertent o"erlap in the numerical "alues of the different signals )he application-le"el signals do not start form :ero $ut rather must $e offset $y the constant 21R#)R1#IG Also note that $y con"ention the suffi2 1#IG is attached to the signals, so you can easily distinguish signals from other constants in your code )ypically the suffi2 1#IG is dropped in the state diagrams to reduce the clutter

Copyright Quantum Leaps, LLC All !ights !eser"ed

!( of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino 061 )he constant B8F1PR/1#IG delimits the pu$lished signals from the rest Dou can sa"e some !A8 $y pro"iding a lower limit of pu$lished signals to QP 0B8F1PR/1#IG1 rather than the ma2imum of all signals used in the application )he last enumeration B8F1#IG indicates the ma2imum of all signals used in the application )he structure Aable)vt represents a class of e"ents to con"ey the Philosopher num$er in the e"ent parameter Aable)vt inherits 2)vt and adds the philo9u% parameter to it

0.1 0?1

03-P1 )hese glo$al pointers represent acti"e o$Bects in the application and are used for posting e"ents directly to acti"e o$Bects 9ecause the pointers can $e initiali:ed at compile time, they are declared "on t! )he acti"e o$Bect pointers are IopaqueJ $ecause they cannot access the whole acti"e o$Bect, only the part inherited from 28"tive!

Copyright Quantum Leaps, LLC All !ights !eser"ed

!4 of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino

)&)

"he State Dachines


)he QP framework allows you to work with the modern hierarchical state machines 0a k a , @8L statecharts1 >or e2ample, >igure #( shows the <,8 for the P'L-CA4 crossing ;igure !): "he hierarchical state machine o# the PE2%$AN crossing
* me-Usu$scri$e0P'/,=GA-)-47=,-71N operational entry * CA!,=!'/N P'/,=/C4)=GALA

C>> cars'na$led e2it * e2it * peds'na$led

cars7reen entry * CA!,=7!''4 e2it * cars7reen4oPed entry * P'/,=GA-)-47 )-8'C@) cars7reen-nt entry * P'/,=GA-)-47 cars7reenPedGait entry * )-8'C@) entry * e2it * )-8'C@)

pedsGalk entry * P'/,=GALA e2it * )-8'C@)

peds>lash

VelseW

Vme-Um=flashCtr TO ;W * --me-Um=flashCtrN

VelseW * 9,P=signalPeds0P'/,=9LA4A1N carsDellow entry * CA!,=D'LLCG e2it * )-8'C@) V0me-Um=flashCtr #1 OO ;W * 9,P=signalPeds0P'/,=/C4)=GALA1N

offline entry * e2it * C4 )-8'C@) * me-Um=flashCtr XO #N

V0me-Um=flashCtr #1 OO ;W * CA!,=!'/N P'/,=/C4)=GALAN VelseW * CA!,=9LA4AN P'/,=9LA4AN

Copyright Quantum Leaps, LLC All !ights !eser"ed

!7 of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino )he $iggest ad"antage of hierarchical state machines 0<,8s1 compared to the traditional finite state machines 0>,8s1 is that <,8s remo"e the need for repetitions of actions and transitions that occur in the non-hierarchial state machines Githout this a$ility, the comple2ity of non-hierarchical state machines Ie2plodesJ e2ponentially with the comple2ity of the modeled system, which renders the formalism impractical for real-life pro$lems
N9"E: )he state machine concepts, state machine design, and hierarchical state machine implementation in C++ are not specific to Arduino and are out of scope of this document )he design and implementation of the /PP e2ample is descri$ed in the separate Application 4ote I/ining Philosophers Pro$lemJ 0see !elated /ocuments and !eferences1 )he P'L-CA4 crossing e2ample is descri$ed in the Application 4ote IP'L-CA4 CrossingJ 9oth these application notes are included in the Q-P file that contains the QP li$rary and e2amples for Arduino 0see Listing (1

Cnce you design your state machine0s1, you can code it $y hand, which the QP framewrok makes particularly straightforward, or you can use the Q8 tool to generate code automatically, as descri$ed in ,ection ##

Copyright Quantum Leaps, LLC All !ights !eser"ed

!8 of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino

,oard Support Pac*age -,SP. #or Arduino


)he QP e2ample sketches 0/PP and P'L-CA41 contain the file b p!"pp, which stands for 9oard ,upport Package 09,P1 )his 9,P contains all $oard-related code, which consists of the $oard initiali:ation, interrupt ser"ice routines 0-,!s1, idle processing, and assertion handler )he following sections e2plain these elements

+&!

,SP %nitialiBation
)he 9,P initiali:ation is done in the function /#P1init() -t is minimal, $ut generic for most Arduino $oards )he most important step is initiali:ation of the @ser L'/ 0connected to PC!)91 and the serial port, which is used to output the data in the e2ample applications -f you use other peripherals as well, you /#P1init() is the $est for such additional initiali:ation code 2isting 4: ,SPAinit-. #unction #or the DPP e=ample -#ile bsp."pp. void /#P1init(void) { **R/ = $;33; P=RA/ = $;$$; #erial!begin(&&Q-$$); #erial!println(K#tartK); + // 8ll P=RA/ pin are output (u er ()*) // drive all pin low

+&2

%nterrupts
An interrupt is an asynchronous signal that causes the Arduino processor to sa"e its current state of e2ecution and $egin e2ecuting an -nterrupt ,er"ice !outine 0-,!1 All this happens in hardware 0without any e2tra code1 and is "ery fast After the -,! returns, the processor restores the sa"ed state of e2ecution and continues from the point of interruption Dou need to use interrupts to work with QP At the minimum, you must pro"ide the s3stem cloc* tic* interrupt, which allows the QP framework to handle the timeout request that acti"e o$Bects make Dou might also want to implement other interrupts as well Ghen working with interrupts you need to $e careful when you ena$le them to make sure that the system is ready to recei"e and process interrupts QP pro"ides a special call$ack function 2344on#tartup(), which is specifically designed for configuring and ena$ling interrupts 2344on#tartup() is called after all initiali:ation completes, $ut $efore the framework enters the endless e"ent loop Listing 3 shows the implementation of 2344on#tartup() for QP, which configures and starts the system clock tick interrupt -f you use other interrupts, you need to add them to this function as well 2isting 7: $on#iguring and starting interrupts in Q$%%on&tartup() void 2344on#tartup(void) { // et Ai%er- in <A< %ode' &/&$-M pre "aler' tart the ti%er ti"@ing A<<R-8 = (& ?? IGB-&) 7 ($ ?? IGB-$); A<<R-/ = (& ?? <#-- ) 7 (& ?? <#-&) 7 (& ?? <#-$); // &/-W&$ 8##R X= Y(& ?? 8#-); AIB#D- = (& ?? =<I)-8); // )nable AIB)R- "o%pare Interrupt A<9A- = $; (-) =<R-8 = AI<D1*IHI*)R; // %u t be loaded la t for 8t%ega&ET and friend + (&)

Copyright Quantum Leaps, LLC All !ights !eser"ed

!/ of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino 0#1 0(1 )his 9,P uses )imer& as the source of the periodic clock tick interrupt 0)imer# is already used to pro"ide the Arduino %illi() ser"ice1 )he output compare register 0CC!&A1 is loaded with the "alue that determines the length of the clock tick interrupt )his "alue, in turn, is determined $y the /#P1<(I<D#1P)R1#)< constant, which currently is set to #;; times per second

>or each ena$led interrupt you need to pro"ide an -nterrupt ,er"ice !outine 0-,!1 -,!s are not the regular C++ functions, $ecause they need a special code to enter and e2it 4onetheless, the Arduino compiler 0GinAE!1 supports writing -,!s in C++, $ut you must inform the compiler to generate the special -,! code $y using the macro I#R() Listing P ,hown the system clock tick -,! for Arduino 2isting 8: S3stem cloc* tic* %SR #or Arduino -#ile bsp."pp. (&) I#R(AIB)R-1<=BP81ve"t) { // 9o need to "lear the interrupt our"e in"e the Ai%er- "o%pare // interrupt i auto%ati"ally "leard in hardware when the I#R run ! (-) 0#1 0&1 + 2344ti"@(); // pro"e all ar%ed ti%e event

)he definition of e"ery -,! must $egin with the I#R() macro )he system clock tick must in"oke 2344ti"@() and can also perform other actions, if necessary

+&)

%dle Processing
)he following Listing 5 shows the 2344onIdle() Icall$ackJ function, which is in"oked repetiti"ely from the Arduino loop() function whene"er there are no e"ents to process 0see >igure &1 )his call$ack function is located in the b p!"pp file in each QP sketch 2isting /: Activating low-power sleep mode #or Arduino -#ile bsp."pp. (&) void 2344onIdle() { (-) (L) R#)R1()*1=9(); R#)R1()*1=33(); // toggle the R er ()* on 8rduino on and off' ee 9=A)&

(M) Jifdef #8H)1P=I)R (Q) (E) (S) (T) (U) #B<R = ($ ?? #B$) 7 (& ?? #)); // idle leep %ode' adCu t to your proCe"t ee 9=A)-

// never eparate the following two a e%bly in tru"tion ' 11a %11 11volatile11 (K eiK KGnGtK 44 ); 11a %11 11volatile11 (K leepK KGnGtK 44 ); #B<R = $; Jel e 231I9A1)98/()(); Jendif +

// "lear the #) bit

0#1

)he call$ack function 2344onIdle() is called from the Arduino loop whene"er the e"ent queues ha"e no more e"ents to process 0see also ,ection (1, in which case only an e2ternal interrupt can 2 of 2/

Copyright Quantum Leaps, LLC All !ights !eser"ed

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino pro"ide new e"ents )he 2344onIdle() call$ack is called with interrupts disabled, $ecause the determination of the idle condition might change $y any interrupt posting an e"ent
N9"E: )he article I@sing Low-Power 8odes in >oreground * 9ackground ,ystemsJ 0httpK**www em$edded com*design*&;&#;(6&.1 e2plains the race condition associated with going to power sa"ing mode and how to a"oid this race condition safely in the simple foreground*$ackground type schedulers

0&-(1 )he ArduinoLs @ser L'/ is turned on and off to "isuali:e the idle loop acti"ity 9ecause the idle call$ack is called "ery often the human eye percei"es the L'/ as glowing at a low intensity )he $rightness of the L'/ is proportional to the frequency of in"ocations of the idle call$ack Please note that the L'/ is toggled with interrupts locked, so no interrupt e2ecution time contri$utes to the $rightness of the @ser L'/ 061 Ghen the macro #8H)1P=I)R is defined, the following code $ecomes acti"e 0.1 )he #B<R register is loaded with the desired sleep mode 0idle mode in this case1 and the ,leep 'na$le 0,'1 $it is set Please note that the sleep mode is not acti"e until the ,L''P command 0?1 )he interrupts are unlocked with the #)I instruction 031 )he sleep mode is acti"ated with the #())P instruction
4C)'K )he AE! datasheet is "ery specific a$out the $eha"ior of the ,'--,L''P instruction pair /ue to pipelining of the AE! core, the ,L''P instruction is guaranteed to e2ecute $efore entering any potentially pending interrupt )his means that ena$ling interrupts and acti"ating the sleep mode is atomic, as it should $e to a"oid non-deterministic sleep

0P1 051

As recommended in the AE! datasheet, the #B<R register should $e e2plicitly cleared upon the e2it from the sleep mode -f the macro #8H)1P=I)R is not defined the low-power mode is not acti"ated so the processor ne"er goes to sleep <owe"er, e"en in this case you must ena$le interrupts, or else they will stay disa$led fore"er and your Arduino will free:e

+&+

Assertion Handler Q_on'ssert()


As descri$ed in Chapter ? of the $ook IPractical @8L ,tatecharts in C*C++, ,econd 'ditionJ VP,iCC&W 0see ,ection !elated /ocuments and !eferences1, all QP components use internally assertions to detect errors in the way application is using the QP ser"ices Dou need to define how the application reacts in case of assertion failure $y pro"iding the call$ack function 21on8 ert() )ypically, you would put the system in fail-safe state and try to reset -t is also a good idea to log some information as to where the assertion failed )he following code fragment shows the 21on8 ert() call$ack for AE! )he function disa$les all interrupts to pre"ent any further damage, turns on the @ser L'/ to alert the user, and then performs the software reset of the Arduino processor void 21on8 ert("har "on t 21R=B N "on t 21R=B1H8R file' int line) { 231I9A1*I#8/()(); // di able all interrupt R#)R1()*1=9(); // R er ()* per%anently =9 a % volatile (KC%p $;$$$$K); // perfor% a oftware re et of the 8rduino +

Copyright Quantum Leaps, LLC All !ights !eser"ed

2! of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino

QP0$11 2ibrar3 #or Arduino


)he QP framework is deployed as an Arduino li$rary, which you import into your sketch As shown in Listing (, the whole li$rary consists Bust of three files )he following sections descri$e these files

(&!

"he qp_port.h!Header ;ile


Ghen you import the li$rary 0Arduiono -/', menu ,ketch R -mport Li$rary R qp1, the Arduino -/' will insert the line IJin"lude ?0p1port!h>J into your currently open sketch file )he 0p1port!h file 0shown in Listing #;1 contains the adaptations 0port1 of QP to the AE! processor followed $y the platformindependent code for QP )ypically, you should not need to edit this file, e2cept perhaps when you want to increase the ma2imum num$er of state machines you can use in your applications )his num$er is configured $y the macro 231B8F18<AIH) and currently is set to P Dou can increase it to ?(, inclusi"e, $ut this costs additional memory 0!A81, so you should not go too high unnecessarily

2isting ! : "he <pAport&h header #ile #or the QP librar3 Jifndef 0p1port1h Jdefine 0p1port1h Jin"lude Jin"lude Jin"lude Jin"lude ? tdint!h> ?avr/pg% pa"e!h> ?avr/io!h> ?avr/interrupt!h> // a""e // <UU. tandard e;a"t.width integer ing data in the progra% %e%ory (PR=GB)B) // #R)G definition // "li()/ ei()

// the %a"ro 2D1PR))BPAIH) ele"t the pree%ptive 2D @ernel // (default i the "ooperative KHanillaK @ernel) //Jdefine 2D1PR))BPAIH) & // allow u ing the 2D priority "eiling %ute; //Jdefine 2D1BRA)F & Jdefine Jdefine Jdefine Jdefine Jdefine Jdefine // variou 231B8F18<AIH) T 231)H)9A1#IZ1#IZ) & 231)2R)R)1<AR1#IZ) & 231BP==(1#IZ1#IZ) & 231BP==(1<AR1#IZ) & 231AIB))HA1<AR1#IZ) 23 obCe"t i5e "onfiguration for thi port

Jdefine 21R=B

// the %a"ro [PR=GB)B[ allo"ate PR=GB)B

"on t obCe"t

to R=B

Jdefine 21R=B1/VA)(ro%1var1) Jdefine 231I9A1*I#8/()() Jdefine 231I9A1)98/()() Jdefine 231<RIA1#A8A1AVP) Jdefine 231<RIA1)9ARV( tat1) ( tat1) = #R)G; G "li(); G

// the %a"ro [21R=B1/VA)[ read a byte fro% R=B pg%1read1byte1near(X(ro%1var1)) // 23 interrupt di able/enable "li() ei() // 23 "riti"al uintT1t do { G e"tion entry/e;it

Copyright Quantum Leaps, LLC All !ights !eser"ed

22 of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino + while ($) Jdefine 231<RIA1)FIA( tat1) Jifdef 2D1PR))BPAIH) Jdefine 2D1I#R1)9ARV() (662D1int9e t1) // 2D interrupt entry and e;it

(#R)G = ( tat1))

Jdefine 2D1I#R1)FIA() do { G ..2D1int9e t1; G if (2D1int9e t1 == (uintT1t)$) { G uintT1t p = 2D1 "hedPrio1(); G if (p != (uintT1t)$) { G 2D1 "hed1(p); G + G + G + while ($) // allow u ing the 2D priority "eiling %ute; Jdefine 2D1BRA)F & Jendif // 2D1PR))BPAIH)

////////////////////////////////////////////////////////////////////////////// // *= 9=A <H89G) 89VAHI9G /)(=I AHI# (I9) ! ! ! Jendif // 0p1port1h

(&2

"he qp_port."pp ;ile


)he 0p1port!"pp source file 0shown in Listing ##1 contains the Arduino-specific adaptation of QP )his file defines the Arduino loop() function, which calls the QP framework to run the application )he function 2344run() implements the e"ent loop shown in >igure & 2isting !!: "he qp_port."pp source #ile #or the QP librar3 Jin"lude K0p1port!hK //21*)3I9)1AHI#1B=*R()(K0p1portK) //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! e;tern K<K void loop() { (void)2P1 2344run(); //run the appli"ation' 9=A)4 2344run() doe n[t return + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Jifdef 2D1PR))BPAIH) void 2D1init(void) { + // devi"e driver ignal off et at the top of the ignal range Jif (21#IG98(1#IZ) == &) Jdefine *)H1*RIH)R1#IG tati"1"a t?2P1 2#ignal>($;33R . TR) Jelif (21#IG98(1#IZ) == -) Jdefine *)H1*RIH)R1#IG tati"1"a t?2P1 2#ignal>($;3333R . L-R) Jelif (21#IG98(1#IZ) == M) // 2P port

Copyright Quantum Leaps, LLC All !ights !eser"ed

2) of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino Jdefine *)H1*RIH)R1#IG tati"1"a t?2P1 2#ignal>($;33333333R . -QER) Jel e Jerror K21#IG98(1#IZ) not defined or in"orre"tK Jendif Jendif
N9"E: )he QP framework pro"ides the generic definition of the Arduino loop() function, so that you do not need to pro"ide it in your applications -n fact, your Arduino sketch will not $uild correctly if you define the loop() function yourself All you need to pro"ide is the Arduino etup() function

Additionally, the 0p1port!"pp source file pro"ides the definition of the C++ operator delete(), which somehow the Arduino compiler 0GinAE!1 uses when "irtual functions are present Dou should not edit the 0p1port!"pp source file

(&)

"he qp."pp ;ile


)he 0p!"pp source file contains the platform-independent code of the QP li$rary, which contains the facilities for e2ecuting state machines, queuing e"ents, handling time, etc Dou should not edit the 0p!"pp source file

Copyright Quantum Leaps, LLC All !ights !eser"ed

2+ of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino

5sing Preemptive Q6 6ernel


)he structure of the QP*C++ framework for Arduino discussed in ,ection # ( corresponds to the simple cooperati"e scheduler called IEanillaJ <owe"er, the QP framework can also e2ecute Arduino applications using the preemptive Q6 *ernel )he difference $etween non-preempti"e kernel 0like IEanillaJ1 and preempti"e kernel 0like QA1 is shown in >igure #6
N9"E: A *ernel is the part of the system that manages computer time $y assigning the processor to "arious tasks

;igure !+: E=ecution pro#iles o# a non-preemptive *ernel -a. and a preemptive *ernel -b.&
priority -,! produces e"ent for highpriority task interrupt entry 0#a1 low-priority task 0(a1 %SR 06a1 0&a1 interrupt return kernel

-a.
high-priority task $locking call or e2plicit yield time

low-priority task 0.a1 6 0?a1

priority

-,! produces e"ent for highpriority task interrupt entry

0($1 06$1 %SR 6 0.$1 0&$1 preempted interrupt return

kernel

-b.

high-priority task 0?$1 6 03$1 conte2t switch low-priority task time

0#$1

low-priority task

A non-preempti"e kernel 0panel 0a1 in >igure #61 gets control only after completion of the processing of each e"ent -n particular, -nterrupt ,er"ice !outines 0-,!s1 always return to the same task that they preempted -f an -,! posts an e"ent to a higher-priority task than currently e2ecuting, the higher-priority task needs to wait until the original task completes )he task-le"el response of a non-preempti"e kernel is not deterministic, $ecause it depends when other tasks complete e"ent processing )he upside is a much easier sharing of resources 0such as glo$al "aria$les1 among the tasks A preempti"e kernel 0panel 0$1 in >igure #61 gets control at the end of e"ery -,!, which allows a preempti"e kernel to return to a di##erent task than the originally preempted one -f an -,! posts an e"ent to a higher-priority task than currently e2ecuting, the preempti"e kernel can return to the higher-priority task, which will ser"ice the e"ent without waiting for any lower-priority processing A preempti"e kernel can guarantee deterministic e"ent responses posted to high-priority tasks, $ecause the lower-priority tasks can $e preempted 9ut this determinism comes a price of increased comple2ity and possi$ility of corrupting any shared resources among tasks A preempti"e kernel can perform a conte2t switch at any point where interrupts are not disa$led 0so essentially $etween most machine Copyright Quantum Leaps, LLC All !ights !eser"ed 2( of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino instructions1 Any such conte2t switch might lead to corruption of shared memory or other shared resources, and a preempti"e kernel usually pro"ides special mechanisms 0such as a mute21 to guarantee a mutually e2clusi"e access to any shared resources

4&!

Re-con#iguring the QP0$11 2ibrar3 to 5se Preemptive Q6 6ernel


!e-configuring the QP to use the preempti"e QA kernel, instead of the simple IEanillaJ kernel, is "ery easy Dou need to remo"e a comment in front of the line starting with Jdefine 2D1PR))BPAIH) in the 0p1port!h header file located in the Arduino li$rary directory 0see Listing #1 Additionally, if you want to use the QA mute2, you need to uncomment the line starting with Jdefine 2D1BRA)F )he following Listing #& highlights the changes

2isting !2: "he <pAport&h header #ile #or the QP librar3 Jifndef 0p1port1h Jdefine 0p1port1h Jin"lude Jin"lude Jin"lude Jin"lude ? tdint!h> ?avr/pg% pa"e!h> ?avr/io!h> ?avr/interrupt!h> // a""e // <UU. tandard e;a"t.width integer ing data in the progra% %e%ory (PR=GB)B) // #R)G definition // "li()/ ei()

// the %a"ro 2D1PR))BPAIH) ele"t the pree%ptive 2D @ernel // (default i the "ooperative KHanillaK @ernel) Jdefine 2D1PR))BPAIH) & // allow u ing the 2D priority "eiling %ute; Jdefine 2D1BRA)F & ! ! !

N9"E: Compared to the simple non-preempti"e IEanillaJ kernel, the preempti"e QA kernel requires more stack space >ortunately, unlike most preempti"e kernels, the run-to-completion QA kernel requires a single stack for nesting all the stack conte2t >or more information a$out the QA kernel, please refer to Chapter #; in the IPractical @8L ,tatechartsJ $ook and to the ',/ article I9uild the ,uper-,imple )askerJ 0see ,ection !elated /ocuments and !eferences1

4&2

"he <pAdppA<* E=ample


)he e2ample 0p1dpp10@ located in the Arduino e2amples directory 0see Listing #1 demonstrates the /PP same application descri$ed in ,ection & &, $ut running under the preempti"e QA kernel )he changes to the application are all confided to the $sp!"pp file located in the application folder )he following Listing #( highlights the changes

2isting !): "he bsp&cpp #ile #or the <pAdppA<* e=ample ! ! ! // I#R ...................................................................... I#R(AIB)R-1<=BP81ve"t) { // 9o need to "lear the interrupt our"e in"e the Ai%er- "o%pare Copyright Quantum Leaps, LLC All !ights !eser"ed 24 of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino // interrupt i QK_I&R_E(TR)()# 2344AI<D(Xl1AIB)R-1<=BP8); + QK_I&R_E*IT()# auto%ati"ally "leard in hardware when the I#R run ! // infor% 2D @ernel about entering an I#R // pro"e all ar%ed ti%e event

// infor% 2D @ernel about e;iting an I#R

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +oid!QK%%onIdle()!, 231I9A1*I#8/()(); R#)R1()*1=9(); R#)R1()*1=33(); 231I9A1)98/()(); Jifdef #8H)1P=I)R #B<R = ($ ?? #B$) 7 (& ?? #)); // idle leep %ode' adCu t to your proCe"t 11a %11 11volatile11 (K leepK KGnGtK 44 ); #B<R = $; // "lear the #) bit Jendif + ! ! ! As shown in Listing #(, e"ery -,! for the preempti"e QA kernel must in"oke the macro 2D1I#R1)9ARV() at the $eginning 0and $efore calling any QP function1 and must in"oke the macro 2D1I#R1)9ARV() right $efore the end )hese macros gi"e control to the QA kernel, so that it can perform preemptions Additionally, the QA kernel handles the idle condition differently 0actually simpler1 than the nonpreempti"e IEanillaJ kernel )he idle call$ack for the QA kernel is called 2D44onIdle() and the difference is that it is called with interrupts ena$led, in contrast to the 2344onIdle() call$ack discussed $efore // toggle the R er ()* on 8rduino on and off' ee 9=A)&

4&)

Running the <pAdppA<* E=ample


)he e2ample 0p1dpp10@ runs e2actly the same as the non-preempti"e "ersion 0p1dpp

Copyright Quantum Leaps, LLC All !ights !eser"ed

27 of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino

Related Documents and Re#erences


Document IPractical @8L ,tatecharts in C*C++, ,econd 'ditionJ VP,iCC&W, 8iro ,amek, 4ewnes, &;;P 2ocation A"aila$le from most online $ook retailers, such as Ama:on com ,ee alsoK httpK**www statemachine com*psicc& htm

QP /e"elopment Aits for Arduino, Quantum Leaps, LLC, &;## IApplication 4oteK /ining Philosopher Pro$lem ApplicationJ, Quantum Leaps, LLC, &;;P IApplication 4oteK P'/estrian L-ght CC4trolled 0P'L-CA41 Crossing ApplicationJ, Quantum Leaps, LLC, &;;P I@sing Low-Power 8odes in >oreground*9ackground ,ystemsJ, 8iro ,amek, 'm$edded ,ystem /esign, Ccto$er &;;3 QP /e"elopment Aits for AE!, Quantum Leaps, LLC, &;;P IQP*C++ !eference 8anualJ, Quantum Leaps, LLC, &;## >ree Q8 graphical modeling and code generation tool, Quantum Leaps, &;## I9uild a ,uper-,imple )askerJ, $y 8iro ,amek and !o$ert Gard, ',/, &;;?

httpK**www state-machine com*arduino httpK**www statemachine com*resources*A4=/PP pdf httpK**www statemachine com*resources*A4=P'L-CA4 pdf httpK**www em$edded com*design*&;&#;(6&.

httpK**www state-machine com*a"r httpK**www statemachine com*do2ygen*qpcpp* httpK**www state-machine com*qm httpK**www eetimes com*7eneral*PrintEiew*6; &.?5# httpK**www statemachine com*resources*samek;? pdf

Copyright Quantum Leaps, LLC All !ights !eser"ed

28 of 2/

Application Note: Event-Driven Arduino Programming with QP state-machine com*arduino

$ontact %n#ormation
Quantum 2eapsG 22$ #;( Co$$le !idge /ri"e Chapel <ill, 4C &3.#? @,A +# P?? 6.; L'AP 0toll free, @,A only1 +# 5#5 P?5-&55P 0>AY1 e-mailK info@quantum-leaps com G'9 K httpK**www quantum-leaps com httpK**www state-machine com Arduino Pro@ect homepage: httpK**arduino cc

Copyright Quantum Leaps, LLC All !ights !eser"ed

2/ of 2/

Anda mungkin juga menyukai