Just last week I had to school a new programmer...he was animating some graphics, and had set up four booleans to represent of four each animation states...he didn't even realize he was implementing a state machine, much less doing it badly. Lots of logic that really only needed to be an increment to four then reset to one.

It is less likely to happen with high level languages, but with PLCs I have seen this botched several times at different companies and had to clean it up. It has become among the first things I look for when brought in to salvage a project.



State Machines:

In the embedded world, and especially PLC based controls, there is a common need to sequence a series of operations, or to have the system switch between some number of "states" (Standy, accepting input, running process, waiting for heater to come up to temp, etc. etc.) This is so common that it has a name "state machine".

The main thing that all state machines have in common is that the system is only in one of the states at any given time. It moves between states (the order can change, states can be skipped, etc) depending on various conditions like timers, inputs, error conditions, etc.

Example: A washing machine has several states:

-Stopped

-Filling

-Draining

-Hi-speed agitation

-Low-speed agitation

-Spin

A Wash cycle involves Filling->Agitation->Draining->Spin->Filling(rinse)->Agitation...etc.

The machine moves from Stopped to filling based on user input, then moves from filling to agitation based on water level, and between other states based on time...and may jump from spin to stop if an unbalanced load is detected. Several cycles may be programmed each with it's own sequence of states.

To low experience programmers (especially with PLCs) it makes perfect sense to assign a boolean variable (tag in PLC speak) to represent each state. As each state completes, it clears it's own flag, and sets the flag to activate the next state.

DO NOT _EVER_ USE BOOLEANS TO INDICATE EACH STATE! It may work fine when you first program it, but if code has much service life at all, eventually you or a successor will make changes that will result in:

A) Two or more states being active at the same time...because only booleans indicate the state, there is nothing stopping any number of them from being true. Remember, if it is a state machine, only ONE state can be valid at a time.

B) All of the booleans get cleared, and now you are in NO state, with no way to know where you were, and no way to get to what should have been the next state.

Either of the above problems leaves no evidence of how it got into this mess, and if it only happens occasionally it is very difficult to troubleshoot.

The Fix:

1) Use ONE integer variable to select the state. (I'd call it iCycleState for the washing machine example above) This is fairly natural in high level languages that have CASE or SWITCH statements, because these make the whole state machine one very tidy block of code. If the language is lacking CASE/SWITCH, then just use multiple IFs (or Compare= contacts in ladder logic)...just group them all together though!

3) When you first write the code, don't number the the states 1,2,3 etc. Number them 10,20,30... or even 100, 200, 300... Because sure as anything, you will need to add some states later, and this will give you a place to insert them into the natural sequencing of the system instead of tacking them on at the end where they don't really belong. In some cases there are natural "sub states" In that case I'll use the 100, 200,300 scheme for the main states and the tens position for the sub states.

You can move between states in two ways:

-Assign a new value to iCycleState

-Increment iCycleState to reach next state. This tends to break when you add in new states, so don't do this...it only really works for state machines that do a fixed sequence of steps, but the general case is skipping between various states, backing up, etc.

Regardless, this guarantees that only only one state can be active at a time. It automatically turns off the current state when a new state is selected. It gives you one variable to monitor the status of the state machine, either via output or online debugging.

In high level languages, use a Default/Otherwise/Else on your Switch/Case statement. In other languages make sure you at least detect too high and too low invalid states... At some point you or someone else may delete a state and something will try to enter it.

This is mainly an issue with PLCs and machines running a RTOS. Standard computers tend to execute things sequentially, so performing a sequence of steps is their forte.