Example TwinCAT ST Syntax Highlighting
This book is a showcase of Structured Text (ST) syntax for your mdBook using Highlight.js
Sample TwinCAT ST Code
Below are several examples of the syntax highlighting in action:
Defining an Interface
// Define an Interface for Motor Control
INTERFACE I_Motor
METHOD Start : BOOL END_METHOD
METHOD Stop : BOOL END_METHOD
METHOD SetSpeed
VAR_INPUT
fSpeed : LREAL;
END_VAR
END_METHOD
END_INTERFACE
Defining a Function Block
// Function Block implementing IMotor Interface
{attribute 'no_explicit_call' := 'do not call this POU directly'}
FUNCTION_BLOCK FB_MotorController EXTENDS FB_Object IMPLEMENTS I_Motor
VAR
_bIsRunning : BOOL;
_fCurrentSpeed : LREAL;
END_VAR
// Implementing the Start Method
METHOD Start : BOOL
THIS^._bIsRunning := TRUE;
Start := THIS^._bIsRunning;
(* Rest of code if needed... *)
END_METHOD
// Implementing the Stop Method
METHOD Stop : BOOL
THIS^._bIsRunning := FALSE;
THIS^._fCurrentSpeed := 0.0;
Stop := NOT THIS^._bIsRunning;
END_METHOD
// Implementing the SetSpeed Method
METHOD SetSpeed
VAR_INPUT
fSpeed : LREAL;
END_VAR
THIS^._fCurrentSpeed := SEL(THIS^._bIsRunning, 0.0, fSpeed);
END_METHOD
END_FUNCTION_BLOCK
Defining a Function
// Function to calculate the average given numbers
FUNCTION F_CalculateAverageSpeed : LREAL
VAR_IN_OUT CONSTANT
arSpeeds : ARRAY[*] OF LREAL;
END_VAR
VAR
fNumberOfSpeeds : LREAL;
i : __XINT;
END_VAR
fNumberOfSpeeds := TO_LREAL(
ABS(UPPER_BOUND(arSpeeds, 1) - LOWER_BOUND(arSpeeds, 1))
);
FOR i := LOWER_BOUND(arSpeeds, 1) TO UPPER_BOUND(arSpeeds, 1) DO
F_CalculateAverageSpeed := F_CalculateAverageSpeed + arSpeeds[i];
END_FOR
F_CalculateAverageSpeed := F_CalculateAverageSpeed / fNumberOfSpeeds;
END_FUNCTION
Defining a Program
// Main Program
PROGRAM MAIN
VAR
bStart : BOOL;
bStop : BOOL := TRUE;
fbMotor : FB_MotorController;
fAverageSpeed : REAL;
arSpeeds : ARRAY[0..1] OF LREAL := [150.5, 180.2];
END_VAR
// Start the motor
IF bStart THEN
bStop := NOT fbMotor.Start();
fbMotor.SetSpeed(arSpeeds[0]);
END_IF
// Stop the motor
IF bStop THEN
bStart := NOT fbMotor.Stop();
END_IF
// Calculate average speed
fAverageSpeed := F_CalculateAverageSpeed(arSpeeds);
END_PROGRAM
Working with Integer Literals
VAR
// Decimal literal with underscores for readability:
nDecimal : LINT := 18_000_000;
// Binary literal (base 2) with an underscore separator:
nBinary : LINT := 2#1001_0011;
// Octal literal (base 8) using a simple value:
nOctal : LINT := 8#22;
// Hexadecimal literal (base 16) with mixed digits and letters:
nHex : LINT := 16#12A;
// Simple integer literal using the type prefix:
nSimple : LINT := INT#44;
// Large unsigned integer literal using an unsigned type:
nUnsigned : ULINT := ULINT#4_294_967_295;
// Integer literal without underscores for comparison:
nPlain : DINT := DINT#123456;
END_VAR
Working with Real Literals
VAR CONSTANT
// Standard real literal in scientific notation:
fElementaryCharge : LREAL := LREAL#1.602E-19;
// Real literal with underscores in the integer part:
fMeasurement : LREAL := LREAL#3_141.5926535;
// Real literal with a fractional part and exponent:
fLargeValue : REAL := REAL#6.022E23; // Avogadro's number
// Real literal with underscore in exponent (for improved readability):
fReadableExp : LREAL := LREAL#2.71828E+00; // Euler's number
END_VAR
Working with Duration Literals
VAR CONSTANT
// TIME literal (without nanoseconds)
// Format: T#<value><unit>[<value><unit>...]
tSystemTick : TIME := T#1d2h3m4s5ms6us;
// TIME literal with only a single unit:
tShortDelay : TIME := T#500ms;
// LTIME literal (with nanosecond precision)
// Format: LTIME#<value><unit>[<value><unit>...]
ltPrecise : LTIME := LTIME#3h30m15s250ms125us75ns;
// LTIME literal with only hours and minutes:
ltWorking : LTIME := LTIME#2h45m;
// DATE literal (ISO format: YYYY-MM-DD)
dCurrentDay : DATE := D#2025-03-25;
// TOD (Time-of-Day) literal (HH:MM:SS)
todCurrent : TOD := TOD#22:02:44;
// DT (Date and Time) literal (YYYY-MM-DD-HH:MM:SS)
dtTimestamp : DT := DT#2025-03-25-22:02:44;
END_VAR
Working with Pointers
VAR
nValue : INT := 42;
pValue : POINTER TO INT;
END_VAR
// Assign the address of nValue to pValue
pValue := ADR(nValue);
// Dereference pValue to update nValue
nValue := pValue^ + 1;
Working with References
VAR
nOriginal : INT := 100;
nRef : REFERENCE TO INT;
END_VAR
// Assign the reference to nOriginal
nRef REF= nOriginal;
// Modify nOriginal via the reference
nRef := nRef + 10;
Working with Arrays
1. Basic Array Declarations
VAR
// One-dimensional array of INTs
arPoints : ARRAY[0..9] OF INT := [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
];
// Two-dimensional array of LREAL
arMatrixStyleA : ARRAY[1..3, 0..2] OF LREAL := [
10, 11, 12,
20, 21, 22,
30, 31, 32
];
// Two-dimensional array of LREAL using a nested array syntax
arMatrixStyleB : ARRAY[1..2] OF ARRAY[1..3] OF LREAL := [
[11, 12, 13],
[21, 22, 23]
];
END_VAR
2. Variable Length Array
// Function to transpose a matrix.
// The input parameter 'arMatrix' is declared as an open (variable length) 2D array of LREAL,
// which means it can accept matrices of any dimensions.
FUNCTION F_Transpose : INT
VAR_INPUT
arMatrix : ARRAY[*, *] OF LREAL;
END_VAR
(* Implementation... *)
END_FUNCTION