Data types of Structured Text (ST)

Just like other programming languages, the IEC 61131-3 programming standard provides many different data types which include both elementary and complex ones. A data type defines how much memory capacity is needed by a variable value and by that, the largest and smallest value in the variable.

1 Elementary data types (INT, REAL, BOOL)

The following (examples) simple data types are standard in any PLC controller:

Data type Bits Numeral system Note Lowest and highest value Eksempel
BOOL (Bit) 1 Boolean (Binary) FALSE/TRUE or 0 to 1 TRUE
BYTE 8 HEX (Hexadecimal) 16#0 to 16#FF 16#10
WORD 16 Binary 2#0 to 2#1111111111111111 2#0001000000000000
UINT 16 HEX (Hexadecimal) 16#0 to 16#FFFF 16#1000
BCD (Binary-Coded Decimal) C#0 to C#999 C#998
Unsigned Integer ( positive numbers) 0 to 65535 564
DWORD (Double word) 32 Binary 2#0 to 2#1111111111111111 1111111111111111 2#10000001000110001 011101101111111
HEX (Hexadecimal) 16#00000000 to 16#FFFFFFFF 16#00A21234
Unsigned Double word (integer) 0 to 4294967295 (4.29 billion) 435
INT (Integer) 16 Signed integer -32768 to 32767 101
DINT (Double integer) 32 Signed double integer -2147483648 to 2147483647 (2.1 billion) 107
REAL (Floating-point number) 32 IEEE 754 Floating-point number (Decimal tal) 1 Lowest value: +/-3.402823E+38
Highest value: +/-1.175495E-38
1.234567e+13
LREAL (Long Real) 64 Dobbelt Float (Decimal tal) IEEE 754 Lowest:-1.7976931348623E308
Highest: 1.79769313486232E308
3432.54
TIME (IEC time) LTime 32
64
IEC time
Step in 1 [ms] or
Step in 1 [ns]
4 T#1ns
to
T#24d20h31m23s
TIME#10s
T#10d14h11m23s
T#5s12ms23us300ns
DATE (IEC date) 16 IEC day,
step 1 day
D#1990-1-1 to
D#2168-12-31
D#1996-3-15
DATE#1996-3-15
TIME_OF_DAY (Time) 32 Time in a step of 1 [ms] 4 TOD#0:0:0.0 to TOD#23:59:59.999 TOD#1:10:3.3 TIME_OF_DAY#1:10:3.3
CHAR WCHAR 8
16
ASCII characters (letter or sign) 2 ‘A’, ‘B’ etc. ‘E’
STRING Text 3 Up to 255 characters ”This is a text”

All variables must have a data type. If a variable is given a value outside the minimum and maximum value range of the data type, a run time error may occur and consequently the PLC may stop the program execution. This may again lead to strange behavior when executing the program (the program may seem unstable).

A few PLC types provide more data types than the ones listed above. In general, it is recommended use only a few data types so that the PLC code can be copied in an easier way to other PLC types. Some special data types such as S7TIME, LWORD and ULINT cannot be used by all PLC types. This means that copying PLC code with special datatypes, or upgrading to a larger PLC, may take a lot of work and risk introducing errors to the code.

The three most used data types are BOOL, INT and REAL. The reason why INT is used more often than WORD is that INT provides the same amount of data as the bit-size in a PLC making it a fast data type. On the other hand, if REAL is used, the PLC will auto-generate underlying machine code as the PLC can only work with integers. The disadvantage of working with INT is when exchanging values between computers where e.g. one computer is a PLC running on a 16-bit operating system, and the second is running on a 64-bit operating system. The second computer could also be a small 8-bit computer (an embedded computer), used inside a sensor, a measuring instrument or equipment for analyzing process values.

