Part 5 - Structures and functions (IEC 61131-3)
Video
#PLC #TwinCAT3 #Beckhoff #IEC_61131-3
Table of Contents:
- A) Objectives
- B) TUTORIAL 7 - Structures
- C) TUTORIAL 8 - Functions
- D) TUTORIAL 9 - Structure & Function Application ("UpdateEventTimestampWithSystemTime" - fill the DATE_AND_TIME value of the Structure with the current system time of the PLC) //FILE -->TimeProject (part1)
- E) Summary
- E.1) Example 1 - Making an Celsius to Fahrenheit function
- E.2) Example 2 - Making a comparison function with multiple outputs (Greater/Smaller than function)
- E.3) Example 3 - Swap Numbers function (read and write to the same variable)
- E.4) Useful Function - "UpdateEventTimestampWithSystemTime" - fill the DATE_AND_TIME value of the Structure with the current system time of the PLC
- Z) Glossary
A) Objectives
In the previous part we, amongst many other things, looked at arrays. Arrays allow us to define types of variables that can hold several data items of the same kind.
In this part of the tutorial we will look at a data unit type that allows us to hold several data items of DIFFERENT kind. The Structure.
We will also look at one of the basis of modularization and re-use in software development called functions.
We will look at how we can get data in and out of functions and we will also look at the difference between passing parameters by value and by reference.
We will finish this part by writing our very first function.
B) TUTORIAL 7 - Structures
First, let's look at a neat way to organize data.
B.1) Example - Making an Alarm and Event System
Suppose you wanted to implement an alarm and event system in your PLC software, so that you can trigger warnings, errors, information or status messages.
To keep track of these alarms and messages, you would need to have a data definition of such a message.
One single event could for example have the following data:
1. The event type:
For example:
- Alarm
- Message
2. Event severity:
so in the case of an alarm, examples could be:
- Verbose
- Info
- Warning
- Error
- Critical
3. Event identity:
For example:
- 3211
4. Event text:
For example:
- 'Pressure loss in pneumatic cylinder'
5. And a timestamp:
Now assume we want to keep track of what has happened in our system over time. This would mean that we would need to store several instances of events. One way of implementing this would be to store this data in arrays.
We could create several arrays, each and one holding every piece of information and every array being indexed from 1 to the amount that we want to be able to store, for example 100.
This is not very user-friendly though.
Although data might be declared this way, it might not be obvious that the data elements are related to each other.
Just imagine if this data would be used at several places in the software. Then this definition would have to be updated on every single place in the software to be consistent.
We also have 5 separate arrays to iterate over when we want to use the complete data for an event.
Just as we can have arrays to hold data items of the same kind, we can use something called structures to structure data of DIFFERENT kinds.
B.2) What is a Structure?
Structures is a user defined data type available in IEC 61131-3 that allows us to combine data items of different types.
Structures are used to represent a record or logical group.
If we want to achieve what we did in the previous slide of storing 100 records of events, we now only need to create one array of 100 instances of this struct.
In this way all data is now grouped into one single array instead of five arrays with different data types.
To access a structures components, you use the following syntax.
In other words, you write the name of the structure, a dot, and the component inside of the structure.
In this example we are accessing the event text and we are storing it in another string variable.
Copy the PLC Code:
TYPE ST_Event :
STRUCT
eEventType : E_EventType;
eEventSeverity : TcEventSeverity;
nEventIdentity : UDINT;
sEvenText : STRING(255);
dtTimestamp : DATE_AND_TIME;
END_STRUCT
END_TYPE
PROGRAM MAIN
VAR
aEvents : ARRAY[1..100] OF ST_Event;
sTempString : STRING(255);
END_VAR
-----------------------------------------------------------------------
sTempString := aEvents[33].sEventText;,
B.3) How to create a Structure?
To create a new structure data unit type, right-click on DUTs, select Add, next select DUT.
Enter the name of the DUT, in this case ST_Event and make sure that "Structure" is selected.
This will create the STRUCT so that we can fill the members of the struct.
Just as with enumerations, the scope of structures is global which means that all the code in your project will see the structure definition.
You can't do like in for example C++ and create a local structure within a class.
C) TUTORIAL 8 - Functions
Now we will look at functions, which are used to perform certain actions and they are important for reusing code.
Define the code once, and use it many times.
C.1) Example 1 - Making an Celsius to Fahrenheit function
A function consists of:
-
a function name, in this case Celsius_To_Fahrenheit. (Don't be afraid of long function names. They should clearly describe their intent)
-
a return type. In this case we want to handle floating point values, such as 22.5 degrees and thus we need to return an REAL or LREAL
-
Next we have the inputs which will be used in the function, in this case a REAL value that we have named to fCelsius
-
Optionally we might have some local variables in the function. The local variables in functions serves as our “scratch pad” and this is where program variables are stored.
-
To return a value, enter the the name of the function and assign it the value to be returned, in this case the input parameter fCelsius times 1.8 + 32.0
Assume we have a program and we want to use this function.
We need a variable to store our result, in this case the fFahrenheit variable.
Next, we simply call the function and assign it the value that we want to convert to Fahrenheit.
If we did this call with the value of 5 degrees Celsius, we would get the value 41 Fahrenheit
Copy the PLC Code:
FUNCTION Celsius_To_Fahrenheit : REAL
VAR_INPUT
fCelsius : Real;
END_VAR
VAR
END_VAR
----------------------------------------------------------------------
Celsius_ToFahrenheit := fCelsius * 1.8 + 32.0;
PROGRAM MAIN
VAR
fFahrenheit : REAL;
END_VAR
-----------------------------------------------------------------------
fFahrenheit := Celsius_To_Fahrenheit(fCelsius := 5.0);
C.2) Example 2 - Making a comparison function with multiple outputs (Greater/Smaller than function)
There are also ways to have more than one output value from a function.
In this case we have a function that takes in two numbers, nNumber1 and nNumber2 and returns the greater and smaller of the two.
Note that the actual implementation of the function is very simple. We simply look whether nNumber1 is greater than nNumber2 and if so assign nNumber1 to nGreater, and if not, we do it the other way around.
To use a function like this, we first need to declare two variables in order for us to have somewhere to store the greater and smaller value. In this case the two variables nReturnGreater and nReturnSmaller.
Next we call the function by its name Greater_Smaller and we provide it with the two numbers we want to evaluate
Note the way to assign output values from a function to variables. We use =>, which is the assignment operator for outputs. You can learn more here.
Now the two variables will have the correct values.
Copy the PLC Code:
FUNCTION Greater_Smaller
VAR_INPUT
nNumber1 : INT;
nNumber2 : INT;
END_VAR
VAR_OUTPUT
nGreater : INT;
nSmaller : INT;
END_VAR
----------------------------------------------------------------------
IF nNumber1 > nNumber2 THEN
nGreater := nNumber1;
nSmaller := nNumber2;
ELSE
nGreater := nNumber2;
nSmaller := nNumber1;
END_IF
PROGRAM MAIN
VAR
nReturnGreater : INT;
nReturnSmaller : INT;
END_VAR
-----------------------------------------------------------------------
Greater_Smaller(nNumber1 := 8,
nNumber2 := 15,
nGreater => nReturnGreater,
nSmaller => nReturnSmaller);
C.3) Example 3 - Swap Numbers function (read and write to the same variable)
Functions can also have variables that are inputs and outputs at the same time This means that we can both read and write from and to the same variable.
These are declared with the VAR_IN_OUT keyword.
Let's assume we write a function SwapNums that swaps two numbers with each other.
And we use it in out main program, so in this case we have the two variables nA with value 5 and nB with value 15 and we want to swap the variables with each other.
If we provide these two numbers to the function, they will first go in as input parameters. Once in the function, we can write to the variables just like output parameters. To swap the numbers, we need to create a temporary variable called nNumberTemp, and store the nNumber1 in it. Next, we store the value of nNumber2 in nNumber1. Finally we store the value of nNumberTemp in nNumber2.
Now we have successfully swapped the values of the variables.
Copy the PLC Code:
FUNCTION SwapNums
VAR_IN_OUT
nNumber1 : INT;
nNumber2 : INT;
END_VAR
VAR
nNumberTemp : INT;
END_VAR
----------------------------------------------------------------------
nNumberTemp := nNumber1;
nNumber1 := nNumber2;
nNumber2 := nNumberTemp;
PROGRAM MAIN
VAR
nA : INT := 5;
nB : INT := 15;
END_VAR
-----------------------------------------------------------------------
SwapNums(nNumber1 := nA,
nNumber2 := nB);
C.4) How to create a Function
To create a function, right-click on POUs, select Add, Select POU.
Write the name of the function and fill in the data type of the return value. Make sure that structured text is selected.
This will create a shell for your function and now you can fill in the implementation.
C.5) Pass by value or by reference
When passing values into your function, you can do so either by value or by reference.
C.5.1) Pass by value vs Pass by reference (ChangeColor function example)
Let's assume we have a function called ChangeColor, and it takes some sort of object as input parameter, in this case a colored circle.
1. Pass by value:
When you pass a parameter to a function by value it means that the changes you make to that parameter inside the function will only be affected while inside that function. There will be no effect on the original data that is stored in the argument value. In essence, when you pass by value, you are sending a copy of the variable into the function. The copied variable can get changed inside of the function; however, the value of the original data will remain preserved.
2. Pass by reference:
On the other hand, when you pass a parameter to a function by reference the changes you make to that parameter inside the function will change the original data. When you pass by reference, you are passing the memory location of the variable to the function and any changes you make inside a function will affect the location in memory and will therefore persist after the function completes.
Let's look at some examples of how it could look like when we are passing parameters by value and by reference.
C.5.2) Pass by value vs Pass by reference (UpdateEventTimestampWithSystemTime function example)
1. Pass by value:
Let's imagine we are writing a function UpdateEventTimestampWithSystemTime which takes our structure event that we previously defined as an input parameter,
Remember, this is the input:
and changes the DATE_AND_TIME field of it to the current system time.
In this example we are providing the structure by value, and thus a copy is made internally in the function.
To return a structure with a modified DATE_AND_TIME value, we need to provide an output parameter, here called stEventOut.
First we would need to copy the complete content of the input parameter to the output parameter and next we would set the timestamp of the output structure to the system time of the PLC.
As you can see this is quite inefficient as the input parameter stEvent is a copy of the original structure and then we are making an additional copy by creating an output parameter.
The equivalent function in C++ would be something like this.
2. Pass by reference:
We can pass the value by reference instead, and then we are passing the memory location of the variable instead, so no copying is made.This can be achieved by either using the VAR_IN_OUT keyword for passing the parameter OR alternatively, provide the parameter as a REFERENCE TO type
By providing the value as reference, we can write the date_and_time timestamp directly into the structure.
The equivalent function in C++ would be something like this.
When should we use pass by value and when should we use pass by reference?
By definition, pass by value means you are making a copy in memory of the parameters value that is passed in a copy of the contents of the actual parameter.
The penalty for this can get quite extensive if the data that has to be copied is big.
We can draw some rules, and to the rules there will sometimes be exceptions, but three low hanging fruits are the following:
-
Pass by value when the function does not want to modify the parameter and the value is easy to copy so for example ints, floats, bools, etc... So by easy to copy I mean that the parameter is small, at most a few WORDs
-
Pass by reference when the function does not want to modify the parameter and the value is expensive to copy, so for example our structure event example
-
Pass by reference when the function does want to modify the parameter and the value is expensive to copy
D) TUTORIAL 9 - Structure & Function Application ("UpdateEventTimestampWithSystemTime" - fill the DATE_AND_TIME value of the Structure with the current system time of the PLC) //FILE -->TimeProject (part1)
Now we have learned what structures and functions are good for.
Let's now use our new knowledge to create something useful. Why not implement the function "UpdateEventTimestampWithSystemTime", which will do exactly what the function name is called that is, it will take our structure, and fill the date_and_time value of the structure with the current system time of the PLC.
Remember, this is the input:
D.1) Step1 - Making an Alarm and Event STRUCTURE with ENUMERATIONS
Ok so what I've done here is that I've created a completely new TwinCAT project and I've called it TimeProject.
Before we create the function we of course need to define the structure, so we:
- create a DUT
- Select structure,
- and call it ST_EVENT. (ST in front of structures is just a naming convention that Beckhoff uses)
Now let's just fill the structure with the data that we previously talked about, the different data fields that we want in our event structure.
1. The event type:
The first one we wanted was the eEventType. Which just defines whether it's an alarm or a message. So it's of type E_EventType.
Note: This enumeration (E_EventType) is not created, so we need to create that.
So let's create the enumeration using DUTs.
E_EventType can be either an alarm or message, finally Save & close.
TYPE E_EventType :
(
Alarm := 0,
Message := 1
);
END_TYPE
2. Event severity:
The structure also needs to hold an EventSeverity. So if it's an alarm, it will define whether it's a very critical error or less critical error.
Note: For this we don't need to make up our own, there is actually one pre-defined in TwinCAT that is used for for something that Beckhoff calls the EventLogger, it is basically already an application programming interface setup for creating events in TwinCAT 3.
This enumeration is called TcEventSeverity.
We can actually check it out by going to the definition.
And you see that this one is also an enumeration and you have VERBOSE, INFO, WARNING, ERROR or CRITICAL.
3. Event identity:
Next we need some form of event identity, so just a number.
This of course can mean whatever, it's up to you to define what it is. For example:
- number 10 means 'pressure loss"
- number 20 means 'too high temperature'
- etc
And this can be just a number so we will do it UDINT
4. Event text:
Next we need an event message, or event text, and this is just a STRING where we can write 'too high pressure' or just some message. We make it a STRING with 255 characters (which is a good size because that's the maximum size that a lot of build-in functions in TwinCAT 3 can handle).
5. And a timestamp:
And then we need the date and time, so we need the date and time of when this event was created so we call this dtTimestamp. And it's of type DATE_and_TIME
So now we have our event.
TYPE ST_Event :
STRUCT
eEventType : E_EventType;
eEventSeverity : TcEventSeverity;
nEventIdentity : UDINT;
sEvenText : STRING(255);
dtTimestamp : DATE_AND_TIME;
END_STRUCT
END_TYPE
D.2) Step2 - Making the function "UpdateEventTimestampWithSystemTime"
Next we need to create our function.
And to create our function we go to POUs, Add POU,
Then select Function, and we call it UpdateEventTimestampWithSystemTime
And the return type... actually we're not going to have any return type. Because this one is going to take the structure by reference and we will write directly to that structure.
But... we NEED to define always a return type in TC3. This is a silly thing, so you can just write 'blablablabla'. And then you can just remove the return type afterwards.
Then as an input we need to have the event so I just call it stEvent which is of type ST_Event (which is just the structure that we just defined).
And we take it in as a REFERENCE TO.
Note: if we didn't pass it by reference it would make a local copy here in the function which we don't need.
And we want to update this timestamp (dtTimestamp : DATE_AND_TIME) with the current system time of the PLC.
To do that we will use our friend Google and check what existing functions exist already in TwinCAT for this purpose. Googling getsystemtime twincat
D.2.1) Step2.1 - Using the GETSYSTEMTIME Function Block
Ok so this is a function block, (I'm going to get into what a function block is in the next episode of this tutorial). Right now we're only going to use it.
We need to instantiate it to use it. You do that here, in your local variables.
You instantiate it in this way. You create an instance of this function block.
And then if we call the function block,
we get this timeLoDW and timeHiDW. It's just two parts of a timestamp. For some reason Beckhoff decided to split into two 32-bit values. So it's 8 bytes for the whole timestamp.
Note: So this only gives us the system time in some weird format, so we're probably going to have to convert the system time into a DATE_TIME so hopefully there is going to be another function for this.
Now we need to store this value somewhere. Right now we just save these values into two local variables. So we just call them nTimeLow and nTimeHigh,
Now we need to look into some function to convert that into a DT (date_and_time)
What I usually do is ... ok let's go back to Google (googling date_and_time systemtime twincat {INCORRECT})
D.2.2) Step2.2 - Using FILETIME_TO_DT Function Block
OK.... (after some reading and corrections)
So FILETIME is what we have from the GETSYSTEMTIME Function Block.
It's two 32-bit values. And this can be converted into a DATE_AND_TIME using the function FILETIME_TO_DT.
So what we're going to do is that we're going to take this value that we got from SYSTEMTIME and we're going to store it inside a this type T_FILETIME which is a structure. So let's instantiate this structure. We're going to create a T_FILETIME and just call it stFileTime.
Using the "Utilities" Library
Ok and here is the next problem. This structure T_FILETIME exists in a library called "Utilities"
And when you create a new project of TwinCAT you don't have that library included as a reference.
And here you can add all the libraries that you have dependencies to.
Note: Normally you get the STANDARD, SYSTEM and MODULE. These are just the very basic stuff that you need in order to be able to compile a TwinCAT program.
But we need UTILITIES. So what we're going to do is right-click on references, add library,
search for "utilities" (Tc2_Utilities)
Now we got T_FILETIME to work.
Now we can actually double-click on it and check.
You see you have the structure, and it exists in Tc2_Utilities
We have the structure and now instead of using the two variables we created, we can remove them (we don't need them), because we are going to store the systemtime inside the structure to convert the filetime to DATE_AND_TIME.
So by calling fbGETSYSTEMTIME we'll get the system time from the function block GETSYSTEMTIME that Beckhoff or someone else has already done for us, so we don't need to worry too much about how this is working.
We could look at the documentation for it and see what it does and everything.
But we don't actually need to know exactly how it is working, we just need to know what this particular function block provides for us.
And we store the data that this function block provides into our T_FILETIME structure.
Next we need to convert this filetime into a DATE_AND_TIME.
This we do by using the function FILETIME_TO_DT,
Its output of DATE_AND_TIME, we can store it inside the structure that we provided by REFERENCE (stEvent)
And now we can run this function and see whether we get what we want.
Copy the PLC Code:
FUNCTION UpdateEventTimestampWithSystemTime
VAR_INPUT
stEvent : REFERENCE TO ST_Event;
END_VAR
VAR
fbGETSYSTEMTIME : GETSYSTEMTIME;
stFileTime : T_FILETIME;
END_VAR
------------------------------------------------------------------
// The function block writes on stFileTime (VAR_OUTPUT) in T_FILETIME format
fbGETSYSTEMTIME(timeLoDW => stFileTime.dwLowDateTime,
timeHiDW => stFileTime.dwHighDateTime);
// Overwrites the Timestamp of stEvent using the FILETIME_TO_DT function
stEvent.dtTimestamp := FILETIME_TO_DT(fileTime := stFileTime);
Note: In Structured Text, function calls can have parameters provided in two ways:
-
Positional Parameters:
The parameters are provided in a positional manner. -
Named Parameters:
The parameters are provided using named notation. This way of passing parameters is particularly useful when the function has multiple parameters, and you want to ensure clarity and readability in the code.
D.3) Step3 - Running the function "UpdateEventTimestampWithSystemTime"
First we are going to create an instance of this structure.
Note:
- This could also be an array of events that you have in the system. You could have an array of hundreds of events.
- Or you could get some event from some other part of your system.
- You could have a special event handler of some sort
But for now this simple example we'll just create one single event and we'll fill it with the data from this function .
And then, to fill it, we need to call our new function, and then we provide the event that we just created
Remeber: This is how our function works,
Now what's going to happen is this one is going to get called at every cycle so this event will just get a new timestamp all the time.
Maybe we don't want that. Maybe we just want it to be filled once, so we'll do that.
So we'll just create a very simple boolean to run it only once.
So again, this is how it works:
- we call the function that we just created (UpdateEventTimestampWithSytemTime).
- We provide the function with our event (stThisIsOurFirstIntstanceOfAStructure).
- The function takes the event as an input, but the input is passed as a REFERENCE to. So no copying is done. It's just provided a REFERENCE of it into the function.
- And then we use a Beckhoff function GETSYSTEMTIME to get the system time of the PLC.
- We store the output of this function block into a structure called T_FILETIME
- Then we need to convert it into a date_and_time, which we do with FILETIME_TO_DT
- And then we store the value in the timestamp of our structure
EASY PEASY! Right?
Copy the PLC Code:
PROGRAM MAIN
VAR
stThisIsOurFirstInstanceOfAStructure : ST_Event;
bBoolean : BOOL := FALSE;
END_VAR
------------------------------------------------------------------
IF NOT bBoolean THEN
UpdateEventTimestampWithSystemTime (stEvent := stThisIsOurFirstInstanceOfAStructure);
bBoolean := TRUE;
END_IF
Let's build this and compile!
Ok, so let's run it
Yes! There we go! It ran only once and the timestamp was filled with the right time
Note: the time is probably in UTC or something like this, so it might be different than the one on you laptop. But the day is correct and the adjustment can be made for different timezones.
Final Thoughts:
So it worked! You might have noticed that there is a lot of stuff happening here and this is usually what happens when you develop software, right? You don't quite know how to solve the problem but that's the nice thing... I mean this is one of the things I love with writing software. You know where you want to get to... you have a vision, you have a picture in your head of where you want to get to... But you don't know HOW. That's what so fun, that's the absolutely best thing with software development, the learning process... to just go around, look for information, do some thinking, and solve the problem. It's just a very enjoyable feeling.
Once you get stuff to work. And again, you never have all the answers in advance, that's the great thing, it's just a constant discovery. This was a very simple example but you'll quickly see that once you get to work with real projects the complexity is going to skyrocket and things are going to get really interesting.
That's it for this part! We managed to create our first structure and a function that's actually quite useful In the next episode we will look at one of the building blocks of object oriented programming, the function block See you in the next part!
E) Summary
In this part we learnt about Structures and Functions and the diference between passing by value and passing by reference. Also, we made our first useful function using all that we know and included some libraries and function blocks.
The functions that we made were:
E.1) Example 1 - Making an Celsius to Fahrenheit function
FUNCTION Celsius_To_Fahrenheit : REAL
VAR_INPUT
fCelsius : Real;
END_VAR
VAR
END_VAR
----------------------------------------------------------------------
Celsius_ToFahrenheit := fCelsius * 1.8 + 32.0;
PROGRAM MAIN
VAR
fFahrenheit : REAL;
END_VAR
-----------------------------------------------------------------------
fFahrenheit := Celsius_To_Fahrenheit(fCelsius := 5.0);
E.2) Example 2 - Making a comparison function with multiple outputs (Greater/Smaller than function)
FUNCTION Greater_Smaller
VAR_INPUT
nNumber1 : INT;
nNumber2 : INT;
END_VAR
VAR_OUTPUT
nGreater : INT;
nSmaller : INT;
END_VAR
----------------------------------------------------------------------
IF nNumber1 > nNumber2 THEN
nGreater := nNumber1;
nSmaller := nNumber2;
ELSE
nGreater := nNumber2;
nSmaller := nNumber1;
END_IF
PROGRAM MAIN
VAR
nReturnGreater : INT;
nReturnSmaller : INT;
END_VAR
-----------------------------------------------------------------------
Greater_Smaller(nNumber1 := 8,
nNumber2 := 15,
nGreater => nReturnGreater,
nSmaller => nReturnSmaller);
E.3) Example 3 - Swap Numbers function (read and write to the same variable)
FUNCTION SwapNums
VAR_IN_OUT
nNumber1 : INT;
nNumber2 : INT;
END_VAR
VAR
nNumberTemp : INT;
END_VAR
----------------------------------------------------------------------
nNumberTemp := nNumber1;
nNumber1 := nNumber2;
nNumber2 := nNumberTemp;
PROGRAM MAIN
VAR
nA : INT := 5;
nB : INT := 15;
END_VAR
-----------------------------------------------------------------------
SwapNums(nNumber1 := nA,
nNumber2 := nB);
E.4) Useful Function - "UpdateEventTimestampWithSystemTime" - fill the DATE_AND_TIME value of the Structure with the current system time of the PLC
Diagram:
E.4.1) DUTs
- Enum
TYPE E_EventType :
(
Alarm := 0,
Message := 1
);
END_TYPE
- Structure
TYPE ST_Event :
STRUCT
eEventType : E_EventType;
eEventSeverity : TcEventSeverity;
nEventIdentity : UDINT;
sEvenText : STRING(255);
dtTimestamp : DATE_AND_TIME;
END_STRUCT
END_TYPE
Remember:
Diagram:
E.4.2) POUs
- Function
FUNCTION UpdateEventTimestampWithSystemTime
VAR_INPUT
stEvent : REFERENCE TO ST_Event;
END_VAR
VAR
fbGETSYSTEMTIME : GETSYSTEMTIME;
stFileTime : T_FILETIME; // requires Tc2_Utilities
END_VAR
------------------------------------------------------------------
// The function block writes on stFileTime (VAR_OUTPUT) in T_FILETIME format
fbGETSYSTEMTIME(timeLoDW => stFileTime.dwLowDateTime,
timeHiDW => stFileTime.dwHighDateTime);
// Overwrites the Timestamp of stEvent using the FILETIME_TO_DT function
stEvent.dtTimestamp := FILETIME_TO_DT(fileTime := stFileTime);
Remember:
A) GETSYSTEMTIME FB
B) T_FILETIME Structure as output of the FB
C) Function to convert FILETIME to DATE_AND_TIME (DT)
- Main
PROGRAM MAIN
VAR
stThisIsOurFirstInstanceOfAStructure : ST_Event;
bBoolean : BOOL := FALSE;
END_VAR
------------------------------------------------------------------
IF NOT bBoolean THEN
UpdateEventTimestampWithSystemTime (stEvent := stThisIsOurFirstInstanceOfAStructure);
bBoolean := TRUE;
END_IF
Z) Glossary
File | Definition |
---|