| 

.NET C# Java Javascript Exception

7
Depending on the task, it may be necessary for function blocks to require parameters that are only used once for initialization tasks. One possible way to pass them elegantly is to use the FB_init() method. Before TwinCAT 3, initialisation parameters were very often transferred via input variables. This had the disadvantage that the function blocks […]

Depending on the task, it may be necessary for function blocks to require parameters that are only used once for initialization tasks. One possible way to pass them elegantly is to use the FB_init() method.

Before TwinCAT 3, initialisation parameters were very often transferred via input variables.

(* TwinCAT 2 *)
FUNCTION_BLOCK FB_SerialCommunication
VAR_INPUT
 nDatabits : BYTE(7..8);
 eParity : E_Parity;
 nStopbits : BYTE(1..2);
END_VAR

This had the disadvantage that the function blocks became unnecessarily large in the graphic display modes. It was also not possible to prevent changing the parameters at runtime.

Very helpful is the method FB_init(). This method is implicitly executed one time before the PLC task is started and can be used to perform initialization tasks.

The dialog for adding methods offers a finished template for this purpose.

The method contains two input variables that provide information about the conditions under which the method is executed. The variables may not be deleted or changed. However, FB_init() can be supplemented with further input variables.

Example

An example is a block for communication via a serial interface (FB_SerialCommunication). This block should also initialize the serial interface with the necessary parameters. For this reason, three variables are added to FB_init():

METHOD FB_init : BOOL
VAR_INPUT
 bInitRetains : BOOL; // if TRUE, the retain variables are initialized (warm start / cold start)
 bInCopyCode : BOOL; // if TRUE, the instance afterwards gets moved into the copy code (online change)
 nDatabits : BYTE(7..8);
 eParity : E_Parity;
 nStopbits : BYTE(1..2); 
END_VAR

The serial interface is not initialized directly in FB_init(). Therefore, the parameters must be copied into variables located in the function block.

FUNCTION_BLOCK PUBLIC FB_SerialCommunication
VAR
 nInternalDatabits : BYTE(7..8);
 eInternalParity : E_Parity;
 nInternalStopbits : BYTE(1..2);
END_VAR

During initialization, the values from FB_init() are copied in these three variables.

METHOD FB_init : BOOL
VAR_INPUT
 bInitRetains : BOOL; // if TRUE, the retain variables are initialized (warm start / cold start)
 bInCopyCode : BOOL; // if TRUE, the instance afterwards gets moved into the copy code (online change)
 nDatabits : BYTE(7..8);
 eParity : E_Parity;
 nStopbits : BYTE(1..2);
END_VAR
 
THIS^.nInternalDatabits := nDatabits;
THIS^.eInternalParity := eParity;
THIS^.nInternalStopbits := nStopbits;

If an instance of FB_SerialCommunication is created, these three additional parameters must also be specified. The values are specified directly after the name of the function block in round brackets:

fbSerialCommunication : FB_SerialCommunication(nDatabits := 8,
 eParity := E_Parity.None,
 nStopbits := 1);

Even before the PLC task starts, the FB_init() method is implicitly called, so that the internal variables of the function block receive the desired values.

With the start of the PLC task and the call of the instance of FB_SerialCommunication, the serial interface can now be initialized.

It is always necessary to specify all parameters. A declaration without a complete list of the parameters is not allowed and generates an error message when compiling:

Arrays

If FB_init() is used for arrays, the complete parameters must be specified for each element (with square brackets):

aSerialCommunication : ARRAY[1..2] OF FB_SerialCommunication[
 (nDatabits := 8, eParity := E_Parity.None, nStopbits := 1),
 (nDatabits := 7, eParity := E_Parity.Even, nStopbits := 1)];

If all elements are to have the same initialization values, it is sufficient if the parameters exist once (without square brackets):