Data type table notes
1) A REAL integer contains at most 7 influential digits. This means that if a variable is allocated the value of 1234.56789, the variable is not able to contain all digits. The value will consequently be changed to the value of 1234.567 (7 digits). Some PLC types use 8 digits: 1234.5678.
In some PLC types these data types are named FLOAT.
Because computers may handle a REAL/FLOAT differently, some challenges can occur when communicating between several computers. In order to handle this, a REAL can be changed to an INT or DINT variable by multiplying by 100, and when data is received in another computer the variable has to be divided by 100. Using this method, a decimal number including 2 digits can be transferred without any problems.
2) ASCII characters are typically used when texts are needed to be written on e.g. user interfaces, data logging to files, communication between instruments, data from a keyboard or other PLCs. Due to the fact that a PLC operates with integers only, letters and signs each have a number in an ASCII table.
The data type CHAR has 8 bits (may contain 255 different characters). A CHAR data type may typically be used for 1 to 5 different languages (countries). WCHAR has 16 bits and is applied for Unicode (ISO 10646, Universal Coded Character Set). Unicode is used for international PLC solutions.
WCHAR is typically used when the same PLC-code is applied in several countries with different languages in the user interface.
3) A STRING consists of an ARRAY of CHAR and is normally set to 255 characters (CHARS)
See above-mentioned note 2).
WSTRING is applied for Unicode (ISO 10646, Universal Coded Character Set) and consists of an ARRAY of WCHAR.
Note: Some PLC types provide a maximum of 80 characters in a STRING, if the ARRAY is not limited e.g. 10. It is good practice in programming to limit ARRAY so that unnecessary memory is not used.
4) TIME/DATE is calculated internally in a PLC as an integer, which counts time from 1.1. 1970 at 00.00 and can therefore only be converted to an integer. (See the documentation from the individual PLC-type)
A PLC gets its current time from an in-built electronic component in the PLC hardware. However, its time indication is not very accurate. An accurate time indication must be fetched from an atomic clock, which allows a PLC to be fully automatic straight away if connected to the internet. A PLC can then get its current time from an ordinary PC, e.g. once a day. It is important that all PLCs on the network show the same time so that alarms and stamping with date and hour of logged data indicate the same time (e.g. event log – logging of changes made by the user in the PLC control).

When a variable is assigned a value (set to a value), the value is normally (by default) a decimal number. If the value is a binary number, 2# must be written in front of the number, and if it is a HEX number, 16# must be written in front of the number. E.g. 2#101 = 5 or 16#FF = 255.

When deciding on what data type to use for a variable, it is important to know its maximum value capacity. Normally an INT data type is used for counters. If INT is used as TACHO HOURS on a motor, the maximum value of an INT can be a problem. TACHO HOURS is a counter showing the total number of hours a motor has run, and is used to indicate when the service interval has ended, and motor service is required. If for example the motor runs 20 hours a day, and it has an expected life time of 10 years, the total counter value will be reached as follows:

Hours within 24 hours*days per year*year = 20*365*10 = 73,000 (hours)

The problem is that the variable cannot be contained in the data type INT, as INT has a maximum value of 32767. A double integer DINT must be used instead, or even better a DWORD data type as it is able to contain an even larger number.

DWORD may contain an integer value from 0 to 4.29 billion.

If an INT is used anyway, the variable will show: 7466 as the INT has two ‘overflows. An ‘overflow’ takes place every time the integer is higher than 32767 and at an ‘overflow’, the variable is reset to -32768 (which is the lowest value for INT).

2 User defined data types

It is possible to define more advanced and complex data types to save time when programming, and to obtain a better program structure. The data types are named user defined or derived data types and are declared within TYPE and END_TYPE.

There are three user defined data types: ENUM (Enumerated data type), which is a list of constant numbers. STRUCT (Structured data type) which group different variables in a structure. ARRAY contains a series of variables having same data type.

NOTICE

If an absolute beginner starts programming in a PLC, it is important to know that the derived data types are not necessary to use to make PLC programs work. Only start using derived data types when greater experience in PLC programming is gained.

The different user defined data types are explained in the following chapters.

3 Enumerated data type, ENUM

The enumerated data type ENUM contains a list of unique names. Names are listed in parentheses, and must be meaningful with regard to their purpose. The declaring begins with TYPE and ends with END_TYPE.

Example:

TYPE LightTYPE :

(RED, YELLOW, GREEN);

END_TYPE

The data type LightTYPE in the example above can either be RED, YELLOW or GREEN. LightTYPE could be used to control a traffic light, an operator signal lamp, a light tower (see picture) on a machine or as a status on a valve.

LightTYPE will always take one of the defined types: RED, YELLOW or GREEN.

An ENUM must be allocated a default value. A default value is required to ensure the right value during start-up (initialization). In the example below LightTYPE is initialized with the default value RED when the PLC is powered up:

