open image in lightbox

Loops in TwinCAT: Breaking Down Struc­tured Text Iterations


Iteration is a core concept in programming, and Structured Text (ST) provides a variety of loop types to implement it. However, when working with TwinCAT, understanding the behavior of loops—especially the FOR-loop—can be trickier than it seems. This article offers a concise introduction to TwinCAT loops and their peculiarities.

FOR-Loop

The FOR-loop is an entry-controlled loop that executes statements repeatedly until the <counter> meets the specified end condition:

  • Without a<step size expression>: Loop stops when the <counter> is greater than the <end condition expression>.

  • With a positive <step size expression>: Loop stops when the <counter> exceeds the <end condition expression>.

  • With a negative <step size expression>: Loop stops when the <counter> is below the <end condition expression>.

The following components must be or return an integer:

  • <counter>, <initial expression>, <end condition expression>, and <step size expression>:

    • ANY_BIT: BYTE, WORD, DWORD, LWORD, __XWORD

    • ANY_INT: SINT, USINT, INT, UINT, DINT, UDINT, LINT, ULINT, __XINT, or __UXINT

After each execution of the loop’s <instructions>, the <counter> is automatically incremented by the value of the <step size expression>. If no step size is specified, the default step size is 1.

The <end condition expression> must not match the upper or lower limits of the <counter> data type, as this could result in an endless loop due to overflow.

The EXIT-statement is used to jump out of a loop.

The CONTINUE-statement interrupts the current iteration and proceeds with the next iteration of the loop.

Syntax

FOR <counter> := <initialization expression> TO <end condition expression> [BY <step size expression>] DO
<instruction>
[CONTINUE;]
[EXIT;]
[<instructions>]
END_FOR

The parts in square brackets are optional.

Flowchart

The <step size expression> is evaluated three times per loop cycle because of a fully evaluated OR. The <end condition expression> is evaluated once per cycle without <step size expression> and twice per cycle with <step size expression>.

Examples

Simple Examples

VAR
	i :LINT;
	squares :ARRAY[0..20] OF LINT;
END_VAR
VAR
	FIRST_SQUARE :LINT := LOWER_BOUND(squares,1);
	LAST_SQUARE :LINT := UPPER_BOUND(squares,1);
END_VAR

FOR i := FIRST_SQUARE TO LAST_SQUARE DO	
	squares[i] := i*i;
END_FOR

Example with Pointer Operations

VAR
	foo : T_MaxString := 'Hello foo';
	bar : POINTER TO BYTE;
	baz : PVOID;
	inverseFoo : T_MaxString;
END_VAR

(* clean the memory before we start *)
Tc2_System.MEMSET(ADR(inverseFoo),0,TO_UDINT(Tc2_Standard.LEN(foo)+1));
(* store the inverse content of foo in inverseFoo *)
FOR baz := bar := ADR(foo) + TO___UXINT(MAX(Tc2_Standard.LEN(foo)-1,0)) TO ADR(foo) BY -1 DO
	bar := baz;
	inverseFoo := Tc2_Standard.CONCAT(inverseFoo, CHR(bar^));
END_FOR

Example with EXIT and CONTINUE

VAR
	actBit :DINT;
	bar :WORD;
	highestSetBit :DINT(-1..15);
END_VAR

(* For loop finds the number of the highest set bit *)
FOR actBit := 15 TO 0 BY -1 DO
	IF (bar = 0) THEN
		highestSetBit := -1;
		EXIT;
	END_IF
	IF ((bar AND SHL(1,actBit)) = 0) THEN
		CONTINUE;
	END_IF
	highestSetBit := actBit;
	EXIT;
END_FOR

Example with Complex Expressions

VAR
	values :ARRAY[0..20] OF WORD;
	a,b,c,d  :WORD;
END_VAR

