Part 4 - Data types and arrays (IEC 61131-3)

Video

#PLC #TwinCAT3 #Beckhoff #IEC_61131-3

🔙 Previous Part | Next Part 🔜

↩️ Go Back

Table of Contents:


A) Objectives

In this part we will dive deeper into the various data types that are available in the IEC 61131-3 standard that TwinCAT implements.

We'll also look at pointers and references, and why we would want to use them.
450

Then we will end this part by a quick look at how to declare and use arrays.

Generally talking about data types isn't too exciting, it's just one of those things you have to learn. I'll try to make this topic at least a little bit fun.


B) Variables

Let's start with asking what a variable is...

Variables are used to store information to be referenced and manipulated in a computer program. They provide a way of labeling data with a descriptive name, so our programs can be understood more clearly by the developer.

Think of variables as containers that hold information. Their sole purpose is to label and store data in memory. This data can then be used throughout your program.

When creating a variable you need to define what data type it should have. TwinCAT 3 follows the standard of IEC 61131-3 of which data types are available.

In TwinCAT 3, all variables are declared between the keywoards VAR and END_VAR.

In this example, we only have one variable declared, and the name of the variable is fCabinetTemperature and it's of type REAL which is a floating point value.

Note: Giving good names to variables is a task that should not be underestimated. For TwinCAT 3 s/w there are some naming conventions available. I've written a little about these on my TwinCAT blog.

If you've done any programming in languages such as JavaScript or Python, you've been using a language that is [[Dynamically-typed]].

Structured text and IEC 61131-3 is [[Statically-typed]].

The difference is that,

First:

Secondly:

So, which data types do we have in the PLC world? I'll show you the most common types in the IEC standard. For every type I will present the value range, that is, which values that type can have the total memory consumption for one instance of the variable and just a simple example.


B.1) Bool data types

We will start with booleans.

  1. A bool can only hold the value FALSE or TRUE and uses 1 byte of memory in the PLC

You declare a variable by giving it:

  1. a name, followed by a colon and the data type
  2. In the declaration the variable can optionally be assigned a value
    Note: If a value is not assigned in the declaration, the variable will get a default value, which for booleans is the value FALSE.

B.2) Integer data types

In TwinCAT 3 we have a wide range of integral data types.

  1. The most basic one is INT, which is signed and thus is capable of representing both positive and negative integers. It requires 2 bytes in the PLC

  2. Next we have UINT, which occupies the same amount of memory as the signed INT, but because it is unsigned you can have twice as many positive integers

  3. Next we have the short signed integer, which only occupies 1 byte compared to the signed integer

  4. Then we have the unsigned version, that is the unsigned short integer, occupying the same amount of memory but only allowing positive integers

Now we're going to start to look into types that use a little more memory

  1. Next we have the signed double INT (DINT), which use double the amount of memory compared to the standard signed integer, that is 4 bytes

  2. The DINT also has an unsigned version, in other words an unsigned double integer

  3. There is also a 64 bit, that is an 8 bytes version called signed long integer. This occupies double the amount of memory as a signed double integer

  4. And just as with the other integer types, there is an unsigned version of this as well.

Next we have some more integer type data types.

  1. BYTE can store the values between 0 and 255 and just as a short integer only consumes 1 byte of the memory

Neat feature #1:
I want to point out a neat feature with PLC programming here and that is that it's possible to define the base of the integer by writing the base number (2) a hashtag (#) and then the value in that base format(10011_0011).

So for example,
if we enter a base of 2, which is binary, and then write a value of 1011_0011, this means it is a value of 179 in base 10. If we don't explicitly declare the base, it will implicitly be declared with base 10

Why is it useful?
It's such a good feature, especially when you integrate your system with other systems and you need to exchange data and you have some documentation for that subsystem in where they are documenting everything in hexadecimal for example

  1. Next we have the WORD data type, which is twice as big as a BYTE (here the example is in hexadecimal format or base 16)

  2. Next we have a double WORD, which not very surprisingly is twice as big as a WORD.

  3. Finally we have the huge 8 bytes LWORD.

