this is my first question on StackOverlfow, so feel free to give me feedback on the problem :)
I'm new to working with controllers from Beckhoff and I'm trying to program a program block for communicating machine data to the PC. To store the data of different types I use an array of T_ARG in the function block "Communication", which is instantiated in "MAIN". At each restart its data are reset, which leads to the fact that I would have to load the information at the start always again into the array, whereby I would have the data then twice on the system.
Code inside the FB "Communication":
VAR
Values : ARRAY[DataArrayLow..DataArrayHigh] OF T_ARG;
ValueChanged : ARRAY[DataArrayLow..DataArrayHigh] OF BOOL;
END_VAR
I am using to the array "ValueChanged" to track change of the data by using a setvalue-method, which marks the index in "Values" to be transmitted.
For now i am calling the dunction block in "MAIN" as usual:
VAR
Communication : FB_Comm;
END_VAR
__________________________________________________________________________
Communication();
I already tried to mark the variables as persistent, which did not work.
I dont really wont to create an external global variable and give it to the function block as input, since it defeats the purpose of capsulation and it would be cluttered.
Here is a simple project that can show you that PERSISTENT data inside a function block can indeed be saved.
Declare a test structure:
TYPE ST_DataToBePersistent :
STRUCT
bVar : BOOL;
nVar : INT;
fVar : REAL;
END_STRUCT
END_TYPE
Now declare a function block, FB_Test using that struct as internal parameter set. Adding the FB_WritePersistentData as VAR_IN_OUT. We need to call it to save the persistent data inside this function block.
FUNCTION_BLOCK FB_Test
VAR PERSISTENT
arrPersistentParameterStruct : ARRAY [0..10] OF ST_DataToBePersistent;
END_VAR
VAR_IN_OUT
fbWritePersistentData : FB_WritePersistentData;
END_VAR
VAR
bSavePersistentData : BOOL;
END_VAR
Body of the FB:
IF bSavePersistentData THEN
bSavePersistentData := FALSE;
fbWritePersistentData.START := TRUE;
END_IF
A simple method to set the value of the internal structure:
METHOD PUBLIC WriteToStruct
VAR_INPUT
arrPersistentParameterStruct : ARRAY[0..10] OF ST_DataToBePersistent;
END_VAR
And it's body. When called internal structure array will be changed and we also set a flag to call the passed FB_WritePersistentData which will saved ALL persistent data on the dedicated port (local):
THIS^.arrPersistentParameterStruct := arrPersistentParameterStruct;
bSavePersistentData := TRUE;
Instantiate 2 instances, just to set the value of the array and adding FB_WritePersistentData that will be called when the method FB_Test.WriteToStruct is called. Also adding some variables for diagnostic purpose and triggering the methods:
PROGRAM MAIN
VAR
fbTestInstance1 : FB_Test;
fbTestInstance2 : FB_Test;
fbWritePersistentData : FB_WritePersistentData;
bSetData1 : BOOL;
bSetData2 : BOOL;
arrDataToSet : ARRAY[0..10] OF ST_DataToBePersistent;
TofPersistentDataSaved : TOF;
FtrigDataSaveComplete : F_TRIG;
bDataSaveComplete : BOOL;
END_VAR
In the main body, cyclically call both fbs as well as the persistent data FB. Set the values of the arrDataToSet in online mode to anything you want and trigger which function block you want to change. Observe the bDataSaveComlete is set for 2 seconds after saving is complete.
fbTestInstance1(fbWritePersistentData := fbWritePersistentData);
fbTestInstance2(fbWritePersistentData := fbWritePersistentData);
IF bSetData1 THEN
bSetData1 := FALSE;
fbTestInstance1.WriteToStruct(arrPersistentParameterStruct := arrDataToSet);
END_IF
IF bSetData2 THEN
bSetData2 := FALSE;
fbTestInstance2.WriteToStruct(arrPersistentParameterStruct := arrDataToSet);
END_IF
fbWritePersistentData(NETID := '', PORT := 851);
FtrigDataSaveComplete(CLK := fbWritePersistentData.BUSY);
TofPersistentDataSaved(IN := FtrigDataSaveComplete.Q, PT := T#2S);
bDataSaveComplete := TofPersistentDataSaved.Q;
IF fbWritePersistentData.BUSY THEN
fbWritePersistentData.START := FALSE;
END_IF
Example:
Initial state of the fbTestInstance1:
I will write to fbTestInstance by setting the bSetData1:
I will set different values to second fb:
Now I will initiate a restart of the target machine's TwinCAT:
Logging back in, the data is still the same:
Persistent data is always loaded properly upon TwinCAT, be it restarting the runtime or operating system.
Hope this answers your question. As Jakob already mentioned, what dwpessoa is saying ONLY applies to functions since all of the memory they occupy is discarded when it has been released.