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 calculationsSimple on/off logic
You have many conditions to checkYou prefer visual wiring
You want reusable functionsQuick prototyping
You're comfortable writing codeYou'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_PROGRAM

Breaking 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

TypeWhat it holdsExample
BOOLTRUE or FALSEMotorRunning : BOOL;
INTWhole numberCounter : INT;
REALDecimal numberSpeed : REAL;
LREALHigh-precision decimalPosition : LREAL;
STRINGTextMessage : 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_VAR

After 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_IF

CASE (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_CASE

FOR loop (repeat a fixed number of times)

FOR i := 0 TO 9 DO
    Values[i] := 0;
END_FOR

WHILE loop (repeat until condition is false)

WHILE Temperature > 50.0 DO
    CoolingFan := TRUE;
END_WHILE

Using 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 namesConveyorSpeed is better than x1
  • Start simple — Get one thing working before adding complexity
  • Use the Trace — Monitor your variables in real-time while the simulation runs (Trace Guide)

On this page