Neat feature #2:
One really useful feature of structured text is that I can do bit-accessing on variables, that is I can access individual bits of a variable.

This is achieved by writing the variables name, a "dot" and which bit I want to access. The bit-addressing starts with 0, and in the example of the BYTE, which is 8 bits big, it goes from 0 to 7. If I write the variable name, in this case nSomeVariable and then "dot" 3. I'm accessing the fourth bit from the right. I can store the value of the bit access in a separate variable of either type BIT or BOOL


B.3) Floating point data types

The floating point data types are used to represent floating values.

There are only two variants,

The equivalent to REAL and LREAL in the C++ world are the FLOAT and DOUBLE data types respectively.


B.4) String data types

With strings you can store textual data.

  1. If you declare a variable with the type STRING it will occupy 80 bytes of data, one byte for each character plus 1 byte for null terminating the string.

This means you can store up to 80 characters in this String. Even though we can declare STRINGs basically as big as we want, most built-in functions of TwinCAT 3 to process strings have a limit of 255 characters.

In here I just demonstrate how to declare a string with another size than 80, in this case a STRING that can have 300 characters

STRINGs are ASCII-coded, so each byte in a STRING is according to the ASCII-character table

  1. Next we have WSTRING, short for Wide STRING.

The WSTRING is using the UNICODE character set and UTF-16 encoding The difference between ASCII and UNICODE is basically that UNICODE has a much wider selection of characters to represent.

So for example, in Sweden we have the characters Å, Ä and Ö which are not available in the ASCII-table but they are available in the UNICODE character set.

In UNICODE, depending on which character we want to encode, the memory consumption for every character can vary. Every character can be either 1 or 2 words, that is 2 or 4 bytes. This means that the amount of characters we can store in a WSTRING is dependent on which characters we store in it. If you just declare a variable as a WSTRING, it's size is set to 80 (+1) WORDs, in other words 160 + 2 bytes

Note that the quotation marks for assigning the variable a value differ between a STRING and WSTRING.

Just as with STRINGs, you can define the size of the variable yourself. In this case, we have declared a WSTRING with the size of 300 + 1 WORD, that is 600 + 2 bytes.

This means that we can store up to 300 characters in this WSTRING

WSTRINGs is usually used at the front-end, in other word an HMI and not in the PLC business logic code


B.5) Time data types

Next we have data types available for declaring dates and times. These are very useful and quite easy to use.

  1. First we have TIME, where you can specify a time. It's a 4 byte data value, and the resolution of the time is 1ms.

When setting a value to a time variable, you can specify the time using:
days, hours, minutes, seconds and milliseconds

