|
|||||||||||
Understanding State MachinesWith a simple example, this article describes how state machines can be effectively applied in real-time multi-tasking applications. A Simple State Machine ExampleConsider a lamp controlled by a momentary contact switch. (A momentary contact switch is a spring loaded button switch that makes the connection when pressed and breaks the connection when released.) When the button is pressed the first time, the lamp should turn on, and, when pressed the second time the lamp should turn off. This apparently simple behavior is a bit involved and can be described in a table as shown below. Current State Condition Action Next State 0 Button down Lamp on 1 1 Button up None 2 2 Button down Lamp off 3 3 Button up None 0 The states have the following meanings:
The state machine remains in the current state until a condition is met, at which time an action is taken, and a state transition is made to a new state (the "new state" may be the current state also). This may be coded as follows.
void taskA(void)
{
int state;
int condition;
typeMsg * msg;
while (TRUE) {
msg = waitMsg(ANY_MSG);
condition = msg->msgNum;
freeMsg(msg);
switch (state) {
case 0:
if (condition == BUTTON_DOWN) {
lampOn();
state = 1;
}
break;
case 1:
if (condition == BUTTON_UP) {
state = 2;
}
break;
case 2:
if (condition == BUTTON_DOWN) {
lampOff();
state = 3;
}
break;
case 3:
if (condition == BUTTON_UP) {
state = 0;
}
break;
}
}
}
taskA receives a message from another task when a change in button status occurs and reacts according to the state table. One may ask why taskA does not poll the switch itself thus eliminating the need for a special task that polls the switch. The answer is that taskA could simply poll the switch, but it would then have to debounce the switch also. Using a separate task to poll the switch also handles the debouncing problem and makes taskA easier to read. The debounce task is also a state machine and its state table is shown below. Current State Condition Action Next State 0 Button down pause 1 1 Button down sendMsg 2 1 Button up None 0 2 Button up pause 3 3 Button up sendMsg 0 3 Button down None 2 The states have the following meanings:
The states 0 and 2 are absolute states in which the button is either up or down. States 1 and 3 are transition states in which the position of the button switch after a delay determines whether the switch has settled into position or not. The implementation of the debounce task is shown below.
extern typeTcb TcbA;
void taskB(void)
{
int state = 0;
while (TRUE) {
switch (state) {
case 0:
if (buttonDown()) {
pause(100L);
state = 1;
} else {yield();}
break;
case 1:
if (buttonDown()) {
sendMsg(makeMsg(TcbA, BUTTON_DOWN));
state = 2;
}
else state = 0;
break;
case 2:
if (buttonUp()) {
pause(100L);
state = 3;
} else {yield();}
break;
case 3:
if (buttonUp()) {
sendMsg(makeMsg(TcbA, BUTTON_UP));
state = 0;
}
else state = 2;
break;
}
}
General ApplicationCertain applications need to know where they are in a sequence of operations and it is applications like these that require state logic. Even if the formal state machine approach shown above is not employed, some form of state machine logic must be used otherwise errors will result. State machines are a must in applications like communications, robotics, process control and the like, since each of these involve a sequence of operations. State machines become indispensible when handling error conditions and recovery procedures because a knowledge of the machine state is required to effect said procedures properly. We welcome comments. Let us know what subjects you would like written up. Send comments to Mike@TicsRealtime.com Copyright © 1992-2004, Tics Realtime |
|||||||||||