TYPE LightTYPE :

(RED, YELLOW, GREEN):= RED;

END_TYPE

The PLC-compiler (program which converts the ST program code to the PLC machine code) automatically associate a number to each text in the ENUM. The numbers are indexed starting from 0. This means that: RED = 0, YELLOW = 1 and GREEN = 2. The automatic numbering of the ENUM types is necessary as a CPU can only work in numbers. This also explains the ENUM data type name as ENUM (enumeration) can be translated to ‘automatic numerical order’. This ENUM is used because it is easier for the programmer to remember text instead of a number.

It is possible to define a fixed value for each name instead of automatic:

TYPE LightTYPE :

(RED:= 10, YELLOW:= 20, GREEN:= 30) := RED;

END_TYPE

The disadvantage of using ENUM is that all numbers are positioned in a continuous order (indexed). If new names are added in the middle of the sequence, the index is disrupted which will cause issues when ENUM variables are exchanged between more PLCs or computers, as all devices must be updated with the new PLC code at the same time.

Examples of use: Below are two variables, MotorLamp and Lamp, both having the data type LightTYPE:

Lamp:= MotorLamp; //Here is Lamp set to red
MotorLamp:= LightTYPE.GREEN; //Set MotorLamp to green
Lamp:= MotorLamp; //Here is Lamp set to green

ENUM creates a better structure, but ENUM is not possible in all PLC types.

4 Structured data type, STRUCT

A structured data type, STRUCT, is a composite data type used to group more datatypes in a class/object. The structured data type is declared by using the key words TYPE, STRUCT and END_STRUCT.

Each variable in a STRUCT needs to have a name followed by a colon, and then the data type. Note that the declaring is ended by a semicolon.

Below a STRUCT is shown called Motor, containing four variables which are all related to a motor. Speed (Motor speed), Temperature (measurement inside the motor), Voltage (Power supply for the motor) and AlarmStatus:

TYPE Motor : //Example 1 STRUCT
STRUCT
Speed : INT; //Actual speed of the motor [RPM]
Temperature : REAL; //Temperature inside the motor [C]
Voltage : REAL; //The voltage of the motor [V]
AlarmStatus : BOOL; //Alarm if TRUE else FALSE
END_STRUCT;
END_TYPE

Motor

Note that comments are written after each variable which accurately describe the functionality of the variable to the reader of the PLC program. Furthermore, a unit is written in square brackets because the unit of different variables is often not known. For example, the speed of a motor could be measured in RPM (revolutions per minute), the frequency in Hz (Hertz) or in percentages (0 to 100%).

When the variable is declared, comment lines are also used to describe the behavior of the variable, as this is not always obvious or logical; e.g. the AlarmStatus where it is not clear whether the alarm goes off when the variable is TRUE or FALSE.

Some PLC types do not use text, as in the example above, when declaring a STRUCT; instead they are declared (written) in a list and therefore the key words: TYPE, STRUCT, END_STRUCT or END_TYPE will not appear to the reader.

A structured data type may contain one or more other derived data types. This can be seen in the example below:

TYPE Valve : //Example 2 STRUCT
STRUCT
DisplayColor : LightTYPE; //User defined TYPE
ValveState : BOOL; //Can be TRUE (open)
//or FALSE (closed)
Pressure : REAL; //Pressure in [Bar]
END_STRUCT;
END_TYPE

Ventil

In example 2 above the data type Valve consists of tree variables:

DisplayColor, ValveState (status of the valve: open or closed) and Pressure. The variables Pressure and ValveState use the standard data types REAL and BOOL, while the variable DisplayColor uses the data type LightTYPE.

Example of a portable tank containing chemicals (IBC tank):

TYPE TankType : //Example 3 STRUCT
STRUCT
Liters : REAL := 1000; //Default tank size
LevelSensor : REAL; //Sensor at bottom
LevelSwitch : BOOL; //Float switch at bottom
END_STRUCT;
END_TYPE

Many variables in a PLC program can easily become confusing. Variables belonging to the same component (object), the same domain, or the same mode of operation may advantageously be grouped in a STRUCT. Grouping variables makes it easier and quicker to set up and maintain many identical components. This method of programming is called Object Oriented Programming (OOP), and is often used when writing computer programs.