Note that you have to use the characters T-hash (T#) when assigning a TIME value.

  1. Next we have the TIME OF DAY data type, which uses 4 bytes of memory and has 1ms resolution. As the name implies, it's used when you need to define the time of day for something.

It's defined using:
hours, minutes, seconds and milliseconds

Note that you have to write a TOD-HASH (TOD#), short for time of day, before the actual value

  1. Next we have the DATE data type, which occupies 4 bytes of memory and has a resolution of 1 second (although only the day is presented)

It's defined using:
year, month, day

Note that you have to write a D-HASH (D#), short for DATE, before the actual value

  1. Next we have the DATE_AND_TIME data type, which is a combination of the TIME data type and the DATE data type, so you can present both date and time. It still only occupies 4 bytes of memory, with 1 second resolution

You have to write a DT-HASH (DT#), short for DATE and TIME, before the actual value

  1. Finally we have our first 8 byte data type, the LTIME which is short for long TIME.

It's a higher resolution version of TIME, where it's not only possible to specify DAYS, HOURS, MINUTES and MILLISECONDS as in TIME, but also MICROSECONDS and NANOSECONDS. The resolution of the data type is 1NS.

In very high speed tasks, that is sub-ms tasks which are easily achievable with Beckhoff PLCs and TwinCAT3, this data type comes in handy.

You have to write LTIME-HASH (LTIME#) before the value.


B.6) Enums

|150

B.6.1) What are Enums?

An enumeration is a user-defined type that consists of a set of named integral constants that are known as enumerators.
|150

With enumerations it's possible to basically put some description to the data, without having to put comments in the code.

An enumeration consists of:

  1. an [[identifier]], which you use when you instantiate the enumeration
    |150

  2. Next, we have an [[enumeration list]], in where you define the different values that the enumeration can have.
    |300

An enumeration has by default a base type of INT, that is the 2 byte integer. By default and implicitly, the first value is assigned the integer value of 0, and then next one is 1 etc. You can assign other values explicitly
|150

  1. Next we have the [[optional type]]. If this is not provided, the enumeration will implicitly have a base type of INTEGER.
    |300

You declare a enumeration variable by defining a name for it, just as with any other variable, colon and then the enumeration identifier. Then you can assign any of the enumeration values to the variable by using the enumeration identifier DOT and the enumeration value.

Thanks to IntelliSense in Visual Studio, if you enter the identifier, you get all the different enumeration options visible

All enumeration types are globally accessible, which is in contrast to for example C++ where you can define an enumeration to be only accessible in the scope of where it was declared.

So, once you create an enumeration, the enumeration type is accessible from everywhere in your program.

Although this has its advantages, it can also be disadvantageous especially when you start to work with libraries.

When you have lots of enumerations available, you can get something called [[namespace pollution]] in where two enumerations in two separate libraries but with the same name are used in a project.

Many of you ask the question:

"But why not use comments next to the integer or whatever data type I'm using instead?"

-- Code should be self-explanatory. With comments you just add something else that needs to be maintained and that most likely will be wrong after the code has been changed.


B.6.2) How to create Enums?

To create an enumeration, right click on DUTs, select Add, then click on DUT.
|500

This will bring up a new window, in where you can define new DUTs, that is Data Unit Types.
|250

Write the name, that is the identifier in the NAME textbox. Make sure ENUMERATION radio box is selected. Click "Open"

Your enumeration is created. Now you can fill in the enumeration list

Conclusion:
There are a few other data types available in the IEC standard and TwinCAT 3, but these are the most common ones. This link is Beckhoff's documentation for all data types available, if you want to read more.

In TwinCAT3, and in PLCs in general, all type declaration is done at [[compile time]]. You have to declare the data types of your variables before you use them, and the type cannot be changed during the execution of the program. Implicitly trying to convert from one type to another will generally result in a compiler warning or error.

In PLCs you generally allocate memory upfront. [[Dynamic memory allocation]], the way it can be done in for example C++ can be done in TwinCAT, although it is generally not used.


C) TUTORIAL 2 - Using the SIZEOF() Operator

OK what I'm going to show you now is the operator SIZEOF(). And what this operator is used for is to determine the required size in bytes for a specific variable.

Note: the SIZEOF() operator is very useful when you work with buffers.

Example #1:
So if we create a few variables here,
|300

Then we can use the operator SIZEOF() that gives us the size in bytes for a specific variable.
The SIZEOF() operator always returns an unsigned value. The type of the return variable adapts to the detected size of variable x.

We can just create a some return variables as unsigned double integers UDINT (which are quite big).
|500

And run the program,

And as you see,

Copy the PLC Code:

PROGRAM MAIN
VAR
	fOneFloat : REAL;
	sThisIsAString : STRING;
	nAnInteger : INT;

	nReturnedNumberOfBytesForFloat : UDINT;
	nReturnedNumberOfBytesForString : UDINT;
	nReturnedNumberOfBytesForInteger : UDINT;
	
END_VAR

------------------------------------------------------------------------

nReturnedNumberOfBytesForFloat := SIZEOF(fOneFloat);
nReturnedNumberOfBytesForString := SIZEOF(sThisIsAString);
nReturnedNumberOfBytesForInteger := SIZEOF(nAnInteger);

Our next subject is pointers.


D) TUTORIAL 3 - Pointers