aSerialCommunication : ARRAY[1..2] OF FB_SerialCommunication(nDatabits := 8,
 eParity := E_Parity.None,
 nStopbits := 1);

Multidimensional arrays are also possible. All initialization values must also be specified here:

aSerialCommunication : ARRAY[1..2, 5..6] OF FB_SerialCommunication[
 (nDatabits := 8, eParity := E_Parity.None, nStopbits := 1),
 (nDatabits := 7, eParity := E_Parity.Even, nStopbits := 1),
 (nDatabits := 8, eParity := E_Parity.Odd, nStopbits := 2),
 (nDatabits := 7, eParity := E_Parity.Even, nStopbits := 2)];

Inheritance

If inheritance is used, the method FB_init() is always inherited. FB_SerialCommunicationRS232 is used here as an example:

FUNCTION_BLOCK PUBLIC FB_SerialCommunicationRS232 EXTENDS FB_SerialCommunication

If an instance of FB_SerialCommunicationRS232 is created, the parameters of FB_init(), which were inherited from FB_SerialCommunication, must also be specified:

fbSerialCommunicationRS232 : FB_SerialCommunicationRS232(nDatabits := 8,
 eParity := E_Parity.Odd,
 nStopbits := 1);

It is also possible to overwrite FB_init(). In this case, the same input variables must exist in the same order and be of the same data type as in the basic FB (FB_SerialCommunication). However, further input variables can be added so that the derived function block (FB_SerialCommunicationRS232) receives additional parameters:

METHOD FB_init : BOOL
VAR_INPUT
 bInitRetains : BOOL; // if TRUE, the retain variables are initialized (warm start / cold start)
 bInCopyCode : BOOL; // if TRUE, the instance afterwards gets moved into the copy code (online change)
 nDatabits : BYTE(7..8);
 eParity : E_Parity;
 nStopbits : BYTE(1..2);
 nBaudrate : UDINT; 
END_VAR
 
THIS^.nInternalBaudrate := nBaudrate;

If an instance of FB_SerialCommunicationRS232 is created, all parameters, including those of FB_SerialCommunication, must be specified:

fbSerialCommunicationRS232 : FB_SerialCommunicationRS232(nDatabits := 8,
 eParity := E_Parity.Odd,
 nStopbits := 1,
 nBaudRate := 19200);

In the method FB_init() of FB_SerialCommunicationRS232, only the copying of the new parameter (nBaudrate) is necessary. Because FB_SerialCommunicationRS232 inherits from FB_SerialCommunication, FB_init() of FB_SerialCommunication is also executed implicitly before the PLC task is started. Both FB_init() methods of FB_SerialCommunication and of FB_SerialCommunicationRS232 are always called implicitly. When inherited, FB_init() is always called from ‘bottom’ to ‘top’, first from FB_SerialCommunication and then from FB_SerialCommunicationRS232.

Forward parameters

The function block (FB_SerialCommunicationCluster) is used as an example, in which several instances of FB_SerialCommunication are declared:

FUNCTION_BLOCK PUBLIC FB_SerialCommunicationCluster
VAR
 fbSerialCommunication01 : FB_SerialCommunication(nDatabits := nInternalDatabits, eParity := eInternalParity, nStopbits := nInternalStopbits);
 fbSerialCommunication02 : FB_SerialCommunication(nDatabits := nInternalDatabits, eParity := eInternalParity, nStopbits := nInternalStopbits);
 nInternalDatabits : BYTE(7..8);
 eInternalParity : E_Parity;
 nInternalStopbits : BYTE(1..2); 
END_VAR

FB_SerialCommunicationCluster also receives the method FB_init() with the necessary input variables so that the parameters of the instances can be set externally.

METHOD FB_init : BOOL
VAR_INPUT
 bInitRetains : BOOL; // if TRUE, the retain variables are initialized (warm start / cold start)
 bInCopyCode : BOOL; // if TRUE, the instance afterwards gets moved into the copy code (online change)
 nDatabits : BYTE(7..8);
 eParity : E_Parity;
 nStopbits : BYTE(1..2);
