← Resources
Practice·8 min read·

Writing a machine sequence as a state machine

One integer, one rung per state, one rung per transition, and the three rules that keep it debuggable at three in the morning.

Short answer

Hold the current state in an integer. Write one rung per state driving that state's outputs, conditioned on the state number. Write one rung per transition, conditioned on the current state and the event, setting the new state number. Never set the state from more than one place per transition, always drive outputs from the state rather than from the transition, and always provide a fault state.

The five IEC 61131-3 languagesLDLadder Diagramgraphical, relay heritageFBDFunction Block Diagramgraphical, signal flowSFCSequential Function Chartsteps and transitionsSTStructured Texttextual, Pascal-likeILInstruction Listtextual, deprecatedOne standard, five notations. Most projects use two.

Machine sequences written as a pile of latches work until they do not, and when they do not, nobody can tell what the machine thinks it is doing.

A state machine is the same behaviour written so that question always has an answer.

The shape

One integer holding the current state. Ten, twenty, thirty, so states can be inserted later without renumbering.

One rung per state driving that state's outputs, conditioned only on the state number.

One rung per transition, conditioned on the current state and the event that ends it, writing the new state number.

That is all of it. The whole sequence is visible as a list of states and a list of transitions.

Rule one: outputs come from the state

The rung that opens the inlet valve is conditioned on being in the filling state, and nothing else.

The temptation is to set the valve in the transition that enters filling, which works and creates a machine whose behaviour depends on how it arrived. Enter filling from a recovery path that forgot to set the valve, and the machine sits in the filling state not filling.

With outputs driven by the state, the state number tells you what every output should be. Looking at the state number and looking at the outputs is a complete diagnosis.

Rule two: one writer per transition

Each transition is one rung, and the state is written in exactly one place per transition.

Two rungs that both write state 30 from different conditions is where the sequence starts behaving unpredictably, because whichever solves last wins, and which solves last depends on rung order.

If two conditions genuinely lead to the same next state, put them in parallel branches of one rung.

Rule three: every state has a timeout

The rule that turns a mysterious stop into a diagnosis.

One timer per state, reset on entry, running while the state is active. If the transition event has not arrived by the timeout, go to a fault state and record which state timed out.

Without this, a valve that failed to open leaves the machine on step 40 forever, with nothing on the HMI saying why, and somebody works it out with a print of the program.

The fault state

One state that everything can enter and only a deliberate reset can leave.

It drives outputs to a safe configuration, holds the state it came from so the fault can be reported precisely, and refuses to advance.

Recording the previous state is what makes the alarm say 'timed out waiting for the inlet valve to open' rather than 'sequence fault'.

Making it visible

Two small things that pay for themselves in commissioning time.

Put the state number on the HMI, plainly, as a number and a name. Nobody looking at the machine should have to go online to find out what step it is on.

Log every transition with a timestamp. A sequence that occasionally takes forty seconds instead of twelve is diagnosable from the transition log and nearly impossible to catch live.

Where SFC fits

IEC 61131-3 has Sequential Function Chart, which is this pattern as a language: steps, transitions and actions drawn as a chart.

Where it is available and the team knows it, it is a good fit and enforces the structure. Where it is not, the ladder version above gives the same discipline, and the discipline is the part that matters.

Common questions

Why not use latches for each step?
Because a latch per step allows two steps to be on at once, which is not a state machine, it is a set of independent flags. A single integer makes the states mutually exclusive by construction, and an impossible state becomes impossible rather than merely unlikely.
Should outputs be driven by the state or by the transition?
By the state, always. Driving from the transition means the output depends on how the state was entered, so entering the same state from a different path gives different behaviour. Driving from the state means what you see on the screen is what the machine is doing.
How should timeouts be handled?
One timer per state, started on entry, that moves the machine to a fault state if the expected event does not arrive. Without them, a valve that fails to open leaves the sequence sitting on a step forever with no indication of why.

Keep reading