Pointers are symbolic representation of addresses. They are a symbolic representation for an address in the memory of the PLC so that you can access a location of the computers memory by a name.

The pointer is a variable in itself, it holds the address of the memory location of the variable it is pointing to. Thus in a 64-bit system, a pointer uses 64 bits of memory, in other words 8 bytes.

What we have in this example is a pointer to an integer. If we write it like this, this pointer doesn't point to anything. If we would look at the value of the pointer now, it would just be the address zero.

REMEMBER: the pointer doesn't hold an integer but an ADDRESS to a memory location

If we want to change the value of the variable that the pointer is pointing to, you have dereference it, by applying the content operator to the pointer identifier.

Now we have updated the actual value of the memory location from the initial 20 to 30

Copy the PLC Code:

PROGRAM MAIN
VAR
	// Create a Variable
	nVariable : INT := 20;
	// Create a Pointer and get the address of the Variable
	pPointer : POINTER TO INT := ADR(nVariable);		
END_VAR

//Dereference and change the content of Variable
pPointer^ := 30;

Then we assign the address of the date and time variable to the string-pointer.
|400

Notice that the compiler doesn't complain when we assign the address of a date and time variable, to a pointer that is supposed to point to a STRING.

That is one of the problems with pointers. A pointer is just an address to a memory location in the PLC. Pointers can become quite dangerous. In this trivial example we are intentionally pointing to another datatype than expected but when you are in the domain of using pointers, this is exactly what happens unintentionally.

If we dereference the string-pointer we will just get these garbage characters instead

Although pointers can be very powerful, there are other more safe ways to reference data that I'd recommend using instead and that's what we are going to look at now


E) TUTORIAL 4 - References

Let's now look at REFERENCES.


E.1) References: How to use them?

While a pointer is just a variable with an address, a reference is the object, just with another name, so see it as an "alias".

In this example we have a reference to an integer, and it's assigned the value nVariableInteger.

When assigning a new value to the reference you don't need to use any dereferencing like with pointers. You just use the variable just like if you would use the normal variable, so again, just see it as an alias for the variable it is a reference for.

Copy the PLC Code:

PROGRAM MAIN
VAR
	// Create a Variable
	nVariableInteger : INT := 20;
	// Create a Reference and the value 
	nReference : REFERENCE TO INT REF= nVariableInteger;		
END_VAR

//Change the content of nVariableInteger
nReference := 30;

REMEMBER: When declaring a reference, you CAN'T assign a reference of a type to a variable of another type.

In this example, we have a DATE_AND_TIME variable and an integer variable.

If I declare a REFERENCE TO AN INTEGER, and try to assign this reference a variable with a type of DATE_AND_TIME the compiler complains and we won't be able to compile our software.

So these are the main advantages of using a reference compared to a pointer:

  1. Easier to use: You don't need to assign an address of a variable, but you assign the reference directly to the variable you are referencing. When using the reference, you don't need to do any weird de-referencing but can use the reference directly just as if it was the variable.
  2. It is more type safe: A reference of one type can't be a reference to a variable of another type as we just saw. We get this check directly at compile time.

E.2) References: C++ vs Structured Text

Though I'm mostly using references whenever I can, I have noticed differences compared to C++ for example.

If we look at the C++ standard, it's very specific and says that:
"A reference shall be initialized to refer to a valid object or function"

With this simple code example, I've tried to create a reference to an int, that doesn't reference anything. In this case, the C++ compiler will complain and say "references must be initialized". It won't compile.