(*
for loop that calculates the fibonacci sequence up to 100.
- the init expression is called only once
	- the expression (a := c := d := 0) returns 0 so b is initailized with 1 and b is the counter varibale
- the condition expression is called twice per cycle
	- the expression (0 AND (c := (d := d + 1) / 2)) returns 0 because of the bitwise AND 0 but it increments d by two and c by one every loop cycle because it is called twice per loop cycle
- the step size expression will be called three times per loop cycle a is the (c-1)th fibonacci number and b is the (c+1)th fibonacci number   
*)
FOR b := 1 + (a := c := d := 0) TO 100 * 3 + (0 AND (c := (d := d + 1) / 2)) BY (a := b - a) DO	
	values[c - 1] := a;
END_FOR

WHILE-Loop

The WHILE-loop is an entry-controlled loop that executes statements repeatedly until the <condition expression> returns FALSE.

The EXIT-statement is used to jump out of a loop.

The CONTINUE-statement interrupts the current iteration and proceeds with the next iteration of the loop.

Syntax

WHILE <condition expression> D
<instruction>
[CONTINUE;]
[EXIT;]
[<instructions>]
END_WHILE

The parts in square brackets are optional.

Flowchart

Examples

Simple Example

VAR
	i :LINT;
	squares :ARRAY[0..20] OF LINT;
END_VAR
VAR
	FIRST_SQUARE :LINT := LOWER_BOUND(squares,1);
	LAST_SQUARE :LINT := UPPER_BOUND(squares,1);
END_VAR

i := FIRST_SQUARE;
WHILE (i <= LAST_SQUARE) DO
	squares[i] := i*i;
	i := i+1;
END_WHILE

Example with CONTINUE and EXIT

VAR
	actBit :DINT;
	bar :WORD;
	highestSetBit :DINT(-1..15);
END_VAR

ctBit := 15;
(* While loop finds the number of the highest set bit *)
WHILE (actBit >= 0) DO
	IF (bar = 0) THEN
		highestSetBit := -1;
		EXIT;
	END_IF
	IF ((bar AND SHL(1,actBit)) = 0) THEN
		actBit := actBit -1;
		CONTINUE;
	END_IF
	highestSetBit := actBit;
	EXIT;
END_WHILE

REPEAT-Loop

The REPEAT -loop is a variant of the WHILE-loop. This loop will execute the code block once, before checking if the <condition expression> is TRUE. Then it will repeat the loop as long as the <condition expression> returns FALSE.

The EXIT-statement is used to jump out of a loop.

The CONTINUE-statement interrupts the current iteration and proceeds with the next iteration of the loop.

Syntax

REPEAT
<instruction>
[CONTINUE;]
[EXIT;]
[<instructions>]
UNTIL
<condition expression>
END_REPEAT

The parts in square brackets are optional.

Flowchart

Examples

Simple Example

VAR
	i :LINT;
	squares :ARRAY[0..20] OF LINT;
END_VAR
VAR
	FIRST_SQUARE :LINT := LOWER_BOUND(squares,1);
	LAST_SQUARE :LINT := UPPER_BOUND(squares,1);
END_VAR

i := FIRST_SQUARE;
REPEAT
	squares[i] := i*i;
	i := i+1;
UNTIL
	(i > LAST_SQUARE)
END_REPEAT

Example with CONTINUE and EXIT

VAR
	actBit :DINT;
	bar :WORD;
	highestSetBit :DINT(-1..15);
END_VAR

actBit := 15;
(* While loop finds the number of the highest set bit *)
REPEAT
	IF (bar = 0) THEN
		highestSetBit := -1;
		EXIT;
	END_IF
	IF ((bar AND SHL(1,actBit)) = 0) THEN
		actBit := actBit -1;
		CONTINUE;
	END_IF
	highestSetBit := actBit;
	EXIT;
UNTIL
	(actBit < 0)
END_REPEAT

For more insights on this topic, check out our in-depth video on loops in TwinCAT on YouTube here.

@Ninjamonkeystutorials