Structured Text
Write PLC programs as code with the Structured Text editor
Structured Text (ST)
Structured Text lets you write PLC programs as code. If you've used Pascal, Python, or any programming language, you'll feel right at home.
When to Use ST Instead of FBD
| Use ST when... | Use FBD when... |
|---|---|
| You need complex math or calculations | Simple on/off logic |
| You have many conditions to check | You prefer visual wiring |
| You want reusable functions | Quick prototyping |
| You're comfortable writing code | You're learning PLC programming |
The Editor
The ST editor includes syntax highlighting, auto-complete, and error checking as you type.
[IMAGE: ST editor with a program open, showing syntax highlighting and the error panel at bottom]
Writing Your First Program
Here's a simple program that starts a conveyor when a button is pressed:
PROGRAM ConveyorControl
VAR
StartButton : BOOL; // Input from scene
ConveyorRun : BOOL; // Output to scene
Speed : REAL; // Output to scene
END_VAR
IF StartButton THEN
ConveyorRun := TRUE;
Speed := 500.0; // 500 mm/s
ELSE
ConveyorRun := FALSE;
Speed := 0.0;
END_IF
END_PROGRAMBreaking it down
- VAR / END_VAR — Declare your variables here. Each needs a name and type.
- IF / THEN / ELSE / END_IF — Check a condition and act on it.
- := — Assignment operator (sets a value).
Variables and Types
| Type | What it holds | Example |
|---|---|---|
| BOOL | TRUE or FALSE | MotorRunning : BOOL; |
| INT | Whole number | Counter : INT; |
| REAL | Decimal number | Speed : REAL; |
| LREAL | High-precision decimal | Position : LREAL; |
| STRING | Text | Message : STRING; |
Input and Output Variables
To connect your program to the scene, declare variables as inputs or outputs:
VAR_INPUT
Sensor1 : BOOL; // Reads from an input node in the scene
Temperature : REAL; // Reads from OPC UA tag
END_VAR
VAR_OUTPUT
ConveyorSpeed : REAL; // Drives an output node in the scene
CylinderPos : REAL; // Controls actuator position
END_VARAfter saving, these variables appear in the scene editor where you can bind them to input/output nodes.
[IMAGE: Scene editor showing ST variables mapped to input/output nodes on a model]
Control Structures
IF / THEN / ELSE
IF Sensor1 AND NOT Sensor2 THEN
ConveyorSpeed := 500.0;
ELSIF Sensor2 THEN
ConveyorSpeed := 200.0;
ELSE
ConveyorSpeed := 0.0;
END_IFCASE (select one of many options)
CASE StepNumber OF
0: // Idle
MotorRun := FALSE;
1: // Running
MotorRun := TRUE;
Speed := 500.0;
2: // Slow down
Speed := 100.0;
END_CASEFOR loop (repeat a fixed number of times)
FOR i := 0 TO 9 DO
Values[i] := 0;
END_FORWHILE loop (repeat until condition is false)
WHILE Temperature > 50.0 DO
CoolingFan := TRUE;
END_WHILEUsing Timers and Counters
Timers and counters are function blocks — you declare them as variables and call them each scan:
VAR
DelayTimer : TON; // On-delay timer
BoxCounter : CTU; // Up-counter
END_VAR
// Start timer when sensor activates (1 second delay)
DelayTimer(IN := Sensor1, PT := T#1s);
// Count boxes (increment when sensor has rising edge)
BoxCounter(CU := Sensor1, PV := 100);
// Use timer output
IF DelayTimer.Q THEN
Conveyor2Speed := 500.0;
END_IF
// Check counter
IF BoxCounter.Q THEN
// 100 boxes counted — stop and reset
ConveyorSpeed := 0.0;
BoxCounter(RESET := TRUE);
END_IF[IMAGE: Trace view showing timer and counter behavior over time]
Example: Sorting Station
A complete example — boxes arrive on a conveyor, a sensor detects them, and a pusher sorts them to a side conveyor:
PROGRAM SortingStation
VAR
// Inputs (from scene)
BoxDetected : BOOL;
// Outputs (to scene)
MainConveyor : REAL;
PusherExtend : BOOL;
SideConveyor : REAL;
// Internal
PushTimer : TON;
RetractTimer : TON;
State : INT;
END_VAR
// Main conveyor always runs
MainConveyor := 400.0;
SideConveyor := 300.0;
CASE State OF
0: // Waiting for box
PusherExtend := FALSE;
IF BoxDetected THEN
State := 1;
END_IF
1: // Push box
PusherExtend := TRUE;
PushTimer(IN := TRUE, PT := T#500ms);
IF PushTimer.Q THEN
PushTimer(IN := FALSE);
State := 2;
END_IF
2: // Retract pusher
PusherExtend := FALSE;
RetractTimer(IN := TRUE, PT := T#500ms);
IF RetractTimer.Q THEN
RetractTimer(IN := FALSE);
State := 0;
END_IF
END_CASE
END_PROGRAM[IMAGE: Sorting station scene with labeled components: main conveyor, sensor, pusher, side conveyor]
Tips
- Save often — The editor auto-checks for errors when you save
- Use meaningful names —
ConveyorSpeedis better thanx1 - Start simple — Get one thing working before adding complexity
- Use the Trace — Monitor your variables in real-time while the simulation runs (Trace Guide)