In IEC61131-3 it seems much more relaxed, as it's entirely possible to create a reference that doesn't reference anything.
|280

There is an operator available called __ ISVALIDREF(), in where it's possible to check whether the reference is valid. That is, if it's other than zero, but this is executed during run-time so it defeats parts of the purpose of references.

If you would run this code, you would get an exception and the PLC would crash.

Note: The reference still has the mentioned advantages over pointers and should be preferred.


E.3) References: using the SIZEOF() operator

You can do a SIZEOF() on the reference, and get the size of the referenced object.

So here we have an integer, that is 2 bytes, and the SIZEOF() the reference is 2.

If you would do a SIZEOF() on a pointer, you would get the size of the pointer, not the SIZEOF the object the pointer is pointing to.

So in this example we have an integer, and a pointer to an integer. And the size isn't the size of the integer, but the size of the pointer. So again if we have a 64-bit system then the size of the pointer is 8 bytes.


E.4) When should I use Pointers and when should I use References?

Just as in modern C++ you should try to avoid pointers.

For instance, in C++ I could find myself avoiding usage of pointers in some occasions by using [[method overloads]], if I needed to perform some data manipulation on different types of data.

In the IEC standard for PLCs, we don't have [[method overloads]]. You can't create a function or method that has the same name but different input parameters.

Also, in TwinCAT we don't have anything equivalent to the C++ standard library's [[smart pointers]] like [[shared or unique pointer]], so you really need to be careful when using pointers.

For all you new PLC or non-C++ developers we are going to get back to functions in the next part of this tutorial so don't worry, we will get back to this topic soon again.

Just showing you pointers and references like this doesn't really clearly show why you would want to use them, but this will be more obvious once we start to shuffle larger amounts of data between the different code functions that we are going to develop.

Which lead us to the question...

We are going to get to this topic when we start to look at functions and methods.

For now you only need to know that it's for example, done when you create a function or method and you want to use some data in that function that comes from the outside of the function, and the data is big.

So we mean, not just a single integer or a REAL, but when we have for example large arrays and we want to avoid data copying from the "outside" of the function to the inside. That is, we want pass data by reference and not by value.

We will get back to the concept of passing by value and passing by reference in future parts of this tutorial.

In these simple examples when we are just using a pointer or reference to an integer it of course doesn't make much sense. It makes more sense when the data we are referencing and we want to avoid data copying.

So if I'm going to use pointers or references,

I hate to give general advice as there are always the exceptions to the rules and people are always going to mention the exceptions. But everyone (including myself) love general rules so I will give you one.

The general rule is, use references when you can, and pointers when you have to.


F) TUTORIAL 5 - Arrays

Now we will briefly touch on the topic of arrays.
|350
Read more here (Arrays are value types!)


F.1) How to declare an Array

An array is a series of elements of the same type placed in contiguous memory locations that can be individually referenced by adding an index to a unique identifier

You declare an array in this way, we have created an array that stores 5 integers.

In this example we can see that all values in the array are initialized with 0 just as any other integer if we haven't assigned a value to it.

We can initialize the array with other values in the declaration.

You can assign a new value to any element in the array by simply writing the name of the array brackets, the position of the element in the array and then the value it should have instead.

So here we have replaced the value 20 in the position 2 in the array to the value 133.

Compared to most other programming languages, an array in IEC 61131-3 can be declared to start and end at basically any position.

In the first example we had an array starting at position 1 and ending at position 5.
|500

We can start at position 0 as well, which is more traditional.
|300

We might also start at -1 and end at 1, so this array has three values.
|300


F.2) How to declare an Multi-Dimensional Arrays

Arrays don't have to be one dimensional, you can create multi-dimensional arrays. In this example we have a 2 dimensional array, and declared in two different ways.

Accessing the arrays is done slightly different depending on how you declare them.

For example look how we access the value in the first row and first column using alternative # 1,