If a variable with the data type STRUCT is to be transferred to a function the variable scope must be set to VAR_IN_OUT within the function.

5 Collection of values with same data type, ARRAY

An ARRAY is a structure, which can store a collection of values with the same data type. The values are located side by side in memory which means that it is simple to work on. An ARRAY always has a fixed length which cannot be changed during the execution of the program. An ARRAY can be set up and indexed by several dimensions.

You can write ARRAY programming code quickly, and it provides a good programming structure. The challenge is getting the values in and out of the ARRAY.

An ARRAY is also called a multi elementary data type.

Below example show an ARRAY, SpeedArray, which contains 6 positions of the data type INT. To declare the 6 positions, use ARRAY followed by square brackets including start end position number, separated by two dots as shown below:

VAR SpeedArray :

ARRAY [1 .. 6] OF INT;

END_VAR

The first value in the array is located in position no. 1 and the last in position no. 6. The name for the ARRAY in this example is Speed, which is added to the text Array, so that any person working on the PLC code will easily know that an ARRAY is used.

SpeedArray is a one-dimensional ARRAY and can be used where a collection of many values with same data type is positioned in one long row. Examples include:

An ARRAY can be used with all data types, including STRING, STRUCT or functions.

A two-dimensional ARRAY can be used on e.g. a parking lot (car park), stock rack, a graph, a bar chart or a pivot table and can be set up as follows:

VAR Racking

ARRAY [1 .. 5, 1 .. 3] OF INT;

END_VAR

A three-dimensional ARRAY is defined as follows:

VAR PackOnPallet

ARRAY [1 .. 5, 1 .. 4, 1 .. 3] OF REAL;

END_VAR

Used e.g. for packages on a pallet (palletizing) or positions in a warehouse.

If you look at a three-dimensional ARRAY as an X, Y and Z system of coordinates, the values from the above-mentioned example can be grouped as follows:

X = 1 til 5, Y = 1 til 4, Z = 1 til 3.

The total amount of positions in PackOnPallet ARRAY is: 5*4*3 = 60 pieces. So this ARRAY contains 60 positions (elements).

An ARRAY can be defined with an index starting point of 0. The ARRAY below contains 4 positions as position 0 (zero) and position 3 are included when counting the number of positions in the array. It results in a more stable program when arrays start from 0, because the array index pointer remain uninitialized (not given an start value):

VAR MyArray1D

ARRAY [0 .. 3] OF INT;

END_VAR

Insert a single value in an ARRAY

In the below example the value 5 is inserted at position 4 in the one-dimensional ARRAY SpeedArray:

SpeedArray [4] := 5;

Values can be inserted in the three-dimensional ARRAY PackOnPallet as follows:

PackOnPallet [1, 1, 1] := 12.1;

PackOnPallet [5, 1, 3] := 43.9;

PackOnPallet [1, 4, 2] := 23.5;

For inserting multiple values in a 3D ARRAY.

Get a value from an array

In this example shows how to get a value from a one-dimensional ARRAY. The value is located at position 2 in the array MyArray1D and copied to the variable Var1:

Var1 := MyArray1D [2];

//Contents of Var1 is 12

Get a value from a three-dimensional ARRAY is carried out as follows:

A value is transferred (copied) to the variable Var3 with the value of 43.9:

Var3 := PackOnPallet [5, 1, 3];

//Contents of Var3 is 43.9

IMPORTANT: You must not assign (copy) a value to positions outside of the ARRAY. If assigning a value to for example, position no. 10 in an ARRAY containing only 6 positions, the PLC can stop the program execution (Run Time Error). This is a common error/mistake when using arrays for your code. To avoid assigning values to positions outside the ARRAY use an IF statement as shown below:

Index:= 4; //Insert 5 at position 4

IF Index > 0 AND Index <= 6 THEN

SpeedArray [Index] := 5;

END_IF;

In the previous example, the low bound and upper bound of the array are used directly. This can be a disadvantage when the array is used inside a function or the lower and upper bounds have to be changed. Therefore, the built-in standard functions LOWER_BOUND and UPPER_BOUND can be used.

The two functions return the bound of the array and can be used as shown below:

Index:= 4; //Insert 5 at position 4

IF Index >= LOWER_BOUND (SpeedArray, 1)