END_VAR
 
THIS^.nInternalDatabits := nDatabits;
THIS^.eInternalParity := eParity;
THIS^.nInternalStopbits := nStopbits;

However, there are some things to be taken into consideration here. The call sequence of FB_init() is not clearly defined in this case. In my test environment the calls are made from ‘inside’ to ‘outside’. First fbSerialCommunication01.FB_init() and fbSerialCommunication02.FB_init() are called, then fbSerialCommunicationCluster.FB_init(). It is not possible to pass the parameters from ‘outside’ to ‘inside’. The parameters are therefore not available in the two inner instances of FB_SerialCommunication.

The sequence of the calls changes as soon as FB_SerialCommunication and FB_SerialCommunicationRS232 are derived from the same basic FB. In this case FB_init() is called from ‘outside’ to ‘inside’. This approach cannot always be implemented for two reasons:

  1. If FB_SerialCommunication is located in a library, the inheritance cannot be changed just offhand. The call sequence of FB_init() is not further defined with nesting. So it cannot be excluded that this can change in future versions.

One way to solve the problem is to explicitly call FB_SerialCommunication.FB_init() from FB_SerialCommunicationCluster.FB_init().

fbSerialCommunication01.FB_init(bInitRetains := bInitRetains, bInCopyCode := bInCopyCode, nDatabits := 7, eParity := E_Parity.Even, nStopbits := nStopbits);
fbSerialCommunication02.FB_init(bInitRetains := bInitRetains, bInCopyCode := bInCopyCode, nDatabits := 8, eParity := E_Parity.Even, nStopbits := nStopbits);

All parameters, including bInitRetains and bInCopyCode, are passed on directly.

Attention: Calling FB_init() always initializes all local variables of the instance. This must be considered as soon as FB_init() is explicitly called from the PLC task instead of implicitly before the PLC task.

Access via properties

By passing the parameters by FB_init(), they can neither be read from outside nor changed at runtime. The only exception would be the explicit call of FB_init() from the PLC task. However, this should principally be avoided, since all local variables of the instance will be reinitialized in this case.

If, however, access should still be possible, appropriate properties can be created for the parameters:

The setter and getter of the respective properties access the corresponding local variables in the function block (nInternalDatabits, eInternalParity and nInternalStopbits). Thus, the parameters can be specified in the declaration as well as at runtime.

By removing the setter, you can prevent the parameters from being changed at runtime. If the setter is available, FB_init() can be omitted. Properties can also be initialized directly when declaring an instance.

fbSerialCommunication : FB_SerialCommunication := (Databits := 8,
 Parity := E_Parity.Odd,
 Stopbits := 1);

The parameters of FB_init() and the properties can also be specified simultaneously:

fbSerialCommunication : FB_SerialCommunication(nDatabits := 8, eParity := E_Parity.Odd, nStopbits := 1) :=
 (Databits := 8, Parity := E_Parity.Odd, Stopbits := 1);

In this case, the initialization values of the properties have priority. The transfer by property and FB_init() has the disadvantage that the declaration of the function block becomes unnecessarily long. To implement both does not seem necessary to me either. If all parameters can also be written via properties, the initialization via FB_init() can be omitted. Conclusion: If parameters must not be changeable at runtime, the use of FB_init() has to be considered. If the write access is possible, properties are another opportunity.

Sample 1 (TwinCAT 3.1.4022) on GitHub

iec-61131-3 oop twincat plc interfaces inheritance iec-61131-3-(english) methods codesys
Weitere News:
Schreibe einen Kommentar:
Themen:
codesys methods iec-61131-3-(english) inheritance interfaces plc twincat oop iec-61131-3
Entweder einloggen... ...oder ohne Wartezeit registrieren
Benutzername
Passwort
Passwort wiederholen
E-Mail