compared to alternative # 2

Compared to for example C++ the declaration for 2D arrays doesn't look the same for neither of these two alternatives

but ACCESSING the array is similar in alternative # 2 to C++

Also note that the online view with the TwinCAT IDE looks slightly different depending on how you have declared your 2 dimensional array.


F.3) Example - Working with Arrays

In this example we have declared an array with five elements, and in the declaration set five values.
We have also declared an integer with the name nOneInt.
|500

We will just do some simple calculations on the array and store the result in the integer.

First we change the value of the first element, so the value 10 is changed to 42
|500

Next we assign the variable nOneInt the values of the first position in the array plus the value of the fourth position in the array. This will add the values of the two positions in the array, and store it in the integer nOneInt.
|500

Copy the PLC Code:

PROGRAM MAIN
VAR
	// Create an Array
	aOneArray : ARRAY[1..5] OF INT := [10,20,30,40,50];
	// Create OneInt 
	nOneInt : INT;		
END_VAR

-----------------------------------------------------------------------

//Change the value of the first element
aOneArray[1] := 42;

//Access the elements of the array and add them
nOneInt := aOneArray[1] + aoNEaRRAY[4]


G) TUTORIAL 6 - Type Conversion

The final topic for this part of the tutorial is type conversion.

There are type conversions from basically every primitive type in TwinCAT.

Every data type has type conversion operators, and they behave slightly different depending from which and to which data type you want to convert.

The behavior is obviously different if you want to convert from one type of integer to another type of integer, compared to converting from an integer to string for example.

I will demonstrate with one example,

Let's assume we have declared two integers:

The USINT is 1 byte with an upper bound of 255,
|250

and the UINT is 2 bytes with an upper bound of 65535
|250

Lets now assume we assigned the UINT, that is the 2 bytes integer, the value of the USINT (that is the 1 byte integer) plus 5.
|300

The compiler would have no problem with this simply because the UINT is bigger than the USINT and can easily fit the value of USINT plus 5.

If we would do it the other way around, we would get a compile error stating that we cannot convert the type UINT to the type USINT simply because the UINT is bigger than USINT and we can't fit the data in the UINT inside the USINT
|500

What we need to do is to do a type conversion using UINT_TO_USINT of the UINT
|500

that is we need to convert the value of the bigger data type to a value that can fit inside the smaller data type.

But, how does this work?

Let's assume the UINT has a value of 259, which is bigger than what we can fit inside the USINT which is 255.
|500

If we represent the decimal value of 259 as a binary, this is what we will get.

Two bytes, each carrying eight bits.

What the type conversion will do is simply remove the left byte, and leave only the right byte
|500

Because one byte is removed in the conversion, we are left with one byte which can fit inside an USINT

The right byte's value is 3 in base-10,
|500

and we take that plus the five from before, which will give us the result 8.
|500

A value of 8 can be stored in an USINT.

Copy the PLC Code:

PROGRAM MAIN
VAR
	// USINT is 1 byte
	nOne_Usint : USINT;

	// UINT is 2 bytes
	nOne_Uint : UINT := 259;	
END_VAR

-----------------------------------------------------------------------

//Ok, USINT is smaller than UINT
nOne_Uint := nOne_Usint + 5

//Convesion needed, UINT loses its left byte to fit USINT
nOne_Usint := UINT_TO_USINT(nOne_Uint) + 5

Now we have learned how to allocate memory in our PLC and in the next part we will look into how we can organize data into structures and actually make something useful with that data using functions. I'll see you in the next part!


H) Summary (copy code)

H.1) Elementary data types

The most common Elementary data types in the IEC standard are:

bJustAVariable : BOOL := TRUE;
nThisIsANumber : INT := -4232;
fPi : REAL := 3.14159265359;
sHelloWorldString : STRING := 'Hello World!';
dtVariable : DATE_AND_TIME := DT#2013-04-18-15:31:19;

