In my 61131 program I have Objects/Information that needs to be shared between different program parts. What is best practice regarding this, should the Objects that needs to be shared be VAR in the PRG POU or global in a GVL?
From "high-level" programming I'm skeptical about global data, but this is maybe necessary?
Thanks for any input about best practice architectures in 61131.
I would make a STRUCT
to global variables that has all the global data for a one component, for example a struct called ST_CoolingSystem
which has the required global data for program handling the cooling system etc.
Other approach would be a method / property for the PROGRAM
POU. It of course required Codesys 3 or similar. This way you could create a getter for variable / struct to the program or function block itself such as PRG_CoolingSystem.GetData()
which returns the struct or reference to it.
Update:
One way to use OOP features is to add a property that returns a reference to data struct. NOTE: This works in TwinCAT 3, should also work in other IEC 61131-3 systems that have the new features.
Let's say we have a struct ST_Cooling
TYPE ST_Cooling :
STRUCT
//Commands
RunCooling : REAL;
TemperatureSetpoint : REAL;
//Status
MotorRunning : BOOL;
CurrentTemperature : REAL;
END_STRUCT
END_TYPE
And we also have a function block FB_Cooling
FUNCTION_BLOCK FB_Cooling
VAR_INPUT
END_VAR
VAR_OUTPUT
END_VAR
VAR
MotorRunCmd AT %Q* : BOOL;
Data_ : ST_Cooling; //"Private" of data struct
END_VAR
IF Data_.RunCooling THEN
//Do something
MotorRunCmd := TRUE;
//Update status
Data_.MotorRunning := TRUE;
ELSE
//Do something
MotorRunCmd := FALSE;
//Update status
data_.MotorRunning := FALSE;
END_IF
We can add a PROPERTY
to FB_Cooling
that can be used to retrieve the struct and read and edit it. Because it returns a reference (like pointer), we can delete the Set method of the property.
Type of the property:
PROPERTY Data : REFERENCE TO ST_Cooling
Code of the added PROPERTY's Get():
//FB_Cooling.Data (Get)
//Return reference to the data struct
Data REF= Data_;
Now it's possible to read and edit the data from anywhere where the instance of the function block can be accessed.
PROGRAM PRG_Test
VAR
CoolingSystem : FB_Cooling;
END_VAR
//This is how we read
IF CoolingSystem.Data.CurrentTemperature > 40.0 THEN
//This is how to write (because it is a reference)
CoolingSystem.Data.RunCooling := TRUE;
END_IF
//Run the block
CoolingSystem();
Perhaps this image also explains what does it look like in the project. See the Data property and it's Get, which is added automatically.
This is just an example, and a real system would have much more code and data. There could (should?) be also more structs, each for commands, statuses and parameters. But it's just my opinion :)