
Array and Enumeration in Structured Text
What is an array:
An array can be defined as an ordered collection of items indexed by contiguous integers. An array is a data structure that can store a number of variables of the same data type in sequence. These similar elements could be of type int, float, double, char, Function Block, etc.
Arrays are used when there is a need to use many variables of the same type. It can be defined as a sequence of objects which are of the same data type. It is used to store a collection of data, and it is more useful to think of an array as a collection of variables of the same type. Arrays can be declared and used. A programmer has to specify the types of elements and the number of elements that are required by an array. This is called a single-dimensional array. The array size should be an integer constant and greater than zero.
One-, two-, and three-dimensional fields (arrays) are supported as elementary data types. Arrays can be defined both in the declaration part of a POU and in the global variable lists.
In the following statement, we declare an array of 5 integers and initialized them with 1, 2, 3, 4, and 5 respectively.
ArrayInt : ARRAY [1..5] OF INT := [1,2,3,4,5];
Look at the syntax ARRAY[lower..upper] OF allows us to define any lower or upper bounds. As compared to C#, our lower bound doesn’t have to be zero. The total number of elements in the array is upper – lower + 1. We could have declared the above statement as the following as well
ArrayInt : ARRAY [2..6] OF INT := [1,2,3,4,5];
In this case, we have accessed first number by by the following way.
firstOne := ArrayInt[2]; // 1
Now we shall describe, how we can declare an array of FUNCTION_BLOCK
Sample function block
FUNCTION_BLOCK MotorAC VAR_INPUT machineName : WSTRING :="Type A"; END_VAR VAR_OUTPUT machineAlarm : BOOL := FALSE; END_VAR VAR maxRotationValue : REAL := 0.0; rotationPerSeconds : INT := 0; myTimer : TON ; startMachine : BOOL := FALSE; END_VAR
We declare and initialize those array of 3 instances in the following way.
ArrayMotorAc : ARRAY [1..3] OF MotorAC := [ (machineName:= "Motor_one"), (machineName:= "Motor_two"), (machineName:= "Motor_three") ];
Initialization can be done in the following way.
FOR index := 1 TO number_of_motor DO
ArrayMotorAc[index].InitMachine();
END_FOR;
Arrays with variable length
We can pass pointer of data to a method and calculate the index as shown in the following example.
FUNCTION FuncArrayTestByPointer : INT
VAR_INPUT
pData : POINTER TO INT;
nSize : UDINT;
END_VAR
VAR
pIndex : POINTER TO INT;
nUpperIndex : UDINT;
nIndex : UDINT;
END_VAR
FuncArrayTestByPointer := 0;
nUpperIndex := nSize / SIZEOF(pIndex^);
IF (nUpperIndex > 0) THEN
FOR nIndex := 0 TO (nUpperIndex - 1) DO
pIndex := pData + (nIndex * SIZEOF(pIndex^));
FuncArrayTestByPointer := FuncArrayTestByPointer + pIndex^;
END_FOR
END_IF
Example usage
array : ARRAY[2..6] OF INT := [16, 34, 4, 43, 35];
Sum : INT;
Sum := FuncArrayTestByPointer(ADR(array), SIZEOF(array));
Newer way use the variable array as defined in 3rd Edition of IEC 61131-3
In function blocks, functions or methods, arrays with variable length can be declared in the declaration section VAR_IN_OUT. The operators LOWER_BOUND and UPPER_BOUND can be used to determine the index limits of the array that is actually used at runtime. LOWER_BOUND returns the lower limit, UPPER_BOUND returns the upper limit.
FUNCTION FuncArrayTestByPointerNewWay : INT
VAR_IN_OUT
arrData : ARRAY[*] OF INT;
END_VAR
VAR
nIndex : DINT;
END_VAR
FuncArrayTestByPointerNewWay := 0;
FOR nIndex := LOWER_BOUND(arrData, 1) TO UPPER_BOUND(arrData, 1) DO
FuncArrayTestByPointerNewWay := FuncArrayTestByPointerNewWay + arrData[nIndex];
END_FOR
Example usage
array : ARRAY[2..8] OF INT := [36, 34, 4, 43, 35, 2, 65];
Sum : INT;
Sum := FuncArrayTestByPointerNewWay(array);
PLC Array index and HMI array index
We declare an array like the following.
ArrayInt : ARRAY [5..9] OF INT := [10,2,3,4,5];
myvar : INT := -1;
END_VAR
//body
myvar := ArrayInt[5];
We have mapped those variables and want to display the ArrayInt and myvar on the HMI, see the mapping in the following picture.

Figure 01: ArrayInt[5] is mapped as ArrayInt[0] in HMI
As we see in the HMI it is mapped from 0 to 4 and in the PLC it is declared as 5 to 0. This is the default behavior. We can read the first item by the following code. Note that we are using ArrayInt[0] not 5
async function asyncFunctionCall() {
try {
const myvar = await ReadPLCVariable('%s%PLC1.MAIN.ArrayInt[0]%/s%');
var myTextBlockControl = TcHmi.Controls.get('TcHmiTextblock_1');
myTextBlockControl.setText(myvar);
}
catch(error) {
console.log(`ErrorCode = ${error.ErrorCode}`);
console.log(`ErrorText = ${error.ErrorText}`);
}
}
asyncFunctionCall();

Figure 02: Second text block shows the number as read by the above code
Real Sample
A sample has been developed which can be adapted to real project. There are few function block where pointer are passed and action is called on the pointer.
PROGRAM MAIN
VAR
ArrayMotorAc : ARRAY [1..3] OF MotorAC := [
(machineName:= 'Motor_one', counterVar := 1),
(machineName:= 'Motor_two', counterVar := 2),
(machineName:= 'Motor_three', counterVar := 3)
];
doworkVar : DoWork;
initDone : BOOL := FALSE;
index : INT := 1;
number_of_motor : INT := 3;
END_VAR
IF NOT initDone THEN
//we pass the pointer and number of index, action, method etc can be called on pointer
doworkVar(param := ADR(ArrayMotorAc), lastIndex:= 2);
initDone := TRUE;
FOR index := 1 TO number_of_motor DO
ArrayMotorAc[index].InitMachine();
END_FOR;
END_IF
doworkVar();
FOR index := 1 TO number_of_motor DO
ArrayMotorAc[index]();
END_FOR;
FUNCTION_BLOCK DoWork
VAR_INPUT
param : POINTER TO MotorAC; // first address
lastIndex : UINT; //Last index
END_VAR
VAR_OUTPUT
END_VAR
VAR
index : UINT := 1;
number_of_motor : UINT := 3;
param2 : POINTER TO MotorAC;
startTimer : BOOL := FALSE;
myTimer : TON;
END_VAR
myTimer(IN:= startTimer, PT:=T#20S);
IF myTimer.Q = TRUE THEN
myTimer(IN:= FALSE);
FOR index := 0 TO lastIndex DO
IF param <> NULL THEN
//param^.Reset();
param2 := param + (index * SIZEOF(param^)); //calculate the current pointer address
param2^.Reset();
END_IF
END_FOR;
END_IF
Tips
=> Changing index in HMI
Index in PLC can have any index, we can adjust the index HMI in the following way.

Some info related to variable length in array.
LOWER_BOUND(arrData, 1) returns as lower bound of the supplied array, and its type is DINT. We can know the number of items by substracting lower bound from the upper bound.
References:
Download the sample from the link given above.
Next, let’s try understand pointer and memory https://www.hemelix.com/plc/structured-text-memory-management/
Ask questions related to Hemelix sample code and design at Google group https://groups.google.com/g/hemelix