Structured Text PLC Programming: Syntax and Examples
Learn IEC 61131-3 Structured Text with a complete state-machine example, scan-cycle model, function-block boundaries, portability checks and tests.
Structured Text (ST) is the textual PLC language in IEC 61131-3. It is well suited to state machines, calculations, arrays and reusable functions, but it still executes inside a configured PLC task. Correct ST therefore depends on scan order, persistent function-block state, bounded loops, explicit outputs and tests on the target runtime—not only on valid syntax.
IEC published IEC 61131-3:2025 Edition 4 on 22 May 2025. It defines the syntax and semantics of ST, LD and FBD, plus SFC elements and controller configuration concepts. The standard is a language baseline; it does not make vendor libraries, data layouts, task behavior or project files interchangeable.
Use Structured Text when the control problem becomes clearer as typed data, calculations, arrays, reusable blocks or an explicit state machine. Keep simple field permissives in Ladder when that is the language the maintenance team can safely diagnose. Mixed-language projects are normal; the engineering goal is one understandable behavior and one acceptance test, not loyalty to a syntax.
At a glance:
:=assigns a value;=compares values in the common IEC-style syntax.IFexpresses priority decisions;CASEis usually clearer when one named state owns the outputs and transitions.- Timer, counter and edge instructions have persistent instance state and product-specific invocation rules.
- A loop executes work inside one task invocation unless the programmer deliberately spreads it across scans.
- A later assignment can overwrite an earlier one during the same routine execution.
- Code is not portable until it compiles and passes the same edge-case matrix on the selected runtime.
Structured Text as a PLC programming language
ST is a standardized language inside a controller execution model
Structured Text is a high-level PLC programming language defined by IEC 61131-3. It uses textual statements, typed variables, expressions, decisions, loops, functions and function blocks to implement controller logic. The current IEC 61131-3:2025 Edition 4 record identifies ST alongside Ladder Diagram and Function Block Diagram, with Sequential Function Chart elements and controller configuration concepts also covered by the standard.
Calling ST a programming language does not make it a general-purpose desktop language. Its program organization units execute when the PLC runtime schedules them. Persistent function-block instances, task periods and priorities, input/output updates, retention, watchdogs, downloads and controller state all affect observable behavior. The same valid-looking algorithm can therefore behave differently after translation if those surrounding contracts change.
| Language question | Structured Text answer | Target-specific evidence still required |
|---|---|---|
| What is the basic unit of execution? | statements inside functions, function blocks and programs/other supported POUs | task, program and routine invocation order |
| How are values assigned and compared? | IEC-style ST commonly uses := for assignment and = for equality |
compiler syntax and extension reference |
| Does code retain state automatically? | function-block instances and declared variables can carry state according to their class and scope | initialization, retain/persistent and restart rules |
| Are loops allowed? | FOR, WHILE and REPEAT constructs are part of common ST implementations |
compiler support, bounded workload and task-watchdog tests |
| Is the source portable? | core concepts and much syntax transfer | data types, declarations, libraries, timers, tasks and project format |
| Is ST inherently safer than Ladder? | no language alone supplies the safety claim | approved safety toolchain, architecture, verification and validation |
Structured Text is not Pascal, C or “Ladder in words”
ST resembles Pascal in its block structure and looks familiar to conventional programmers, but resemblance is not source compatibility. It does not inherit the C memory model, C toolchain or operating-system process model. It also should not be treated as a mechanical line-by-line rewrite of Ladder: ST often expresses calculations, state ownership, arrays and reusable blocks more clearly, while Ladder can remain clearer for field permissives and maintenance diagnostics.
Choose the representation that makes the requirement, output ownership, scan behavior and negative tests easiest to review. A mixed-language project can keep device-facing permissives in Ladder, calculation/state logic in ST and reusable control behavior in function blocks. The acceptance matrix—not the number of languages—proves that the combined program behaves correctly.
Diagnostic answer map for search and AI-assisted implementation
“Structured Text program” can mean syntax reference, a complete machine example, a debugging question or a portable design pattern. Use this map to choose the right depth before copying a code block.
| Question | Direct answer | Evidence required |
|---|---|---|
| What is Structured Text? | ST is the textual programming language defined within IEC 61131-3 for programmable-controller applications. | Current standard record plus the target vendor's supported-language documentation |
| Is ST the same as Pascal or C? | It resembles conventional structured languages, but it executes in a PLC task with IEC data, POUs and vendor libraries; it is not source-compatible Pascal or C. | Compiler syntax, task configuration and library reference |
| What does a complete ST program need? | A problem statement, named I/O, state/ownership model, declarations, executable logic, known initial/restart behavior and acceptance tests. | I/O table, code, scan trace, edge cases and target result |
| Does ST run from top to bottom? | Statements in an invoked routine execute in order; surrounding task, program/routine order and I/O updates determine the full cycle. | Task schedule, routine order and online trace |
| Why did an output change unexpectedly? | A later statement, another routine, an HMI/external writer or output mapping may own the final value. | Cross-reference, single-writer review and scan-by-scan trace |
| Should a timer be called inside a state? | Only if the exact platform's instance semantics and skipped-call behavior support the intended reset/retention. A consistently called timer with an explicit enable is easier to review. | Vendor timer reference and state-entry/exit tests |
| Are ST examples portable between CODESYS, Siemens and Logix? | The algorithm can transfer; declarations, timers, edges, libraries, tasks, data and project structure commonly need translation. | Compile report and identical acceptance matrix on each target |
| Is a browser exercise enough for commissioning? | No. It can validate logic behavior and edge cases; the selected PLC must verify dialect, task timing, I/O mapping, retentivity and safety boundaries. | Graded browser result plus target-controller test record |
| Should “structured text program example” have another page? | No. The syntax, complete program, scan trace and tests belong on this canonical owner; a keyword-swapped page would split intent and links. | Permanent alias redirect and canonical metadata |
Ownership boundary: the Structured Text glossary owns the concise definition. This page owns syntax, complete code, execution, vendor translation and test intent. The PLC programming practice exercises owns the broader multi-language exercise catalogue.
Structured Text guide contents
- Execution model
- Scan-by-scan trace
- Syntax essentials
- Program and acceptance contract
- Complete state-machine example
- Functions and function blocks
- Additional program patterns
- Defensive programming
- Arrays and bounded loops
- Vendor differences
- Compile and runtime faults
- Testing checklist
- Frequently asked questions
For a language-level overview first, use the Structured Text glossary. For the broader PLC model—field I/O, scan scheduling and matched LD/FBD behavior—start with the PLC programming guide.
Structured Text execution model
An ST routine does not run continuously just because it looks like conventional source code. A controller executes it when the configured task invokes its program or routine. The observable result depends on:
- when inputs are sampled or read;
- where the ST routine sits in task/program order;
- which variables persist between calls;
- when output data reaches the physical module;
- how long the task may run before a watchdog or scheduling fault; and
- what happens during download, mode change, restart and communications loss.
Assignments run in statement order within the routine. That means a later statement can overwrite an earlier assignment in the same call. Make this intentional: assign safe defaults once, then apply the state-specific commands.
Structured Text scan-by-scan execution trace
A trace should distinguish the state read at the start of a task invocation from a state value assigned during that invocation. In the example below, a StartEdge presented while State = STATE_IDLE writes STATE_STARTING. The starting branch does not execute retroactively; it is selected on the next invocation. That one-cycle boundary is often hidden by an online display that refreshes much more slowly than the PLC task.
| Invocation | Sampled inputs | State selecting CASE branch |
Key statements | State after routine | Ordinary motor command |
|---|---|---|---|---|---|
| 0 | No request; no feedback | IDLE |
Defaults applied; no transition | IDLE |
FALSE |
| 1 | StartEdge = TRUE; permissives healthy |
IDLE |
Writes STATE_STARTING |
STARTING |
FALSE because the starting branch has not run yet |
| 2 | Start edge cleared; no feedback | STARTING |
Enables start timer; writes command | STARTING |
TRUE |
| 3 | Feedback becomes true | STARTING |
Command remains true; feedback transition wins before timeout branch | RUNNING |
TRUE |
| 4 | Feedback remains true | RUNNING |
Starting timer enable is false; running state owns output | RUNNING |
TRUE |
| 5 | Stop request true | RUNNING |
Writes STATE_STOPPING; default/branch removes command according to design |
STOPPING |
Defined by the selected stop behavior |
Three review lessons follow:
- Transition order is priority. If feedback and timeout are true on the same invocation, the first satisfied
IF / ELSIFbranch wins. Write and test that priority deliberately. - Assignment order is ownership. Two assignments to
MotorCommandin one routine are legal; the later executed assignment determines the value leaving that routine. Across routines or tasks, ownership can become harder to see. - Online animation is not a scan trace. A human interface refreshing every few hundred milliseconds can skip many PLC cycles. Use a controller trace, sequence log or captured variables when the one-scan order matters.
Structured Text syntax essentials
The common core includes assignments, expressions, conditional statements, CASE, and bounded loops. Variables are strongly typed, but the exact available types and implicit conversion rules still need the target compiler's documentation.
VAR
StartRequest : BOOL;
StopRequest : BOOL;
ProtectionHealthy : BOOL;
SpeedSetpointPct : REAL;
SpeedCommandPct : REAL;
END_VAR
IF StopRequest OR NOT ProtectionHealthy THEN
SpeedCommandPct := 0.0;
ELSIF StartRequest THEN
SpeedCommandPct := LIMIT(0.0, SpeedSetpointPct, 100.0);
END_IF;
Three details matter:
:=is assignment;=is equality comparison in the IEC-style syntax.- Boolean names should describe the state being true.
ProtectionHealthyis easier to review than an ambiguousOverload. - Library signatures can differ. Confirm the exact
LIMIT, timer, conversion and string functions supplied by the target platform.
Choosing between IF and CASE
Use IF / ELSIF / ELSE for a small priority decision. Use CASE when one named machine state should own the outputs and legal transitions. Deeply nested IF statements often hide priority and recovery paths.
Timer instances
Timers are function blocks with internal state. Declare an instance, call it every relevant scan, and read its outputs. Do not assume a timer behaves like a stateless function.
VAR
StartTimeout : TON;
END_VAR
StartTimeout(IN := State = STATE_STARTING, PT := T#3s);
IF StartTimeout.Q AND NOT MotorFeedback THEN
FaultCode := FAULT_START_TIMEOUT;
State := STATE_FAULTED;
END_IF;
The generic example shows intent. Timer type names, input/output names, reset behavior and retentivity must be checked on the selected runtime.
Structured Text program example contract
Code is only “complete” relative to a stated problem. This example controls the ordinary start, run, stop and fault sequence of one conveyor motor. It does not implement the safety-related stop, starter/VFD power circuit or physical I/O mapping. Those boundaries are independently designed and verified.
Problem statement and assumptions
When the conveyor is idle, a one-scan start request may begin a start attempt if all ordinary permissives are healthy. The PLC commands the motor and waits for running feedback. Missing feedback within the allowed start time causes a latched fault. A stop request or lost permissive removes the run command and enters a stopping state; feedback must disappear within the allowed stop time. Reset is accepted only while feedback is off and permissives are healthy.
Assumptions for the platform-neutral listing:
StartEdgeandResetEdgeare already one-invocation pulses created by a reviewed edge detector.MotorFeedback = TRUEmeans the ordinary running-status signal is present; it is not proof of safe standstill.PermissivesHealthycombines ordinary process permissives, not the certified safety function.- Timer instances use the common IEC-style
TON(IN, PT)interface shown. Translate to the target library rather than renaming blindly. - All variables shown as persistent program variables retain their value from one invocation to the next while the program runs. Power-cycle retentivity is a separate configuration decision.
I/O and internal-state list
| Name | Direction/type | Physical or logical meaning | Testable states |
|---|---|---|---|
StartEdge |
Input BOOL |
One accepted ordinary start request | No pulse, one pulse, held button converted to one pulse |
StopRequest |
Input BOOL |
Ordinary stop request | False, true during starting, true during running |
ResetEdge |
Input BOOL |
One accepted fault-reset request | No pulse, pulse while unsafe to reset, valid pulse |
PermissivesHealthy |
Input BOOL |
Combined ordinary process permission | Healthy at start, lost during start/run, restored |
MotorFeedback |
Input BOOL |
Contactor/drive/motor running status selected by design | Off, delayed on, lost while running, stuck on while stopping |
MotorCommand |
Output BOOL |
Ordinary motor run request | Off in idle/fault; on during valid starting/running |
FaultActive |
Output BOOL |
Sequence is in fault state | False outside fault; true in STATE_FAULTED |
FaultCode |
Output UINT |
First actionable sequence diagnosis | None, start timeout, feedback lost, stop timeout, invalid state |
State |
Internal enum | Exclusive sequence owner | Idle, starting, running, stopping, faulted |
| Timer instances | Internal FBs | Start/stop supervision state | Disabled/reset, timing, done |
Acceptance cases before code review closes
| Case | Initial state | Stimulus | Expected state/output | Failure the case exposes |
|---|---|---|---|---|
| Normal start | Idle, permissives healthy, feedback off | One StartEdge, then feedback before timeout |
Starting then Running; command remains on | Missing transition or command gap |
| Held start | Idle | Physical button held but edge logic emits one pulse | One start attempt only | Level-sensitive repeated start/restart |
| Start timeout | Starting | Feedback remains off until timeout | Faulted; command off; start-timeout code | Endless starting state |
| Stop during start | Starting | StopRequest = TRUE |
Stopping; command off | Stop priority below start completion |
| Lost permissive | Running | PermissivesHealthy = FALSE |
Stopping; command off | Permissive checked only at initial start |
| Feedback lost | Running | Feedback false without a stop request | Faulted with feedback-lost code | Silent run-status loss |
| Stop timeout | Stopping | Feedback remains true | Faulted with stop-timeout code | False assumption that command-off equals stopped |
| Reset rejected | Faulted, feedback true | Reset edge | Remains faulted | Reset permits unintended restart/uncleared motion |
| Invalid state | Approved isolated test | Inject out-of-range state representation if platform permits | Faulted with unknown-state code | Unhandled enum/data corruption |
| Controlled restart | Defined stopped setup | Runtime power/mode cycle | Documented state and outputs; no automatic motion | Unreviewed initialization/retentivity |
Complete Structured Text state-machine example
The example below controls an ordinary conveyor sequence. It is not safety logic. A safety-rated system must independently remove or prevent hazardous motion according to the validated design.
TYPE ConveyorState :
(
STATE_IDLE,
STATE_STARTING,
STATE_RUNNING,
STATE_STOPPING,
STATE_FAULTED
);
END_TYPE
VAR
State : ConveyorState := STATE_IDLE;
StartEdge : BOOL;
StopRequest : BOOL;
ResetEdge : BOOL;
PermissivesHealthy : BOOL;
MotorFeedback : BOOL;
MotorCommand : BOOL;
FaultActive : BOOL;
FaultCode : UINT;
StartTimeout : TON;
StopTimeout : TON;
END_VAR
(* Safe ordinary-control defaults for this scan. *)
MotorCommand := FALSE;
FaultActive := FALSE;
StartTimeout(IN := State = STATE_STARTING, PT := T#3s);
StopTimeout(IN := State = STATE_STOPPING, PT := T#5s);
CASE State OF
STATE_IDLE:
IF StartEdge AND PermissivesHealthy THEN
State := STATE_STARTING;
END_IF;
STATE_STARTING:
MotorCommand := PermissivesHealthy;
IF StopRequest OR NOT PermissivesHealthy THEN
State := STATE_STOPPING;
ELSIF MotorFeedback THEN
State := STATE_RUNNING;
ELSIF StartTimeout.Q THEN
FaultCode := 1; (* Start feedback timeout *)
State := STATE_FAULTED;
END_IF;
STATE_RUNNING:
MotorCommand := PermissivesHealthy;
IF StopRequest OR NOT PermissivesHealthy THEN
State := STATE_STOPPING;
ELSIF NOT MotorFeedback THEN
FaultCode := 2; (* Feedback lost while commanded *)
State := STATE_FAULTED;
END_IF;
STATE_STOPPING:
IF NOT MotorFeedback THEN
State := STATE_IDLE;
ELSIF StopTimeout.Q THEN
FaultCode := 3; (* Stop feedback timeout *)
State := STATE_FAULTED;
END_IF;
STATE_FAULTED:
FaultActive := TRUE;
IF ResetEdge AND NOT MotorFeedback AND PermissivesHealthy THEN
FaultCode := 0;
State := STATE_IDLE;
END_IF;
ELSE
FaultCode := 999; (* Unknown-state recovery *)
State := STATE_FAULTED;
END_CASE;
Download the complete ST example and its acceptance-test CSV. Treat the file as platform-neutral teaching code: import or translate it only after checking the target compiler and I/O mapping.
Why the example is structured this way
- Outputs receive explicit defaults before the state logic.
- Every transition has a readable condition.
- A start command is different from running feedback.
- Starting and stopping have separate timeouts.
- Reset is accepted only from a known stopped condition.
- The
ELSEbranch catches an invalid state value. - The example avoids hidden retained run bits.
Run the Structured Text sequence and edge cases in the browser before translating it to a target controller. PLC Programming IO and PLC Simulation Software share ownership. The browser lab helps prove logic behavior; it does not validate wiring, safety, target timing, retentivity or firmware-specific behavior.
Functions and function blocks
| Program organization unit | State between calls? | Typical use |
|---|---|---|
| Function | Normally no instance state | Conversion or calculation with a returned value |
| Function block | Yes, per instance | Timer, valve object, motor object or sequence module |
| Program | Runtime/project dependent organization | Scheduled application logic and coordination |
A function block is useful when a machine object needs state, but its interface should stay small and diagnosable. Prefer explicit request, permissive, feedback and reset inputs over dozens of global tags.
Function-block review questions
- Is each instance called exactly where the task design expects?
- Are outputs assigned for disabled and faulted states?
- Can an HMI command bypass a permissive?
- Are retained and non-retained fields documented?
- Does the diagnostic distinguish command, feedback, timeout and configuration faults?
- Can the block be tested without energizing real outputs?
Structured Text program examples by control task
Examples should teach a transferable pattern and expose the condition that breaks it. These short listings use common IEC-style notation; declarations, instruction names, parameter order and restart behavior still belong to the target environment.
| Control task | Useful ST pattern | Required edge case | Better home elsewhere when… |
|---|---|---|---|
| Stop-dominant run memory | Priority IF / ELSIF plus one writer |
Start and stop true together; permissive lost | Certified safety behavior is required |
| Analog scaling | Typed conversion, span validation and clamping | Zero span, overrange, underrange and bad quality | A supported vendor scaling block owns diagnostics |
| One-shot request | Persistent edge-detector instance | Held input, restart while high and skipped call | Hardware capture is needed for a shorter-than-task pulse |
| Exclusive machine sequence | Enum plus CASE and explicit transition timeouts |
Simultaneous transition conditions and invalid state | A platform sequence/SFC tool is clearer to the team |
| Repeated channel calculation | Bounded FOR loop over declared array bounds |
Index at both ends and task worst case | Work cannot finish within the task budget |
| Reusable equipment object | Function block with request, feedback, state and diagnostics | Multiple independent instances and disabled calls | Hidden globals or uncontrolled methods would dominate behavior |
Stop-dominant motor run memory
The order makes the intended priority obvious: stop or lost permission clears memory before a start edge can set it. This is ordinary process control, not a safety circuit.
IF StopRequest OR NOT PermissivesHealthy THEN
RunMemory := FALSE;
ELSIF StartEdge THEN
RunMemory := TRUE;
END_IF;
MotorCommand := RunMemory AND PermissivesHealthy;
Test start and stop true together, a held start, a permission that drops for one task, download/mode change and power restart. Decide explicitly whether RunMemory initializes, retains or reconstructs from a machine state. Never let an HMI write the internal memory and the routine write it too without defined arbitration.
Analog scaling with a valid configuration boundary
This example demonstrates the calculation structure, not a universal raw range. It rejects a zero/negative span before division and reports whether the raw value lies inside the configured measurement endpoints.
RawSpan := RawHigh - RawLow;
ScaleConfigured := RawSpan > 0;
IF ScaleConfigured THEN
RawAsReal := DINT_TO_REAL(RawInput);
EngineeringValue := EngLow
+ ((RawAsReal - DINT_TO_REAL(RawLow))
/ DINT_TO_REAL(RawSpan))
* (EngHigh - EngLow);
SignalInRange := (RawInput >= RawLow) AND (RawInput <= RawHigh);
ELSE
EngineeringValue := EngLow;
SignalInRange := FALSE;
END_IF;
The code deliberately keeps configuration validity separate from signal plausibility. A calculation can succeed while the input is overrange. Decide whether to clamp the displayed value, preserve the diagnostic value, substitute a fallback or inhibit control according to the process requirements. The exact conversion functions and overflow behavior vary by compiler.
One-shot request with a persistent edge instance
Many PLC instructions execute every time they are scanned. Rockwell's Structured Text instruction guidance specifically warns that an instruction inside IF tag_xic THEN executes on every scan while the condition is true unless the programmer supplies edge conditioning.
VAR
StartRise : R_TRIG;
END_VAR
StartRise(CLK := StartPushbutton);
StartEdge := StartRise.Q;
Call the instance consistently so it observes both low and high states. Test power-up while the physical input is already high, a one-task pulse, a held input and repeated low/high changes. For Logix, Siemens or another platform, use the supported edge instruction/pattern and document its prescan/restart behavior.
Single-writer output composition
Instead of assigning the physical output from multiple branches, calculate requests and compose the final command once near the interface boundary:
SequenceRunRequest := (State = STATE_STARTING) OR (State = STATE_RUNNING);
MaintenanceRunRequest := MaintenanceMode AND JogHeld;
MotorCommand := PermissivesHealthy
AND NOT OrdinaryStopRequest
AND (SequenceRunRequest OR MaintenanceRunRequest);
This does not solve arbitration automatically, but it creates one inspectable writer. The design still needs to define which modes are mutually exclusive, whether a transition can leave both requests true, and how safety-rated control acts independently of this ordinary output expression.
Defensive Structured Text patterns
PLC code must remain predictable when values are bad, feedback is late or a sequence enters an unexpected state.
Use these patterns:
- Default then override. Clear ordinary commands before the state-specific branch.
- Range-check indices. Never trust recipe or HMI indices before array access.
- Bound loops. A PLC task cannot tolerate open-ended work hidden inside a loop.
- Time out handshakes. Define what happens when the next device never responds.
- Separate validation from conversion. A successful type conversion does not mean the source value is plausible.
- Detect stale data. Communications status, sequence numbers or timestamps may be needed at integration boundaries.
- Handle the unknown state. A
CASE ... ELSEbranch provides a defined recovery path.
Do not describe ordinary defensive ST as safety-rated simply because it drives an output to false. Functional-safety logic requires the selected certified platform, safety requirements, verification and validation process.
Arrays and bounded loops
Arrays make repeated calculations compact, but the task still performs every iteration. Measure the worst case on the target CPU and task.
VAR
Samples : ARRAY[0..9] OF REAL;
Sum : REAL;
Average : REAL;
Index : INT;
END_VAR
Sum := 0.0;
FOR Index := 0 TO 9 DO
Sum := Sum + Samples[Index];
END_FOR;
Average := Sum / 10.0;
Check the declared bounds, counter type and loop limit. CODESYS explicitly documents a counter-overflow pitfall when the loop end equals the maximum value of a small integer type. Do not assume every compiler handles overflow, CONTINUE, or malformed bounds the same way.
For larger data sets, distribute the work across scans, use a bounded index state, or move non-control analytics to an appropriate external service. Whether that is necessary depends on the task period, controller load and required response—not on a generic line-count rule.
Structured Text vendor differences
Siemens SCL
Siemens calls its Structured Text implementation Structured Control Language (SCL). TIA Portal supports SCL blocks on applicable SIMATIC controllers. Confirm the target CPU, firmware and STEP 7 version because supported instructions and block behavior vary.
Rockwell Logix Structured Text
Studio 5000 Logix Designer provides Structured Text routines and documents its syntax, data types and instruction behavior in versioned online help. Rockwell's implementation is not a drop-in CODESYS project: tags, routines, Add-On Instructions, task structure and controller instruction support belong to the Logix environment.
CODESYS ST and ExST
CODESYS documents both ST and its Extended Structured Text (ExST) additions. An extension supported in one CODESYS target or compiler version should not be assumed portable to another toolchain. Build, download and test on the selected device description and runtime.
| Boundary | What may differ |
|---|---|
| Data types | Supported widths, strings, aliases, layouts and conversions |
| Task model | Priority, period, watchdog, event tasks and I/O update |
| Libraries | Timer behavior, string functions, motion, communications and diagnostics |
| Retentivity | Declaration, memory region, download and restart behavior |
| Project structure | Program, routine, block and namespace organization |
| Online changes | What can be edited, tested, accepted or rolled back |
Vendor translation checklist
| Boundary | CODESYS-family question | Siemens SCL question | Rockwell Logix ST question |
|---|---|---|---|
| Declarations | Which POU, scope, namespace and compiler extensions are enabled? | Is the value local, static, temporary, input/output or in an instance/global DB? | Is it a controller/program tag, routine parameter, UDT or instruction control structure? |
| Timer/counter | Which standard/library FB instance and call semantics apply? | Which IEC timer instance form and block storage are supported on this CPU/project? | Which timer/counter instruction is available in ST for this controller/version and what structure does it use? |
| Rising edge | Is R_TRIG from the selected library called every required cycle? |
Is the edge memory stored in a persistent block location with defined restart behavior? | Is a supported one-shot instruction/control tag used and prescan behavior understood? |
| Data conversion | Are implicit/explicit conversions and target-native intermediate widths acceptable? | Do optimized blocks, typed constants and conversion functions match the interface? | Do tag types and instruction operands match the versioned Logix reference? |
| Task/runtime | Which task calls the program, with what interval, priority and watchdog? | Which organization block/cyclic task calls the block, and when is I/O updated? | Which task/program/routine calls the ST routine and what are its period/priority/watchdog? |
| Restart/change | What initializes or retains after reset, download and online change? | What is remanent, initialized or re-created in the data block? | What do prescan, program-mode transition and download do to tags/instructions? |
The current CODESYS CASE reference documents labels, ranges and ELSE; Rockwell's Logix ST programming manual documents its own constructs; Siemens publishes both an S7-1200/1500 programming guideline and a TIA Portal programming style guide. Use those product sources to translate the pattern, then run the same cases.
Common Structured Text compile and runtime faults
| Symptom | Likely cause | Evidence to inspect | Corrective direction |
|---|---|---|---|
Compile error at END_IF or next line |
Missing semicolon, wrong terminator or dialect mismatch earlier | First compiler diagnostic and preceding statement | Fix the earliest error; confirm target syntax rather than adding punctuation randomly |
| Value changes back within one task | Later assignment or second writer | Cross-reference, write breakpoints/trace and routine order | Establish one owner or explicit arbitration |
| Timer never finishes | Instance not called consistently, enable resets, wrong time literal or dialect | Instance IN/Q/ET, call path and exact timer manual |
Use explicit enable and tested call/reset behavior |
| Action repeats while button is held | Level condition used where an edge was required | Input, edge memory and action counter scan trace | Add a supported one-shot pattern and restart test |
| Array logic faults only at last element | Inclusive bound/index mismatch or typed counter overflow | Declaration bounds, loop start/end and runtime exception | Derive/test bounds and choose a counter type that can exit |
| Analog result jumps or saturates | Integer division, conversion/overflow or invalid span | Operand types, intermediate values and quality flags | Convert deliberately; validate span and range before use |
| Behavior differs after restart | Initial/retained values or prescan behavior not defined | Power/mode-cycle trace and memory configuration | Specify initialization and retentivity as requirements |
| Watchdog/task overrun | Unbounded loop, variable work, blocking library or excessive processing | Worst execution time, task diagnostics and loop count | Bound/distribute work or change architecture after measurement |
| Browser result passes, target fails | Dialect, timer, task, I/O or retained-state difference | Compiler report and side-by-side acceptance record | Translate the boundary and repeat cases on the selected target |
| Code stops motion but safety claim is unsupported | Ordinary logic confused with certified safety function | Risk assessment, safety requirements and certified platform docs | Keep ordinary sequence and safety lifecycle separate |
Structured Text vs Ladder Logic
Choose the language from the task and maintainers rather than calling one language universally better.
| Requirement | Usually favors ST | Usually favors Ladder |
|---|---|---|
| Array or recipe processing | Yes | No |
| State-machine transitions | Often | Sometimes |
| Dense calculations | Yes | No |
| Simple permissive chain | Sometimes | Often |
| Online electrical-style tracing | No | Often |
| Reusable text-based algorithm | Yes | Sometimes |
Mixed-language projects are normal where the platform supports them. The important part is a shared tag model, reviewable interfaces and matched acceptance tests.
Structured Text test and commissioning checklist
Run the example with the physical output isolated or in an approved test environment.
| Test | Action | Expected evidence |
|---|---|---|
| Normal start | Start edge with all permissives | Starting then Running after feedback |
| Start timeout | Hold feedback false | Fault code 1 and command removed |
| Stop request | Stop while running | Command removed and Stopping entered |
| Stop timeout | Hold feedback true | Fault code 3 and Faulted state |
| Lost permissive | Remove a permissive while running | Command removed; recovery path recorded |
| Invalid state | Force only in an approved test | ELSE branch moves to Faulted |
| Held start | Keep request true through recovery | No unintended restart if edge logic is required |
| Controller restart | Controlled mode/power cycle | Defined state and outputs, no unintended movement |
Record:
- controller, firmware and engineering-tool versions;
- task period, priority and watchdog;
- project checksum or version identifier;
- initial and retained values;
- test inputs, observed transitions and timestamps;
- any differences between simulator and target runtime; and
- reviewer approval plus unresolved deviations.
Frequently asked questions
What is Structured Text PLC programming?
Structured Text (ST) is the textual programming language defined within IEC 61131-3 for programmable-controller applications. It expresses typed assignments, conditions, loops, functions and function-block calls inside a PLC task. The standard provides a baseline; the selected vendor determines the engineering project, task configuration, libraries, instruction availability and target behavior.
What is a simple Structured Text program example?
A stop-dominant motor request is a useful first example: clear run memory when stop is requested or permissives are unhealthy, set it on a one-scan start edge, then compose the ordinary motor command once. Even this small program needs tests for simultaneous start/stop, held start, lost permissive and restart state.
Does Structured Text execute from top to bottom?
Statements in an invoked routine execute in order, so a later executed assignment can overwrite an earlier one. The complete behavior also depends on the PLC task, program/routine order, conditional calls, I/O update and other writers. Use a scan trace and cross-reference when order affects the result.
Should I use IF or CASE in Structured Text?
Use IF / ELSIF / ELSE for a small prioritized decision. Use CASE when one enumerated machine state should own outputs and legal transitions. Add an ELSE or equivalent unknown-state policy where the target compiler and state representation make that appropriate, and test simultaneous transition conditions.
How do timers work in Structured Text?
Timers are stateful instructions or function blocks whose exact call, reset, time base, fields and skipped-call behavior vary by platform. Declare the required instance/control data, call it as the vendor documents, expose its enable/done/elapsed evidence and test state entry, exit, timeout, reset and restart.
How do I make a one-shot in Structured Text?
Use the target platform's supported rising-edge instruction or a reviewed previous-state pattern. The edge detector needs persistent memory and consistent invocation. Test a one-task pulse, held input, repeated low/high cycles, and restart while the physical input is already high.
Are Structured Text examples portable between PLC brands?
Algorithms and state models can be portable, but source is not automatically drop-in. Declarations, timers, edge instructions, conversions, namespaces/data blocks, tasks, retentivity and libraries differ among CODESYS, Siemens SCL, Rockwell Logix ST and other environments. Compile and run the same acceptance matrix on each target.
How do I prevent a Structured Text loop from overrunning the PLC task?
Prefer a bounded FOR loop over declared array bounds, choose a counter type that can pass the terminal value, and measure worst-case execution in the configured task. Put an explicit iteration guard around condition-based loops. If the work cannot fit with margin, distribute it across scans or move it outside the control task.
How should I test a Structured Text state machine?
Test every normal transition, every timeout, simultaneous conditions, held requests, lost feedback/permissives, invalid state handling, reset rejection and controlled restart. Record current state, next state, timers, commands, feedback, fault code and task timestamps. Run logic tests first, then repeat target-specific cases with I/O isolated or under an approved commissioning plan.
Where can I run Structured Text code without a PLC?
Use a browser learning simulator or a vendor-supported simulator/runtime appropriate to the goal. The runnable Structured Text learning path can grade logic examples without hardware. It shares ownership with this site and is not a firmware-exact substitute for the selected PLC, engineering tool, field I/O or safety validation.
Sources, review scope, and limitations
This owner was reviewed on 29 August 2026 against the current standard record and primary vendor documentation. Direct links let readers and AI answer systems distinguish common IEC-style patterns from product-specific behavior.
- IEC 61131-3:2025 Edition 4 publication record
- PLCopen-hosted IEC 61131-3:2025 table of contents
- PLCopen coding guidelines for IEC 61131-3
- CODESYS Structured Text editor
- CODESYS ST
IFstatement - CODESYS ST
CASEstatement - CODESYS ST
FORstatement and overflow caution - CODESYS Extended ST
CONTINUEstatement - Rockwell Automation Logix Designer Structured Text syntax
- Rockwell Automation Structured Text instruction execution
- Rockwell Automation Logix 5000 Structured Text programming manual
- Rockwell Automation timer and counter instruction availability
- Siemens programming guideline for S7-1200/1500
- Siemens programming style guide for TIA Portal
- Beckhoff TwinCAT 3 PLC quickstart and IEC language support
- Beckhoff TwinCAT programming languages and editors
- Beckhoff state-machine, timer and trigger sample
- Beckhoff task configuration and watchdog settings
- Beckhoff ST operators and target-dependent overflow note
- Schneider Electric Machine Expert Structured Text code development
Limitations: the examples are vendor-neutral teaching patterns and were not compiled unchanged on every listed platform. The article does not define a safety lifecycle, certify scan time, validate physical I/O or replace the selected controller's versioned manuals. Preserve the problem statement and acceptance cases when translating; record every dialect/runtime deviation rather than silently changing the intended behavior.
Continue with the PLC programming languages guide, state-machine glossary, PLC scan-cycle guide and practical PLC examples.