Keyword Description Range
BOOL Boolean value 0 or 1
SINT Short integer -128 to +127
USINT Unsigned short integer 0 to 255
BYTE Single byte bitmask 16#00 to 16#FF
INT Integer -32768 to +32767
UINT Unsigned integer 0 to 65535
WORD Two byte bitmask 16#0000 to 16#FFFF
DINT Double integer -2147483648 to +2147483647
UDINT Unsigned double integer 0 to 4294967295
DWORD Four byte bitmask 16#00000000 to 16#FFFFFFFF
LINT Long integer -9223372036854775808 to +9223372036854775807
ULINT Unsigned long integer 0 to 18446744073709551615
LWORD Eight byte bitmask 16#0000000000000000 to 16#FFFFFFFFFFFFFFFF
REAL Single precision floating point x
LREAL Double precision floating point x
TIME Interval value x
DATE Date value 1601-01-01 to 9999-12-31
TIME_OF_DAY or TOD Time of day 00:00:00.000 to 23:59:59.999
DATE_AND_TIME or DT Date and time value 1601-01-01-00:00:00.000 to 9999-12-31-23:59:59.999
CHAR Single byte character $00 to $FF
WCHAR Double byte character $0000 to $FFFF
STRING Variable length single byte character string x
WSTRING Variable length double byte character string x

H.2) User-defined data types

The most common User-defined data types in the IEC standard are:

TYPE E_Color :
(
	Red := 0,
	Green := 1,
	Blue := 2,
) USINT;
END_TYPE
PROGRAM MAIN
VAR
	eLightTower : E_Color;	
END_VAR

--------------------------------------------------------------------------

eLightTower := E_Color.Red;

PROGRAM MAIN
VAR
	// Create a Variable
	nVariable : INT := 20;
	// Create a Pointer and get the address of the Variable
	pPointer : POINTER TO INT := ADR(nVariable);		
END_VAR

//Dereference and change the content of Variable
pPointer^ := 30;

PROGRAM MAIN
VAR
	// Create a Variable
	nVariableInteger : INT := 20;
	// Create a Reference and the value 
	nReference : REFERENCE TO INT REF= nVariableInteger;		
END_VAR

//Change the content of nVariableInteger
nReference := 30;

PROGRAM MAIN
VAR
	// Create an Array
	aOneArray : ARRAY[1..5] OF INT := [10,20,30,40,50];
	// Create OneInt 
	nOneInt : INT;		
END_VAR

-----------------------------------------------------------------------

//Change the value of the first element
aOneArray[1] := 42;

//Access the elements of the array and add them
nOneInt := aOneArray[1] + aoNEaRRAY[4]


H.3) Tutorial (Operators):

PROGRAM MAIN
VAR
	fOneFloat : REAL;
	sThisIsAString : STRING;
	nAnInteger : INT;

	nReturnedNumberOfBytesForFloat : UDINT;
	nReturnedNumberOfBytesForString : UDINT;
	nReturnedNumberOfBytesForInteger : UDINT;
	
END_VAR

------------------------------------------------------------------------

nReturnedNumberOfBytesForFloat := SIZEOF(fOneFloat);
nReturnedNumberOfBytesForString := SIZEOF(sThisIsAString);
nReturnedNumberOfBytesForInteger := SIZEOF(nAnInteger);

PROGRAM MAIN
VAR
	// USINT is 1 byte
	nOne_Usint : USINT;

	// UINT is 2 bytes
	nOne_Uint : UINT := 259;	
END_VAR

-----------------------------------------------------------------------

//Ok, USINT is smaller than UINT
nOne_Uint := nOne_Usint + 5

//Convesion needed, UINT loses its left byte to fit USINT
nOne_Usint := UINT_TO_USINT(nOne_Uint) + 5


🔙 Previous Part | Next Part 🔜

↩️ Go Back


Z) Glossary

File Definition