Structured Text and the Other IEC Languages
Structured Text, function block, SFC and instruction list, with one example written several ways.
The five languages
The IEC 61131-3 standard defines five programming languages, three graphical and two text. A project can mix them, choosing each for what it does best.
| Language | Style | Best for | Weak at |
|---|---|---|---|
| Ladder diagram (LD) | Graphical: contacts and coils | Discrete logic, interlocks, anything an electrician must troubleshoot | Math, loops, strings, long sequences |
| Function block diagram (FBD) | Graphical: blocks joined by wires | Analog processing, PID loops, signal conditioning | Complex branching |
| Structured text (ST) | Text, Pascal-like | Math, arrays, loops, strings, reusable blocks, data handling | Quick visual fault-finding by non-programmers |
| Sequential function chart (SFC) | Graphical: steps and transitions | Step-by-step machine sequences and batch | Heavy computation (the actions are written in another language) |
| Instruction list (IL) | Text, assembly-like | Small code; some older systems | Deprecated in the third edition (2013); avoid in new work |
One problem, five ways
A motor that starts on Start, holds itself, and stops on Stop, overload or emergency stop, written each way.
Ladder
See the start/stop rung on Ladder Logic in Practice.
Structured text
Motor_Run := (Start_PB OR Motor_Run) AND Stop_OK AND Overload_OK AND EStop_OK;
Function block diagram
An OR block (Start_PB, Motor_Run) feeding an AND block with Stop_OK, Overload_OK and EStop_OK, whose output is Motor_Run. The same blocks appear in the signal-processing example below.
Instruction list (deprecated)
LD Start_PB
OR Motor_Run
AND Stop_OK
AND Overload_OK
AND EStop_OK
ST Motor_Run
Sequential function chart
SFC is not used for a single seal-in. It is for sequences: for example, step 10 “Run motor” with the transition “Start pressed”, then step 20 “Stopped” with the transition “Stop pressed”.
Compare the length of the text version with the ladder one. Both are correct; choose the one the people who maintain the machine can read.
Structured Text basics
| Element | Syntax | Notes |
|---|---|---|
| Assignment | x := a + b; | Assignment uses :=; a single = is a comparison |
| Comparison | a = b, a <> b, a >= b | Result is BOOL |
| Logic | AND, OR, XOR, NOT | Operate on BOOL or on bit strings |
| IF | IF c THEN … ELSIF d THEN … ELSE … END_IF; | The conditions must be BOOL |
| CASE | CASE State OF 0: … 10: … ELSE … END_CASE; | Ideal for state machines |
| FOR | FOR i := 1 TO 10 DO … END_FOR; | Counted loop; keep the count small |
| WHILE, REPEAT | WHILE c DO … END_WHILE; | Dangerous in a scan: an endless loop trips the watchdog |
| Function block call | Timer1(IN := x, PT := T#5s); then Timer1.Q | Instance-based: each call uses its own data |
| Comments | (* text *) or // text | Comment the reason, not the code |
- Variables must be declared with a type, in sections (VAR_INPUT, VAR_OUTPUT, VAR, VAR_GLOBAL). Initialize them.
- Operator precedence: NOT, then multiplication and division, then addition and subtraction, then comparison, then AND, then XOR, then OR. Use brackets to make it obvious.
- Types must match. Convert with INT_TO_REAL, REAL_TO_INT, DINT_TO_REAL and so on.
- Edges. Use R_TRIG and F_TRIG blocks:
Trig(CLK := Button); IF Trig.Q THEN … END_IF;
Writing a reusable function block
A function block bundles logic and its own memory (its instance variables) so that you can write it once and reuse it for every motor, valve or pump. It is the biggest productivity gain structured text offers. A motor block with a start-up check:
FUNCTION_BLOCK FB_Motor
VAR_INPUT
Start_Cmd : BOOL; (* from the HMI or the sequence *)
Stop_OK : BOOL; (* stop button, wired normally closed *)
Overload_OK : BOOL;
EStop_OK : BOOL;
Running_FB : BOOL; (* contactor auxiliary contact *)
Reset : BOOL;
END_VAR
VAR_OUTPUT
Run_Out : BOOL;
Fault : BOOL;
END_VAR
VAR
StartCheck : TON;
END_VAR
(* run the motor unless something is wrong *)
Run_Out := (Start_Cmd OR Run_Out) AND Stop_OK AND Overload_OK AND EStop_OK AND NOT Fault;
(* fault if the contactor does not confirm within 3 s *)
StartCheck(IN := Run_Out AND NOT Running_FB, PT := T#3s);
IF StartCheck.Q OR NOT Overload_OK THEN
Fault := TRUE;
END_IF;
IF Reset AND Overload_OK THEN
Fault := FALSE;
END_IF;
- Instantiate it once per motor:
Pump1 : FB_Motor;Pump2 : FB_Motor;Each has its own timer and fault memory. - Call it every scan with its inputs wired, and read its outputs:
Pump1(Start_Cmd := HMI_Pump1_Start, …); Q0_0 := Pump1.Run_Out; - Fix it once and every motor is fixed. That is the benefit of reusable blocks; Allen-Bradley calls these Add-On Instructions, Siemens calls them FBs, and CODESYS has Function Blocks.
- Keep I/O out of the block. Pass the tags in and out, so that the block can be tested and reused.
Structured Text examples
Scaling function
FUNCTION Scale : REAL
VAR_INPUT
Raw, RawMin, RawMax, EuMin, EuMax : REAL;
END_VAR
(* straight line through two points *)
Scale := EuMin + (Raw - RawMin) / (RawMax - RawMin) * (EuMax - EuMin);
Calling it with Raw = 20 736, RawMin = 0, RawMax = 27 648, EuMin = 0, EuMax = 10 returns 7.5. See the analog scaling in Timers, Counters and Data.
Moving average of an analog signal
VAR
Buf : ARRAY[0..9] OF REAL;
Idx : INT := 0;
Sum : REAL;
Avg : REAL;
i : INT;
END_VAR
Buf[Idx] := Level_m; (* newest sample *)
Idx := (Idx + 1) MOD 10; (* wrap the index 0..9 *)
Sum := 0.0;
FOR i := 0 TO 9 DO
Sum := Sum + Buf[i];
END_FOR;
Avg := Sum / 10.0;
Worked example: averaging a noisy level
- Ten samples of a level (m): 4.10, 4.12, 4.09, 4.15, 4.11, 4.13, 4.08, 4.14, 4.10, 4.12.
- Sum = 41.14 m; average = 41.14 ÷ 10 = 4.114 m, against a spread of 4.08 to 4.15 m in the raw signal.
- Averaging ten samples reduces random noise by about √10 ≈ 3.2 times, at the cost of a delay of about five samples.
- The loop runs ten times per scan, which is negligible; a loop of 10 000 iterations could trip the watchdog.
A simple state machine
CASE State OF
0: (* idle *)
Inlet := FALSE; Agitator := FALSE; Outlet := FALSE;
IF Start AND Level_Low THEN State := 10; END_IF;
10: (* filling *)
Inlet := TRUE;
IF Level_High THEN Inlet := FALSE; State := 20; END_IF;
20: (* mixing *)
Agitator := TRUE;
MixTimer(IN := TRUE, PT := T#120s);
IF MixTimer.Q THEN Agitator := FALSE; MixTimer(IN := FALSE); State := 30; END_IF;
30: (* draining *)
Outlet := TRUE;
IF Level_Empty THEN Outlet := FALSE; State := 0; END_IF;
ELSE
State := 0;
END_CASE;
More on this pattern, with timeouts and faults, is on Sequences and State Machines.
Function Block Diagram
In FBD, blocks (functions and function blocks) are wired together, and data flows from left to right. It suits signal processing, where you see the chain from raw value to alarm.
- Execution order follows the data: a block runs after the blocks that feed it. Some tools let you set the order explicitly; check it when blocks feed back.
- PID and analog control blocks (PID_Compact in Siemens, PIDE in Logix) are normally used in FBD. See Motors, Drives and PID Control.
- Limits: large diagrams become tangled; split into smaller blocks.
Sequential Function Chart
An SFC describes a sequence as steps (what the machine does) joined by transitions (conditions that move to the next step). Only the active steps run their actions. It is based on the French GRAFCET standard (IEC 60848).
| Element | Meaning | Example |
|---|---|---|
| Step | A state in which the machine does something | S20 Clamp: close the clamp valve |
| Initial step | The step that is active at start-up | S0 Idle |
| Transition | A condition that moves from one step to the next | Clamp_Closed AND Part_Present |
| Action | The code that runs while a step is active | Written in ladder, ST or FBD |
| Branch (selection) | Choose one of several paths | Good part or reject part |
| Parallel branch | Start several paths at once and wait for all to finish | Heat the tank while filling another |
SFC makes a sequence visible to the operator and the maintainer: the active step is highlighted, so you see exactly what the machine is waiting for. If your platform has no SFC, a state machine in ST does the same job.
Instruction List
IL is a low-level text language with one operation per line, like assembly. It was deprecated in the third edition of the standard (2013) and many new platforms do not offer it. You may meet it on older Mitsubishi and Omron programs (the mnemonic form of ladder: LD, AND, OR, OUT). If you inherit IL code, translate it to ladder or ST when you modify it.
Dialects: SCL, Logix ST, CODESYS
| Platform | Language name | Differences to watch |
|---|---|---|
| Siemens | SCL (Structured Control Language) | Local variables are prefixed #; global tags are quoted "Tag"; statements end with ;; the timer is an instance data block |
| Allen-Bradley Logix | Structured Text | Uses :=; no #; tags and AOI instances are referenced directly; some IEC features are missing (check the manual) |
| CODESYS | Structured Text (IEC) | The reference dialect: FUNCTION_BLOCK, VAR_INPUT, instances and pointers |
| Omron Sysmac | Structured Text | IEC compliant; variables with data types and namespaces |
| Mitsubishi GX Works | ST | IEC compliant on the newer series; device addresses allowed |
| Unitronics UniLogic | ST/FBD/LD | Mixes graphical and text; check the supported instructions |
Pitfalls and good habits
- Assignment against comparison.
x = 5tests;x := 5assigns. A tool should flag the mistake; many do not. - Assign each output in one place (one block, one routine). Two writes to the same variable in one scan, with the last one winning, is the text equivalent of a double coil.
- Keep loops short and bounded. A FOR over 10 items is fine; a WHILE that waits for a sensor stops the scan and trips the watchdog.
- Initialize variables, and decide which must survive power loss (retentive).
- Comment intent. Say why (“fault if the contactor does not confirm within 3 s”), not what.
- Do not use text for what an electrician must see. Interlocks and permissives are easier to fault-find in ladder.
- Test off-line. Use the simulator and force inputs; ST has no visual power flow, so use the watch window.
Related
- PLC & Logic Control: the overview of this guide.
- Ladder Logic in Practice and Timers, Counters and Data: the other languages’ patterns.
- Sequences and State Machines: state machines and SFC in practice.
- Motors, Drives and PID Control: PID blocks and drive control.
FAQ
Which language should I use?
Use ladder for discrete logic and interlocks, structured text for math, data handling and reusable blocks, function block diagram for analog signal chains and PID, and SFC (or a state machine) for sequences. Most real programs mix them.
Is structured text harder than ladder?
It is different: shorter for math and loops, but harder for a maintenance technician to troubleshoot live. If your plant’s staff know only ladder, keep the logic in ladder and use ST for calculations.
What is an Add-On Instruction or function block?
A reusable, tested piece of logic with its own memory and inputs and outputs: a motor, a valve, a PID wrapper. Writing a block once and instantiating it many times keeps the code consistent.
Why does my ST code compile but not work?
Common causes: = used where := was meant, an output written from two places, a variable that is not retentive or not initialized, or a function block that is not called every scan.
Can I convert ladder to structured text?
Often yes, by hand or with a tool, but the result may be harder to read than the original. Convert only where the text form is clearly better.
References
- IEC 61131-3, Programmable controllers, Part 3: Programming languages, 3rd ed. (2013): LD, FBD, ST, SFC and IL (deprecated).
- IEC 60848, GRAFCET specification language for sequential function charts.
- Siemens, SIMATIC S7-1200/1500 Programming Guideline and SCL Programming Language Manual.
- Rockwell Automation, Logix 5000 Controllers Structured Text Programming Manual (1756-PM007).
- CODESYS Group, CODESYS Online Help (ST language reference); PLCopen, IEC 61131-3 Programming Languages.
- Lewis, R., Programming Industrial Control Systems Using IEC 1131-3, IEE.
Last reviewed: October 2026. Instruction names, addresses and data sizes differ by manufacturer: confirm against your controller’s manual, and keep safety functions independent of standard PLC logic.
