Vous êtes sur la page 1sur 30

QP state machine frameworks for Arduino

Application Note
Event-Driven Arduino
Programming with QP
Document Revision C
December 2!!
Copyright Quantum Leaps, LLC
info@quantum-leapscom
wwwstate-machinecom
Copyright Quantum Leaps, LLC All !ights !eser"ed
"able o# Contents
! $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 'tarted %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% (
&# ,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 'tructure o# an Arduino '*etch #or QP %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% !)
(# )he setup01 function #(
(& )he Application -nterface 0'"ents and ,ignals1 #.
(( )he ,tate 8achines #9
+ ,oard 'upport Pac*age -,'P. #or Arduino %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% !/
6# :,P -nitiali;ation #<
6& -nterrupts #<
6( -dle Processing #5
66 Assertion =andler Q>onAssert01 &?
( QP0C11 2ibrar3 #or Arduino %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2!
.# )he qp>porth =eader @ile &#
.& )he qp>portcpp @ile &&
.( )he qpcpp @ile &(
4 5sing Preemptive Q6 6ernel %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2+
9# !e-configuring the QP*C++ Li$rary to Ase Preempti"e QB Bernel &.
9& )he qp>dpp>qk '2ample &.
9( !unning the qp>dpp>qk '2ample &9
7 Related Documents and Re#erences %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 27
/ Contact $n#ormation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2/
i
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++ state machine framework, which is
like a modern real-time operating s3stem 0!)C,1 specifically designed for e2ecuting e"ent-dri"en state
machines 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 wwwarduinocc1 is an open-source
electronics prototyping platform, designed to make
digital electronics more accessi$le to non-specialists
in multidisciplinary proEects )he hardware consists of
a simple Arduino printed circuit $oard with an Atmel
AF! 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 Ga"a-$ased integrated de"elopment
en"ironment 0called Processing1 that runs on a
desktop computer 0Hindows, Linu2, or 8ac1
Arduino $oards can $e purchased pre-assem$led at
relati"ely low cost 0I&?-I.?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 JshieldsK, 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 0A,:, CA4, 'thernet,
wireless, etc1, 7P,, motor control, ro$otics, and
many other functions A steadily growing list of
Arduino shields is maintained at shieldlistorg
N8"E9 )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
! of 2/
:igure !9 A stac* o# Arduino shields
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
!%2 Event-driven programming with Arduino
)raditionally, Arduino programs are written in a se;uential manner Hhene"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 Haiting Jin-lineK 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 insideL
2isting !9 'e;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 erial port
"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
+
Although this approach is functional in many situations, it doesnMt 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 0eg, a $utton press1, it is not doing any other work and is not responsive to
other e"ents 0eg, 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 $attery-
powered de"ices
N8"E9 -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
An e"ent-dri"en framework can $e "ery simple -n fact, many proEects in the Arduino Playground *
)utorials and !esources * Protothreading, )iming N 8illis section pro"ide e2amples of rudimentary e"ent-
dri"en frameworks )he general structure of all these rudimentary frameworks is shown in Listing &
2isting 29 "he simplest event-driven program structure%
"he highlighted code conceptuall3 belongs to the event-driven #ramewor*%
void loop() {
if (event&()) // event& o""urred,
event&Handler(); // pro"e event&
2 of 2/
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
if (event-()) // event- o""urred,
event-Handler(); // pro"e event-
! ! ! // handle other event
+
)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(), etc1 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 Eust following the polling loops )his arrangement allows a sequential program to mo"e naturally
from one e"ent to the ne2t1
Anfortunately, the Eust 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 ele-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 Jdispense productK $utton-press e"ent until the full payment has $een collected )his
means that somewhere inside the dipeneProdu"t/uttonPreHandler() 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 0if.s and ele-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 Eust starting to de"elop is the ,topwatch proEect 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
JspaghettiK 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 QP0C11 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 donMt pro"ide a true e"ent-dri"en programming en"ironment for a num$er of
reasons @irst, the simple frameworks donMt 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
) of 2/
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
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
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
N8"E9 )he e"ent queue, state machine, and a unique priority is collecti"ely called an active ob?ect
)he design guarantees that the dipat"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
N8"E9 )he J"anillaK 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-to-
completion step )he QP*C++ framework contains also a more ad"anced, fully preemptive real-time
kernel called QB )he QB kernel can $e also used with Arduino when you define the macro
QK_PREEMPTIVE in the 0p1port!h header file ,ee ,ection 9 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
+ of 2/
:igure 29 Event-driven QP0C11 #ramewor* with multiple event ;ueues and state machines
=vanilla> scheduler
% % %
% % % dispatch0e1O
e P queueget01O
dispatch0e1O
e P queueget01O
dispatch0e1O
e P queueget01O
% % %
find highest-priority
non-empty queue
all queues empty
0idle condition1
idle
processing
priority P # priority P n-# priority P n
priority P ?
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
2 &etting 'tarted
)o focus the discussion, this Application 4ote uses the Arduino A4C $oard $ased on the Atmel
Atmega(&<P 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
2%! 'o#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 )9 Contents o# the ;p@arduino%Aip 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 Philoopher Proble% e;a%ple appli"ation
7 6.891P)(I<89!pdf : P)detrian (Ight <=9trolled (P)(I<89) "roing 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 Philoopher Proble% (*PP) e;a%ple
7 7 7 6.bp!"pp . /oard #upport Pa"@age i%ple%entation for *PP
7 7 7 6.bp!h . /oard #upport Pa"@age interfa"e for *PP
7 7 7 6.dpp!h . *PP interfa"e (ignal' event' global)
7 7 7 6.philo!"pp . Philoopher a"tive obAe"t
7 7 7 6.table!"pp . Bable 8"tive obAe"t
7 7 7 6.0p1dpp!ino . 2P/*PP 8rduino @et"h
7 7 7
7 7 6.0p1dpp10@/ : *PP e;a%ple with the pree%ptive 2C @ernel (#e"tion D)
( of 2/
:igure )9 Arduino 5N8 board
!eset $utton
Atmega(&<P
microcontroller
,tandard Arduino
pin-header
A,: Connector
to the host PC
Aser L'/
,tandard Arduino
pin-header
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
7 7 7 6.bp!"pp . /oard #upport Pa"@age i%ple%entation for *PP
7 7 7 6.bp!h . /oard #upport Pa"@age interfa"e for *PP
7 7 7 6.dpp!h . *PP interfa"e (ignal' event' global)
7 7 7 6.philo!"pp . Philoopher a"tive obAe"t
7 7 7 6.table!"pp . Bable 8"tive obAe"t
7 7 7 6.0p1dpp!ino . 2P/*PP 8rduino @et"h
7 7 7
7 7 6.0p1peli"an/ : P)detrian (Ight <=9trolled (P)(I<89) "roing e;a%ple
7 7 7 6.bp!"pp . /oard #upport Pa"@age i%ple%entation for P)(I<89
7 7 7 6.bp!h . /oard #upport Pa"@age interfa"e for P)(I<89
7 7 7 6.peli"an!"pp . P)(I<89 a"tive obAe"t
7 7 7 6.peli"an!h . P)(I<89 interfa"e (ignal' event' global)
7 7 7 6.0p1peli"an!ino . 2P/P)(<I89 8rduino @et"h
7
7 7 6.0%1peli"an/ : P)(I<89 "roing e;a%ple for the graphi"al 2E tool
7 7 7 6.peli"an!0% . Bhe 2E %odel of the P)(<I89 "roing appli"ation
7 (generate all the "ode auto%ati"ally)
7
6.librarie/ ==> goe to the ?8rduino>/librarie/ folder
7 6.0p/ . 2P library
7 7 6."opying!t;t . ter% of "opying thi "ode
7 7 6.GP(-!BFB . GP( verion - open our"e li"ene
7 7 6.0p!"pp . 2P/<66 platfor%.independent i%ple%entation
7 7 6.0p1port!"pp . 2P/<66 port for 8rduino i%ple%entation
7 7 6.0p1port!h . 2P/<66 port for 8rduino interfa"e
)he complete QP*C++ li$rary code consists of Eust three source filesL 0p1port!h, 0p1port!"pp, and
0p!"pp )he QP li$rary is accompanied with four e2amplesL 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
4 of 2/
:igure +9 5nAipping qp_arduino.zip into the Arduino director3% Bou need to con#irm that
3ou want to merge the #olders examples and libraries%
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
Dou need to un;ip the 0p1arduino!5ip archi"e into the Arduino directory 0eg, arduino.&!$G1 As
shown in @igure 6, on Hindows you can simply open the Q-P file with the Hindows '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 Eust choose the 0p1dpp e2ample
At this point you must connect the Arduino $oard to your computer "ia a A,: ca$le )he Arduino $oard is
powered from the A,: connector 0see @igure (1, so you donMt need to attach e2ternal power Dou upload
the code to the Arduino microcontroller $y pressing the Apload $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 Aser L'/
0see @igure (1 start to glow with low intensity 0not full on1 )he Aser 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 'erial Conitor $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
7 of 2/
:igure (9 8pening -le#t. and veri#3ing -right. the DPP e<ample in the Arduino $DE%
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
N8"E9 )he design and implementation of the /ining Philosopher Pro$lem application, including state
machines, is descri$ed in the Application 4ote J/ining Philosopher Pro$lemK 0see !elated
/ocuments and !eferences1
)o understand what the messages in the ,erial
8onitor window mean, you need to know whatMs
going in the /ining Philosopher Pro$lem 0/PP1 -t is
specified as followsL @i"e philosophers are gathered
around a ta$le with a $ig plate of spaghetti in the
middle 0see @igure 31 :etween 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 Hhen 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
/ of 2/
:igure 49 DPP e<ample output to the Arduino 'erial Conitor%
Ca*e sure that the 'erial Conitor is set up #or !!(2 baud rate%
,erial
8onitor
:utton
:igure 79 Dining Philosopher Problem with #ive
philosophers numbered %%+%
(
&
#
?
6
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
2%) Running the PE2$CAN Crossing 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 <
:efore you can test the e2ample, you
need to understand the how it is
supposed to work ,o, the P'L-CA4
crossing operates as followsL )he
crossing 0see @igure 51 starts with cars
ena$led 0green light for cars1 and
pedestrians disa$led 0J/onMt HalkK
signal for pedestrians1 )o acti"ate the
traffic light change a pedestrian must
push the $utton at the crossing, which
generates the P'/,>HA-)-47 e"ent
-n response, oncoming cars get the
yellow light, which after a few seconds
changes to red light 4e2t, pedestrians
get the JHalkK signal, which shortly
D of 2/
:igure /9 8pening -le#t. and veri#3ing -right. the PE2$CAN crossing e<ample in the Arduino $DE%
:igure D9 Pedestrian 2igtht C8Ntrolled -PE2$CAN. crossing%
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
thereafter changes to the flashing J/onMt HalkK signal After the J/ontM HalkK signal stops flashing, cars
get the green light again After this cycle, the traffic lights donMt respond to the P'/,>HA-)-47 $utton
press immediately, although the $utton Jremem$ersK 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 JofflineK mode the cars get the flashing red light and the
pedestrians get the flashing J/onMt HalkK signal At any time the operator can turn the crossing $ack
online 0$y pro"iding the C4 e"ent1
N8"E9 )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 JP'L-CA4 Crossing ApplicationK 0see !elated
/ocuments and !eferences1
! of 2/
:igure !9 PE2$CAN crossing e<ample output to the Arduino 'erial Conitor%
Bou in?ect events to the application b3 sending *e3 stro*es 9
EpE #or PED'@FA$"$N&G E#E #or 8:: and EoE #or 8N%
,erial
8onitor
:utton
)ype MpM
and press
,end
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
2%+ &enerating the PE2$CAN '*etch with the QC Codeling "ool
)he P'L-CA4 crossing e2ample for Q8% 0located in ?0p1arduino!5ip>/e;a%ple/0p/
0%1peli"an/, see Listing (1 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
N8"E9 )o start working with the Q8% modeling tool, you need to download the tool from state-
machinecom Q8% is currently supported on Hindows 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 J7enerate CodeK
$utton, as shown in @igure ## Q8 will then generate the complete Arduino sketch that you open in the
Arduino -/' as any other sketch
!! of 2/
:igure !!9 PE2$CAN crossing model opened in the QC graphical modeling tool%
Press to generate
P'L-CA4 sketch
automatically
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
2%( Codi#3ing the E<amples to Reduce Power Consumption
As mentioned in ,ection #&, the QP*C++ framework allows you to take ad"antage of the Arduino
processorMs low-power sleep mode, which is the only way to achie"e really low-power design :oth
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 Eust to ena$le this code As shown in
@igure #&, you select the file bp!"pp 0:oard ,upport Package1 and uncomment the definition of the
#8H)1P=I)R macro
After you recompile the code and download to Arduino, you will see that the Aser 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 Aser L'/ means that the Arduino :ackground 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 bp!"pp
!2 of 2/
:igure !29 Codi#3ing QP e<amples to run in low-power mode
,elect $spcp and
uncomment the definition
of ,AF'>PCH'!
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
) "he 'tructure o# an Arduino '*etch #or QP
'"ery e"ent-dri"en Arduino sketch for QP consists of four rough groupsL setup, e"ents, acti"e o$Eects,
and $oard support package 0:,P1 )ypically, the main sketch file 0the !pde 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$Eects are defined in source files 0the !"pp files1, one acti"e o$Eect 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 +9 "3pical Arduino s*etch #or QP -#ile qp_dpp.pde.
(&) Jin"lude ?0p1port!h>
(-) Jin"lude Kdpp!hK
(L) Jin"lude Kbp!hK
// (o"al."ope obAe"t .......................................................
(M) tati" 2)vent "ont Nl1table2ueue#toO91PHI(=P;
(Q) tati" 2)vent "ont Nl1philo2ueue#toO91PHI(=PO91PHI(=P;
(D) tati" 2#ub"r(it l1ub"r#toOE8F1PR/1#IGP;
(S) tati" Bable)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 RB @ernel
// initiali5e event pool!!!
(&&) 2344poolInit(l1%lPool#to' i5eof(l1%lPool#to)' i5eof(l1%lPool#toO$P));
(&-) 2344pInit(l1ub"r#to' 21*IE(l1ub"r#to)); // init publih.ub"ribe
// tart the a"tive obAe"t!!!
uintT1t n;
for (n = $; n ? 91PHI(=; 66n) {
(&L) 8=1PhiloOnP.>tart((uintT1t)(n 6 &)'
l1philo2ueue#toOnP' 21*IE(l1philo2ueue#toOnP));
+
(&M) 8=1Bable.>tart((uintT1t)(91PHI(= 6 &)'
l1table2ueue#to' 21*IE(l1table2ueue#to));
+
0#1 'ach sketch for QP imports the QP li$rary port to Arduino 0the ?0p1port!h> header file1
0&1 )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
0(1 )he header file $sp!h contains the facilities pro"ided $y the :oard ,upport Package )his file is also
shared among most files in the sketch
!) of 2/
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
06-.1 )he application must pro"ide storage for e"ent queues of all acti"e o$Eects 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
091 -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$Eects 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 E8F1PR/1#IG found in the application header file
031 )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 Bable)vt e"ents and e"ents without parameters 02)vent1
0<1 Dou pro"ide only the definition of the Arduino etup() function Dou donMt define the loop()
function, $ecause it is pro"ided in the framework 0see ,ection .&1
051 )he function /#P1init() initiali;es the Arduino $oard for this application and is defined in the
bp!"pp file
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 areL 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 $lock-
si;e pool must $e initiali;ed $efore the medium $lock-si;e pool
0#&1 )he function 2344pInit() initiali;es the pu$lish-su$scri$e e"ent deli"ery mechanism of QP )he
parameters of this function areL the pointer to the su$scri$er-list array and the dimension of this
array
N8"E9 )he utility macro 21*IE() 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$Eect as part of the application )he function takes the following parametersL
the pointer to the acti"e o$Eect, the priority of the acti"e o$Eect, the pointer to its e"ent queue, the
dimension 0length1 of that queue )he acti"e o$Eect priorities in QP are num$ered from # to
231E8F18<BIH), inclusi"e, where a higher priority num$er denotes higher urgency of the acti"e
o$Eect )he constant 231E8F18<BIH) is defined in the QP port header file 0f1port!h 0see
,ection .#1
N8"E9 At this point you ha"e pro"ided the QP framework with all the storage and acti"e o$Eect
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"ent-
loop shown in @igure &
!+ of 2/
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
)%2 "he Application $nter#ace -Events and 'ignals.
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 )8B1#IG signal represents the permission to eat to a Philosopher acti"e o$Eect,
whereas HR9GRV1#IG con"eys to the )a$le acti"e o$Eect 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)vent class pro"ided $y the framework ,pecifically, the 2)vent
class contains the mem$er sig, to represent the signal of that e"ent '"ent parameters are added in the
su$classes of 2)vent, that is classes that inherit from 2)vent
:ecause e"ents are shared among most of the application components, it is con"enient to declare them
in a separate header file 0eg, 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 (9 "3pical Arduino s*etch #or QP -#ile qp_dpp.pde.
(&) enu% *PP#ignal {
(-) )8B1#IG = 21R#)R1#IG' // publihed by Bable to let a philoopher eat
*=9)1#IG' // publihed by Philoopher when done eating
B)REI98B)1#IG' // publihed by /#P to ter%inate the appli"ation
(L) E8F1PR/1#IG' // the lat publihed ignal
HR9GRV1#IG' // poted fro% hungry Philoopher to Bable
(M) E8F1#IG // the lat ignal
+;
(Q) tru"t Bable)vt 4 publi" 2)vent {
uintT1t philo9u%; // philoopher nu%ber
+;
enu% { 91PHI(= = Q +; // nu%ber of philoopher
(D) e;tern 28"tive N "ont 8=1PhiloO91PHI(=P; // Kopa0ueK pointer to Philo 8=
(S) e;tern 28"tive N "ont 8=1Bable; // Kopa0ueK pointer to Bable 8=
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
0&1 )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
0(1 )he constant E8F1PR/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 0E8F1PR/1#IG1 rather than the ma2imum of all
signals used in the application
061 )he last enumeration E8F1#IG indicates the ma2imum of all signals used in the application
0.1 )he structure Bable)vt represents a class of e"ents to con"ey the Philosopher num$er in the
e"ent parameter Bable)vt inherits 2)vent and adds the philo9u% parameter to it
09-31 )hese glo$al pointers represent acti"e o$Eects in the application and are used for posting e"ents
directly to acti"e o$Eects :ecause the pointers can $e initiali;ed at compile time, they are declared
"ont! )he acti"e o$Eect pointers are JopaqueK $ecause they cannot access the whole acti"e
o$Eect, only the part inherited from 2a"tive!
!( of 2/
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
)%) "he 'tate Cachines
)he QP framework allows you to work with the modern hierarchical state machines 0aka, A8L
statecharts1 @or e2ample, @igure #( shows the =,8 for the P'L-CA4 crossing
!4 of 2/
:igure !)9 "he hierarchical state machine o# the PE2$CAN crossing
operational
entry * CA!,>!'/O P'/,>/C4)>HALB
offline
entry *
e2it *
cars'na$led
e2it *
peds'na$led
e2it *
cars7reen
entry * CA!,>7!''4
e2it *
carsDellow
entry * CA!,>D'LLCH
e2it *
pedsHalk
entry * P'/,>HALB
e2it *
peds@lash
entry *
e2it *
cars7reen4oPed
entry *
cars7reen-nt
entry *
cars7reenPedHait
entry *
*
me-Usu$scri$e0P'/,>HA-)-47>,-71O
C@@
P'/,>HA-)-47
)-8'CA)
)-8'CA)
P'/,>HA-)-47
)-8'CA)
)-8'CA)
)-8'CA)
Vme-Um>flashCtr TP ?W *
--me-Um>flashCtrO
VelseW
V0me-Um>flashCtr #1 PP ?W *
:,P>signalPeds0P'/,>/C4)>HALB1O
VelseW *
:,P>signalPeds0P'/,>:LA4B1O
)-8'CA) *
me-Um>flashCtr XP #O
V0me-Um>flashCtr #1 PP ?W *
CA!,>!'/O P'/,>/C4)>HALBO
VelseW * CA!,>:LA4BO P'/,>:LA4BO
C4
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*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 Hithout this a$ility, the comple2ity of non-hierarchical state machines
Je2plodesK e2ponentially with the comple2ity of the modeled system, which renders the formalism
impractical for real-life pro$lems
N8"E9 )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 J/ining
Philosophers Pro$lemK 0see !elated /ocuments and !eferences1 )he P'L-CA4 crossing e2ample
is descri$ed in the Application 4ote JP'L-CA4 CrossingK :oth 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 ##
!7 of 2/
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
+ ,oard 'upport Pac*age -,'P. #or Arduino
)he QP e2ample sketches 0/PP and P'L-CA41 contain the file bp!"pp, which stands for :oard
,upport Package 0:,P1 )his :,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
+%! ,'P $nitialiAation
)he :,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 Aser L'/ 0connected to PC!):1 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 49 ,'P@init-. #unction #or the DPP e<ample -#ile bsp.cpp.
void /#P1init(void) {
**R/ = $;33; // 8ll P=RB/ pin are output (uer ()*)
P=RB/ = $;$$; // drive all pin low
#erial!begin(&&Q-$$);
#erial!println(K#tartK);
+
+%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$Eects make Dou
might also want to implement other interrupts as well
Hhen 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 79 Con#iguring and starting interrupts in Q!!on"tartup()
void 2344on#tartup(void) {
(&) // et Bi%er- in <B< %ode' &/&$-M pre"aler' tart the ti%er ti"@ing
B<<R-8 = (& ?? IGE-&) 7 ($ ?? IGE-$);
B<<R-/ = (& ?? <#-- ) 7 (& ?? <#-&) 7 (& ?? <#-$); // &/-W&$
8##R X= Y(& ?? 8#-);
BIE#C- = (& ?? =<I)-8); // )nable BIE)R- "o%pare Interrupt
B<9B- = $;
(-) =<R-8 = BI<C1*IHI*)R; // %ut be loaded lat for 8t%ega&DT and friend
+
!/ of 2/
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
0#1 )his :,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
0(1 )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<C#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 0HinAF!1 supports writing -,!s in C++, $ut you must inform the compiler to generate the
special -,! code $y using the macro I#R() Listing < ,hown the system clock tick -,! for Arduino
2isting /9 '3stem cloc* tic* $'R #or Arduino -#ile bsp.cpp.
(&) I#R(BIE)R-1<=EP81ve"t) {
// 9o need to "lear the interrupt our"e in"e the Bi%er- "o%pare
// interrupt i auto%ati"ally "leard in hardware when the I#R run!
(-) 2344ti"@(); // pro"e all ar%ed ti%e event
+
0#1 )he definition of e"ery -,! must $egin with the I#R() macro
0&1 )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() Jcall$ackK 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 bp!"pp file in each QP sketch
2isting D9 Activating low-power sleep mode #or Arduino -#ile bsp.cpp.
(&) void 2344onIdle() {
(-) R#)R1()*1=9(); // toggle the Rer ()* on 8rduino on and off' ee 9=B)&
(L) R#)R1()*1=33();
(M) Jifdef #8H)1P=I)R
(Q) #E<R = ($ ?? #E$) 7 (& ?? #)); // idle leep %ode' adAut to your proAe"t
// never eparate the following two ae%bly intru"tion' ee 9=B)-
(D) 11a%11 11volatile11 (KeiK KGnGtK 44 );
(S) 11a%11 11volatile11 (KleepK KGnGtK 44 );
(T) #E<R = $; // "lear the #) bit
Jele
(U) 231I9B1)98/()();
Jendif
+
!D of 2/
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
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
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
N8"E9 )he article JAsing Low-Power 8odes in @oreground * :ackground ,ystemsK
0httpL**wwwem$eddedcom*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 ArduinoMs Aser L'/ is turned on and off to "isuali;e the idle loop acti"ity :ecause 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 Aser L'/
061 Hhen the macro #8H)1P=I)R is defined, the following code $ecomes acti"e
0.1 )he #E<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
091 )he interrupts are unlocked with the #)I instruction
031 )he sleep mode is acti"ated with the #())P instruction
4C)'L )he AF! datasheet is "ery specific a$out the $eha"ior of the ,'--,L''P instruction pair /ue
to pipelining of the AF! 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
0<1 As recommended in the AF! datasheet, the #E<R register should $e e2plicitly cleared upon the e2it
from the sleep mode
051 -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 9 of the $ook JPractical A8L ,tatecharts in C*C++, ,econd 'ditionK 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 21on8ert() )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 21on8ert() call$ack for AF! )he function disa$les all
interrupts to pre"ent any further damage, turns on the Aser L'/ to alert the user, and then performs the
software reset of the Arduino processor
void 21on8ert("har "ont 21R=E N "ont 21R=E1H8R file' int line) {
231I9B1*I#8/()(); // diable all interrupt
R#)R1()*1=9(); // Rer ()* per%anently =9
a% volatile (KA%p $;$$$$K); // perfor% a oftware reet of the 8rduino
+
2 of 2/
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
( QP0C11 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 Eust of three files )he following sections descri$e these files
(%! "he qp_port.$ Header :ile
Hhen you import the li$rary 0Arduiono -/', menu ,ketch R -mport Li$rary R qp1, the Arduino -/' will insert
the line JJin"lude ?0p1port!h>K into your currently open sketch file )he 0p1port!h file 0shown in
Listing #?1 contains the adaptations 0port1 of QP to the AF! processor followed $y the platform-
independent 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 231E8F18<BIH) and currently is set to < Dou can increase it to 9(, inclusi"e,
$ut this costs additional memory 0!A81, so you should not go too high unnecessarily
2isting !9 "he ;p@port%h header #ile #or the QP librar3
Jifndef 0p1port1h
Jdefine 0p1port1h
Jin"lude ?tdint!h> // <UU.tandard e;a"t.width integer
Jin"lude ?avr/pg%pa"e!h> // a""eing data in the progra% %e%ory (PR=GE)E)
Jin"lude ?avr/io!h> // #R)G definition
Jin"lude ?avr/interrupt!h> // "li()/ei()
// the %a"ro 2C1PR))EPBIH) ele"t the pree%ptive 2C @ernel
// (default i the "ooperative KHanillaK @ernel)
//Jdefine 2C1PR))EPBIH) &
// allow uing the 2C priority "eiling %ute;
//Jdefine 2C1ERB)F &
// variou 23 obAe"t i5e "onfiguration for thi port
Jdefine 231E8F18<BIH) T
Jdefine 231)H)9B1#IZ1#IZ) &
Jdefine 231)2R)R)1<BR1#IZ) &
Jdefine 231EP==(1#IZ1#IZ) &
Jdefine 231EP==(1<BR1#IZ) &
Jdefine 231BIE))HB1<BR1#IZ) -
// the %a"ro [PR=GE)E[ allo"ate "ont obAe"t to R=E
Jdefine 21R=E PR=GE)E
// the %a"ro [21R=E1/VB)[ read a byte fro% R=E
Jdefine 21R=E1/VB)(ro%1var1) pg%1read1byte1near(X(ro%1var1))
// 23 interrupt diable/enable
Jdefine 231I9B1*I#8/()() "li()
Jdefine 231I9B1)98/()() ei()
// 23 "riti"al e"tion entry/e;it
Jdefine 231<RIB1#B8B1BVP) uintT1t
Jdefine 231<RIB1)9BRV(tat1) do { G
(tat1) = #R)G; G
"li(); G
2! of 2/
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
+ while ($)
Jdefine 231<RIB1)FIB(tat1) (#R)G = (tat1))
Jifdef 2C1PR))EPBIH)
// 2C interrupt entry and e;it
Jdefine 2C1I#R1)9BRV() (662C1int9et1)
Jdefine 2C1I#R1)FIB() do { G
..2C1int9et1; G
if (2C1int9et1 == (uintT1t)$) { G
uintT1t p = 2C1"hedPrio1(); G
if (p != (uintT1t)$) { G
2C1"hed1(p); G
+ G
+ G
+ while ($)
// allow uing the 2C priority "eiling %ute;
Jdefine 2C1ERB)F &
Jendif // 2C1PR))EPBIH)
//////////////////////////////////////////////////////////////////////////////
// *= 9=B <H89G) 89VBHI9G /)(=I BHI# (I9)
! ! !
Jendif // 0p1port1h
(%2 "he qp_port.cpp :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 !!9 "he qp_port.cpp source #ile #or the QP librar3
Jin"lude K0p1port!hK // 2P port
21*)3I9)1BHI#1E=*R()(0p1port)
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
e;tern K<K void loop() {
2344run(); // run the appli"ation' 9=B)4 2344run() doe not return
+
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Bhi 2P fra%ewor@ doe 9=B ue new or delete' but the Iin8HR/avr.g66
// "o%piler generate o%ehow a referen"e to the operator delete for every
// "la with a virtual detru"tor! 2P de"lare virtual detru"tor' o to
// atify the lin@er the following du%%y definition of the operator
// delete i provided! Bhi operator hould never be a"tually "alled!
//
void operator delete(void N) {
21)RR=R(); // thi operator hould never be a"tually "alled
+
22 of 2/
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
N8"E9 )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 0HinAF!1 uses when "irtual functions are present Dou should not
edit the 0p1port!"pp source file
(%) "he qp.cpp :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
2) of 2/
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
4 5sing Preemptive Q6 6ernel
)he structure of the QP*C++ framework for Arduino discussed in ,ection #( corresponds to the simple
cooperati"e scheduler called JFanillaK =owe"er, the QP framework can also e2ecute Arduino applications
using the preemptive Q6 *ernel )he difference $etween non-preempti"e kernel 0like JFanillaK1 and
preempti"e kernel 0like QB1 is shown in @igure #6
N8"E9 A *ernel is the part of the system that manages computer time $y assigning the processor to
"arious tasks
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 :ut 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
2+ of 2/
:igure !+9 E<ecution pro#iles o# a non-preemptive *ernel -a. and a preemptive *ernel -b.%
-a.
low-priority task
time
p
r
i
o
r
i
t
y
high-priority task
low-priority task
interrupt
entry
$locking call
or e2plicit yield
interrupt
return
6
kernel
-b.
low-priority task
time
high-priority task
low-priority task
interrupt
entry
conte2t switch
interrupt return
6
kernel
0&a1
0(a1
06a1
0#a1 0.a1 09a1
0#$1
0&$1
0($1 06$1
$'R
0.$1
09$1
03$1
-,! produces
e"ent for high-
priority task
p
r
i
o
r
i
t
y
-,! produces
e"ent for high-
priority task
$'R
6
preempted
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*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 QP0C11 2ibrar3 to 5se Preemptive Q6 6ernel
!e-configuring the QP to use the preempti"e QB kernel, instead of the simple JFanillaK kernel, is "ery
easy Dou need to remo"e a comment in front of the line starting with Jdefine 2C1PR))EPBIH) in the
0p1port!h header file located in the Arduino li$rary directory 0see Listing #1 Additionally, if you want to
use the QB mute2, you need to uncomment the line starting with Jdefine 2C1ERB)F )he following
Listing #& highlights the changes
2isting !29 "he ;p@port%h header #ile #or the QP librar3
Jifndef 0p1port1h
Jdefine 0p1port1h
Jin"lude ?tdint!h> // <UU.tandard e;a"t.width integer
Jin"lude ?avr/pg%pa"e!h> // a""eing data in the progra% %e%ory (PR=GE)E)
Jin"lude ?avr/io!h> // #R)G definition
Jin"lude ?avr/interrupt!h> // "li()/ei()
// the %a"ro 2C1PR))EPBIH) ele"t the pree%ptive 2C @ernel
// (default i the "ooperative KHanillaK @ernel)
Jdefine 2C1PR))EPBIH) &
// allow uing the 2C priority "eiling %ute;
Jdefine 2C1ERB)F &
! ! !
N8"E9 Compared to the simple non-preempti"e JFanillaK kernel, the preempti"e QB kernel requires
more stack space @ortunately, unlike most preempti"e kernels, the run-to-completion QB kernel
requires a single stack for nesting all the stack conte2t @or more information a$out the QB kernel,
please refer to Chapter #? in the JPractical A8L ,tatechartsK $ook and to the ',/ article J:uild the
,uper-,imple )askerK 0see ,ection !elated /ocuments and !eferences1
4%2 "he ;p@dpp@;* 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 QB 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 !)9 "he bsp%cpp #ile #or the ;p@dpp@;* e<ample
! ! !
// I#R ......................................................................
I#R(BIE)R-1<=EP81ve"t) {
// 9o need to "lear the interrupt our"e in"e the Bi%er- "o%pare
2( of 2/
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
// interrupt i auto%ati"ally "leard in hardware when the I#R run!
QK_I"R_E&TR'()( // infor% 2C @ernel about entering an I#R
2344BI<C(Xl1BIE)R-1<=EP8); // pro"e all ar%ed ti%e event
QK_I"R_E)IT()( // infor% 2C @ernel about e;iting an I#R
+
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*oid QK!!onIdle() +
231I9B1*I#8/()();
R#)R1()*1=9(); // toggle the Rer ()* on 8rduino on and off' ee 9=B)&
R#)R1()*1=33();
231I9B1)98/()();
Jifdef #8H)1P=I)R
#E<R = ($ ?? #E$) 7 (& ?? #)); // idle leep %ode' adAut to your proAe"t
11a%11 11volatile11 (KleepK KGnGtK 44 );
#E<R = $; // "lear the #) bit
Jendif
+
! ! !
As shown in Listing #(, e"ery -,! for the preempti"e QB kernel must in"oke the macro 2C1I#R1)9BRV()
at the $eginning 0and $efore calling any QP function1 and must in"oke the macro 2C1I#R1)9BRV() right
$efore the end )hese macros gi"e control to the QB kernel, so that it can perform preemptions
Additionally, the QB kernel handles the idle condition differently 0actually simpler1 than the non-
preempti"e JFanillaK kernel )he idle call$ack for the QB kernel is called 2C44onIdle() and the
difference is that it is called with interrupts ena$led, in contrast to the 2344onIdle() call$ack discussed
$efore
4%) Running the ;p@dpp@;* E<ample
)he e2ample 0p1dpp10@ runs e2actly the same as the non-preempti"e "ersion 0p1dpp
24 of 2/
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
7 Related Documents and Re#erences
Document 2ocation
JPractical A8L ,tatecharts
in C*C++, ,econd 'ditionK
VP,iCC&W, 8iro ,amek,
4ewnes, &??<
A"aila$le from most online $ook retailers,
such as Ama;oncom
,ee alsoL httpL**wwwstate-
machinecom*psicc&htm
QP /e"elopment Bits for Arduino, Quantum Leaps,
LLC, &?##
httpL**wwwstate-machinecom*arduino
JApplication 4oteL /ining Philosopher Pro$lem
ApplicationK, Quantum Leaps, LLC, &??<
httpL**wwwstate-
machinecom*resources*A4>/PPpdf
JApplication 4oteL P'/estrian L-ght CC4trolled
0P'L-CA41 Crossing ApplicationK, Quantum Leaps,
LLC, &??<
httpL**wwwstate-
machinecom*resources*A4>P'L-CA4pdf
JAsing Low-Power 8odes in @oreground*:ackground
,ystemsK, 8iro ,amek, 'm$edded ,ystem /esign,
Ccto$er &??3
httpL**wwwem$eddedcom*design*&?&#?(6&.
QP /e"elopment Bits for AF!, Quantum Leaps,
LLC, &??<
httpL**wwwstate-machinecom*a"r
JQP*C++ !eference 8anualK, Quantum Leaps, LLC,
&?##
httpL**wwwstate-
machinecom*do2ygen*qpcpp*
@ree Q8 graphical modeling and code generation
tool, Quantum Leaps, &?##
httpL**wwwstate-machinecom*qm
J:uild a ,uper-,imple )askerK, $y 8iro ,amek and
!o$ert Hard, ',/, &??9
httpL**wwweetimescom*7eneral*PrintFiew*6?
&.95#
httpL**wwwstate-
machinecom*resources*samek?9pdf
27 of 2/
Copyright Quantum Leaps, LLC All !ights !eser"ed
Application Note9
Event-Driven Arduino Programming with QP
state-machinecom*arduino
/ Contact $n#ormation
Quantum 2eapsG 22C
#?( Co$$le !idge /ri"e
Chapel =ill, 4C &3.#9
A,A
+# <99 6.? L'AP 0toll free, A,A only1
+# 5#5 <95-&55< 0@AY1
e-mailL info@quantum-leapscom
H': L httpL**wwwquantum-leapscom
httpL**wwwstate-machinecom
Arduino Pro?ect
homepage9
httpL**arduinocc
2/ of 2/

Vous aimerez peut-être aussi