OpenPLC Structured Text Reference
OpenPLC compiles IEC 61131-3 Structured Text via the Matiec compiler. The supported subset is large but not 100% — this reference lists what works, what is partial, and what is unsupported. Use it as a quick lookup before porting commercial Structured Text into OpenPLC.
Supported data types
BOOL, BYTE, WORD, DWORD, LWORD
SINT, USINT, INT, UINT, DINT, UDINT, LINT, ULINT
REAL, LREAL
TIME, DATE, TIME_OF_DAY, DATE_AND_TIME
STRING (max 80 chars), WSTRING
ARRAY [..] OF <basetype>
STRUCT (declared in DUT)
ENUM (typed)Operators
Arithmetic: + - * / MOD **
Comparison: = <> < > <= >=
Logical: AND OR XOR NOT
Bitwise: AND OR XOR NOT (on integer types)
Shift: SHL SHR ROL ROR (function-call style)
Assignment: := (in code), => (output assignment in FB calls)Control flow
IF cond THEN ... ELSIF cond2 THEN ... ELSE ... END_IF;
CASE var OF
1: ...
2,3,4: ...
5..10: ...
ELSE ...
END_CASE;
FOR i := 1 TO 10 BY 1 DO ... END_FOR;
WHILE cond DO ... END_WHILE;
REPEAT ... UNTIL cond END_REPEAT;
EXIT; (* break out of loop *)
RETURN; (* return from function or program *)Standard function blocks (built-in)
- Timers: TON, TOF, TP, RTC
- Counters: CTU, CTD, CTUD
- Edge detection: R_TRIG, F_TRIG
- Bistable: SR (set-dominant), RS (reset-dominant)
- Math: ABS, SQRT, LN, LOG, EXP, SIN, COS, TAN, ASIN, ACOS, ATAN
- Selection: SEL, MIN, MAX, LIMIT, MUX
- String: LEN, LEFT, RIGHT, MID, CONCAT, INSERT, DELETE, REPLACE, FIND
Known limits vs full IEC 61131-3
- No object-oriented extensions (METHOD, INTERFACE, classes from 2013 revision). Function blocks only, no inheritance.
- STRING max 80 characters by default. WSTRING for Unicode.
- No POINTER or REF_TO types — pure value semantics throughout.
- Limited multi-tasking — Matiec generates single-task code; multiple POUs run sequentially in the configured task period.
- Some math functions return slightly different types than CODESYS or TIA Portal — check the result type when porting code.
Worked example: 3-stage state machine
PROGRAM main
VAR
Step : INT := 0;
StartBtn : BOOL;
StopBtn : BOOL;
OutputA : BOOL;
OutputB : BOOL;
Timer1 : TON;
END_VAR
CASE Step OF
0: (* IDLE *)
OutputA := FALSE;
OutputB := FALSE;
IF StartBtn THEN Step := 1; END_IF;
1: (* PHASE A *)
OutputA := TRUE;
Timer1(IN := TRUE, PT := T#5s);
IF Timer1.Q THEN
Step := 2;
Timer1(IN := FALSE);
END_IF;
2: (* PHASE B *)
OutputA := FALSE;
OutputB := TRUE;
Timer1(IN := TRUE, PT := T#3s);
IF Timer1.Q THEN
Step := 0;
Timer1(IN := FALSE);
END_IF;
END_CASE;
(* Stop button always returns to IDLE *)
IF StopBtn THEN Step := 0; END_IF;
END_PROGRAM