n1ksn 26 Posted October 26, 2011 Share Posted October 26, 2011 In this thread I would like to go though the pieces of code that implement a state machine to control one or more LEDs (3 in this case). It is written to be a device driver with an interface to a client module. You could argue that it is overkill for controlling LEDs, but this is intended to be an example on translating a two-level hierarchical UML statechart into C code. The complete program includes other modules, but for now I just want to concentrate on the LED state machine. First, though, why use a state machine? There are different choices for the structure of embedded software, and which one works best depends on factors like program size and complexity and ease of maintenance and modification. From most of the the books I've read on the subject (e.g., Simon's "An Embedded Software Primer"), the structures go from the simplest, a round robin with polling, to a round robin with interrupts (including some sleeping), then a task queue and scheduler, and finally a real-time operating system (RTOS). State machines, which seem to be neglected in many books, offer an alternative to task schedulers and real-time operating systems (or can be used in conjunction with them). They are a good approach when the software activity is primarily responses to stimuli from inputs. State machines allow for multiple thread operations combined with a fairly straight-forward way to translate a program specification into code. They can be implemented with large, nested switch statements, but this approach can get out of hand and be difficult to maintain. (I know this from personal experience because I took this approach a couple of years ago with a program to control a homebrew shortwave transceiver. It depended on a mess of flags and multiple switch statements and was difficult to debug.) Instead we will associate with each state a couple of C functions that perform the needed actions, parse signals to the state machine, and make the appropriate transitions. This work is an outgrowth of my study of two books. "MSP430 State Machine Programming with the ES2274" by Tom Baugh shows how to build very low power applications on the MSP430 using flat state machines. It also taught me a lot about C and MSP430 assembly instructions. "Practical UML Statecharts in C/C++" by Miro Samek shows how to use his open-source system to implement hierarchical state machines and its Chapter 2 is a crash course UML statecharts, which are part of the Unified Modeling Language (UML). The approach I will take uses a two-level hierarchical UML statechart for the specification, which I then translate into a flat state machine implemented as per Baugh. (Alternatively, one can use some of Samek's software to implement these state machines.) Here is the UML statechart specifying the state machine for the LED driver module: Each box with rounded corners in the diagram is a state. There are two higher level states representing two different modes of operation. Each of these "superstates" contains two substates which describe the behavior of the LED state machine for that mode of operation. The superstate ledStateSteady represents the LED being either off or on indefinately. The superstate ledStateBink represents the LED being in a blinking mode. The arrows represent transistions from one state to another caused by a "signal" to the state machine. For example, if the LED is in the steady off state, reception of the signal LED_ON_SIG causes a transition to the steady on state. As another example, if the LED is in either the steady off or steady on states and receives an LED_BLINK_SIG, it will transition to the blinking superstate. Note that some transition arrows start or end on a superstate, while others start or end on a substate. The black dots represent initial starting points. The dot at the very top shows that at start up the state machine goes to the steady superstate. When going into the steady superstate, the dot inside that state shows that initially the transition is into the off steady state. The dot inside the blink superstate shows that upon entering that superstate the state machine transitions to the blink on state. Inside the steady superstate is a dot with an "H" inside. This represents "history" and means that when there is a transition due to the signal LED_STEADY_SIG, the state machine returns to whichever steady substate was last active. (According to strict UML rules, this H dot should replace the solid dot inside the steady superstate, but I think this is confusing.) Finally, each state contains Entry and/or Exit actions which are taken upon entry to or exit from that state. For example, when the blink superstate is entered the state machine software timer (driven by the system tick) is activated to allow blinking. When the blink superstate is left the timer is deactivated. As another example, when the blink on substate is entered the LED is turned on and the timer counter is set for the number of system ticks it will be on. When the timer counts down to zero, a LED_TIMEOUT_SIG signal is sent to the state machine and a transition is made to the blink off state, where upon entry the LED is turned off and the timer counter is loaded with the number of system ticks it is to be off. One rule of UML statecharts is that as you transition out of a substate into another substate in a different superstate, you must execute the applicable entry and exit actions of the superstates (as well as the substates) as you progress up and then down the hierarchy. This simple example does not have any transitions to illustrate this. Well, that's it for this first post. Next time we'll quickly look at the "client interface" (the associated header file) and then begin building the C code to implement the LED state machine. Cheers, Andy n1ksn bluehash, zborgerd, cdch10 and 1 other 4 Quote Link to post Share on other sites
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.