AND Index <= UPPER_BOUND(SpeedArray, 1) THEN SpeedArray[Index]:= 5;

END_IF;

Direct and indirect addressing

For direct addressing in an array, numbers are used to retrieve the content at a particular location in an array and for indirect addressing, a variable is used:

//Indirect addressing is using a variable

Index:= 4; //Index is an INT or a WORD data type

SpeedArray[Index]:= 5;

//Direct addressing when a number is used directly

SpeedArray[4]:= 5;

Data collection

An array is perfect for collecting data (data log) in a PLC controller. This code collects the number of items produced from a machine:

The array is configured as shown:

VAR

DataCollect ARRAY [7 .. 16] OF WORD;

END_VAR

The array saves data from a range from 7 to 16 which corresponds to the period during which the machine produces items. From 7 o’clock to 8 o’clock the machine produces 15 items, between 8 o’clock and 9 o’clock the machine produces 29 items, etc.

By collecting the number of items produced, it is easy to find out the periods in which the machine has produced the most and the fewest items. The data collected confirms how efficient the production is during different time periodes.

An element in an array can only save one value. This example shows how an array can contain multiple values, and how constant values are saved in an array.

The example is a warehouse rack, controlled by a robot:

1 Starting point (homing position)
2 Distance, X-axis for each row
3 Distance, Y-axis for each shelf
4 Pallet with 1 box in location 3,1
5 Pallet with 2 boxes in location 2,2
6 Pallet with 4 boxes in location 4,3

Numbers at X-axis (2) and Y-axis (3) are predefined numbers to inform the robot how far to go (distance) to place an item on a certain row and shelf in the warehouse rack. Each axis uses an encoder to determine where a location is. An encoder is a sensor that sends a pulse for distance traveled, and when the correct number of pulses is received, the robot stops at the correct location.

Each location in the warehouse rack contains several values and therefore a STRUCT is created as shown to the right:

To add more values, add additional code lines under the Weight variable.

TYPE LocationTYPE

STRUCT

NoOfBox : WORD;

Weight : REAL;

END_STRUCT

END_TYPE

To handle the warehouse rack, the following variables are created:

VAR CONSTANT

StockSizeX: INT := 4; //Size x of the Stock

StockSizeY: INT := 3; //Size y of the Stock

StockEncodeX: ARRAY[1.. StockSizeX] OF INT := [235, 370, 505, 640]; //Encoder X values

StockEncodeY: ARRAY[1.. StockSizeY] OF INT := [0, 213, 355]; //Encoder Y values

END_VAR

VAR

Stock: ARRAY[1.. StockSizeX, 1.. StockSizeY] OF LocationTYPE; //Location is a STRUCT

END_VAR

Inserting values for the pallet located at (6) is done like this:

Stock[4, 3].NoOfBox := 4; //Located at StockEncodeX[4] and StockEncodeY[3]

Stock[4, 3].Weight := 1210.25; //Set weight

This example is based on a depalletizer:

A conveyor belt can have different states

and these are grouped in an ENUM:

TYPE ConveyorState :

( NONE, STOP,

RUN_CW, // Run clock wise

RUN_CCW, // Run counter clock wise

ALARM) := STOP; // Default set to stop mode

END_TYPE

By default the state is set to STOP to avoid the conveyor belt running unintentionally when the PLC is powered up.

The variables for a conveyor belt are grouped into a STRUCT:

TYPE ConveyorTYPE :

STRUCT

State : ConveyorState; //State/mode
Speed_m_s : REAL; //Conveyor speed in [m/s]
Size : INT; //Conveyor size, 40 or 60

END_STRUCT

END_TYPE

Declaration of the conveyor belt variables and code examples are shown below:

VAR
M1 : ConveyorTYPE; //Single conveyor
ConveyALL : ARRAY [4..6] OF ConveyorTYPE; //All conveyor
END_VAR

//Start M1 single conveyor

M1.State:= ConveyorState.RUN_CW;

//Set size of conveyor 5

ConveyALL[5].Size:= 40;

//Start conveyor 5

ConveyALL[5].State:= ConveyorState.RUN_CW;

//Copy all variables from conveyor 5 to conveyer 6.

ConveyALL[6]:= ConveyALL[5]; // Conveyor 6 is a copy of conveyor 5

Leave a Comment