Defining and configuring an application object database of controlled station
Here you can unpack the complete PLC sources: TutorialSample.zip
Application objects = single points, double points, measured values, short floating point values, etc.
In this example the commands have been configured in a way that the process data are placed in the same memory area but on another byte/bit offset than the data of information in control direction. But you can also place the commands to the same byte/bit offset like information in control direction.
Example:
C_SC_NA_1 with IOA = 10 on the same byte/bit offset like M_SP_NA_1 with IOA = 100 (both byte ofset = 100 and bit offset = 0).
In this case a change of value via a command from the control station will cause a transfer of the M_SP_NA_1 with the object address 100 and transfer cause <11> (returned by remote command).
As an example we will configure the following application objects as part of the introductory project:
Requirements
Array | ASDU | Object address | Group | Base time | PLC | Byte | Bit | Process data width in the TwinCAT PLC |
---|---|---|---|---|---|---|---|---|
0 | M_SP_NA_1 | 100 | General interrogation group global | 0 | Memory | 100 | 0 | 1 bit |
1 | M_SP_NA_1 | 101 | General interrogation group global | 0 | Memory | 100 | 1 | 1 Bit |
2 | M_SP_TB_1 | 102 | General interrogation group global | 0 | Memory | 100 | 2 | 1 Bit |
3 | M_DP_NA_1 | 200 | General interrogation group global | 0 | Memory | 200 | 0 | 2 Bits |
4 | M_DP_NA_1 | 201 | General interrogation group global | 0 | Memory | 200 | 2 | 2 Bits |
5 | M_DP_TB_1 | 202 | General interrogation group global | 0 | Memory | 200 | 4 | 2 Bits |
6 | M_ST_NA_1 | 300 | General interrogation group global | 0 | Memory | 300 | 0 | 1 Byte |
7 | M_ST_NA_1 | 301 | General interrogation group global | 0 | Memory | 301 | 0 | 1 Byte |
8 | M_ST_TB_1 | 302 | General interrogation group global | 0 | Memory | 302 | 0 | 1 Byte |
9 | M_BO_NA_1 | 400 | General interrogation group global | 0 | Memory | 400 | 0 | 4 Byte |
10 | M_BO_NA_1 | 401 | General interrogation group global | 0 | Memory | 404 | 0 | 4 Byte |
11 | M_BO_TB_1 | 402 | General interrogation group global | 0 | Memory | 408 | 0 | 4 Byte |
12 | M_ME_NA_1 | 500 | General interrogation group global | 0 | Memory | 500 | 0 | 2 Byte |
13 | M_ME_NA_1 | 501 | General interrogation group global | 0 | Memory | 502 | 0 | 2 Byte |
14 | M_ME_TD_1 | 502 | General interrogation group global | 0 | Memory | 504 | 0 | 2 Byte |
15 | M_ME_NB_1 | 600 | General interrogation group global | 0 | Memory | 600 | 0 | 2 Byte |
16 | M_ME_NB_1 | 601 | General interrogation group global | 0 | Memory | 602 | 0 | 2 Byte |
17 | M_ME_TE_1 | 602 | General interrogation group global | 0 | Memory | 604 | 0 | 2 Byte |
18 | M_ME_NC_1 | 700 | General interrogation group global | 0 | Memory | 700 | 0 | 4 Byte |
19 | M_ME_NC_1 | 701 | General interrogation group global | 0 | Memory | 704 | 0 | 4 Byte |
20 | M_ME_TF_1 | 702 | General interrogation group global | 0 | Memory | 708 | 0 | 4 Byte |
21 | M_IT_NA_1 | 800 | General counter interrogation and mode A (local freeze with spontaneous transfer every 15s) | 0 | Memory | 800 | 0 | 4 Byte |
22 | M_IT_NA_1 | 801 | General counter interrogation and mode A (local freeze with spontaneous transfer every 15s) | 0 | Memory | 804 | 0 | 4 Byte |
23 | M_IT_TB_1 | 802 | General counter interrogation and mode A (local freeze with spontaneous transfer every 15s) | 0 | Memory | 808 | 0 | 4 Byte |
Commands |
|
|
|
|
|
|
|
|
24 | C_SC_NA_1 | 10 | - | 0 | Memory | 2100 | 0 | 1 Bit |
25 | C_SC_NA_1 | 11 | - | 0 | Memory | 2100 | 1 | 1 Bit |
26 | C_SC_TA_1 | 12 | - | 0 | Memory | 2100 | 2 | 1 Bit |
27 | C_DC_NA_1 | 20 | - | 0 | Memory | 2200 | 0 | 2 Bit |
28 | C_DC_NA_1 | 21 | - | 0 | Memory | 2200 | 2 | 2 Bit |
29 | C_DC_TA_1 | 22 | - | 0 | Memory | 2200 | 4 | 2 Bit |
30 | C_RC_NA_1 | 30 | - | 0 | Memory | 2300 | 0 | 1 Byte |
31 | C_RC_NA_1 | 31 | - | 0 | Memory | 2301 | 0 | 1 Byte |
32 | C_RC_TA_1 | 32 | - | 0 | Memory | 2302 | 0 | 1 Byte |
33 | C_BO_NA_1 | 40 | - | 0 | Memory | 2400 | 0 | 4 Byte |
34 | C_BO_NA_1 | 41 | - | 0 | Memory | 2404 | 0 | 4 Byte |
35 | C_BO_TA_1 | 42 | - | 0 | Memory | 2408 | 0 | 4 Byte |
36 | C_SE_NA_1 | 50 | - | 0 | Memory | 2500 | 0 | 2 Byte |
37 | C_SE_NA_1 | 51 | - | 0 | Memory | 2502 | 0 | 2 Byte |
38 | C_SE_TA_1 | 52 | - | 0 | Memory | 2504 | 0 | 2 Byte |
39 | C_SE_NB_1 | 60 | - | 0 | Memory | 2600 | 0 | 2 Byte |
40 | C_SE_NB_1 | 61 | - | 0 | Memory | 2602 | 0 | 2 Byte |
41 | C_SE_TB_1 | 62 | - | 0 | Memory | 2604 | 0 | 2 Byte |
42 | C_SE_NC_1 | 70 | - | 0 | Memory | 2700 | 0 | 4 Byte |
43 | C_SE_NC_1 | 71 | - | 0 | Memory | 2704 | 0 | 4 Byte |
44 | C_SE_TC_1 | 72 | - | 0 | Memory | 2708 | 0 | 4 Byte |
Declaring a database variable
The application object database is an array variable of type ST_IEC870_5_101AODBEntry. Each array element corresponds to an application object. The maximum number of application objects is freely selectable and is only limited by the available memory. During PLC programming you have to specify a constant maximum number. The maximum number of application objects cannot be changed at runtime.
In our example 50 application objects are declared. This number is sufficient for most applications. Please note that many application objects require adequate memory and runtime resources.
Define the following variable in MAIN:
PROGRAM MAIN
VAR
AODB : ARRAY[0..49] OF ST_IEC870_5_101AODBEntry;
END_VAR
Configuring application objects
The object type (M_SP_NA_1, M_DP_NA_1, M_ST_NA_1 etc.), the object address and further object parameters are specified during configuration of the individual application objects.
The required application objects are configured during program runtime. Each application object (database array element) is configured by calling the F_iecInitAOEntry function once. The array element to be configured is transferred to the function via VAR_IN_OUT. Configuration is usually carried out once during PLC program start-up via an Init routine. The F_iecInitAOEntry function expects the following function parameters (from left to right):
FUNCTION F_iecInitAOEntry : UDINT
VAR_INPUT
eType : E_IEC870_5_101TcTypeID;
objAddr : DWORD := 0;
group : DWORD := 0;
multiplier : BYTE := 0;
ioMapType : E_IEC870_5_101IOMappingType;
byteOffs : UDINT := 0;
bitOffs : UDINT := 0;
END_VAR
VAR_IN_OUT
dbEntry : ST_IEC870_5_101AODBEntry;
END_VAR
eType: application object type (ASDU identifier, e.g.: M_SP_NA_1 for single point or M_DP_NA_1 for double point). Please note that only the ASDU types listed in the compatibility list can be used. Invalid types are ignored.
objAddr : object address, e.g. 100. Each application object should be configured with a unique address.
group: group configuration parameters. The available group parameters are defined as constants and can be combined with an OR operator. E.g.: IEC870_GRP_INROGEN OR IEC870_GRP_PERCYC.
A description of all group configuration parameters can be found here.
mutiplier: base time multiplier for cyclic/periodic data transfer (0=deactivated). The base time is configured via the system parameters. If the base time was set to T#10 s, and the multiplier to 2, for example, the periodic/cyclic data of the application object are sent every 20 seconds.
ioMapType: This parameter defines from or in which process data area of the TwinCAT PLC the IEC process data are to be mapped at runtime (inputs, outputs, memory, data).
byteOffs: process data area byte offset;
bitOffs: process data area bit offset;
dbEntry: application object to be configured (a database variable array element that is transferred to the function via VAR_IN_OUT).
In order to configure the application objects during program start-up, add the following PLC code in MAIN:
PROGRAM MAIN
VAR
AODB : ARRAY[0..49] OF ST_IEC870_5_101AODBEntry;
init : BOOL := TRUE;
initError : UDINT;
END_VAR
IF init THEN
init := FALSE;
(* Monitored Single Points *)
initError := F_iecInitAOEntry( M_SP_NA_1, 100, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 100, 0, AODB[0] );
initError := F_iecInitAOEntry( M_SP_NA_1, 101, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 100, 1, AODB[1] );
initError := F_iecInitAOEntry( M_SP_TB_1, 102, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 100, 2, AODB[2] );
(* Double Points*)
initError := F_iecInitAOEntry( M_DP_NA_1, 200, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 200, 0, AODB[3] );
initError := F_iecInitAOEntry( M_DP_NA_1, 201, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 200, 2, AODB[4] );
initError := F_iecInitAOEntry( M_DP_TB_1, 202, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 200, 4, AODB[5] );
(* Regulating step value *)
initError := F_iecInitAOEntry( M_ST_NA_1, 300, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 300, 0, AODB[6] );
initError := F_iecInitAOEntry( M_ST_NA_1, 301, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 301, 0, AODB[7] );
initError := F_iecInitAOEntry( M_ST_TB_1, 302, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 302, 0, AODB[8] );
(* 32 bit string*)
initError := F_iecInitAOEntry( M_BO_NA_1, 400, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 400, 0, AODB[9 );
initError := F_iecInitAOEntry( M_BO_NA_1, 401, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 404, 0, AODB[10] );
initError := F_iecInitAOEntry( M_BO_TB_1, 402, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 408, 0, AODB[11] );
(* Measured value, normalized value *)
initError := F_iecInitAOEntry( M_ME_NA_1, 500, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 500, 0, AODB[12] );
initError := F_iecInitAOEntry( M_ME_NA_1, 501, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 502, 0, AODB[13] );
initError := F_iecInitAOEntry( M_ME_TD_1, 502, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 504, 0, AODB[14] );
(* Mesured value, scaled value *)
initError := F_iecInitAOEntry( M_ME_NB_1, 600, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 600, 0, AODB[15] );
initError := F_iecInitAOEntry( M_ME_NB_1, 601, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 602, 0, AODB[16] );
initError := F_iecInitAOEntry( M_ME_TE_1, 602, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 604, 0, AODB[17] );
(* Measured value , short floating point value *)
initError := F_iecInitAOEntry( M_ME_NC_1, 700, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 700, 0, AODB[18] );
initError := F_iecInitAOEntry( M_ME_NC_1, 701, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 704, 0, AODB[19] );
initError := F_iecInitAOEntry( M_ME_TF_1, 702, IEC870_GRP_INROGEN, 0, MAP_AREA_MEMORY, 708, 0, AODB[20] );
(* Integrated totals *)
initError := F_iecInitAOEntry( M_IT_NA_1, 800, IEC870_GRP_REQCOGEN OR IEC870_GRP_LOCFREEZE, 0, MAP_AREA_MEMORY, 800, 0, AODB[21] );
initError := F_iecInitAOEntry( M_IT_NA_1, 801, IEC870_GRP_REQCOGEN OR IEC870_GRP_LOCFREEZE, 0, MAP_AREA_MEMORY, 804, 0, AODB[22] );
initError := F_iecInitAOEntry( M_IT_TB_1, 802, IEC870_GRP_REQCOGEN OR IEC870_GRP_LOCFREEZE, 0, MAP_AREA_MEMORY, 808, 0, AODB[23] );
(* Single commands *)
initError := F_iecInitAOEntry( C_SC_NA_1, 10, 0, 0, MAP_AREA_MEMORY, 2100, 0, AODB[24] );
initError := F_iecInitAOEntry( C_SC_NA_1, 11, 0, 0, MAP_AREA_MEMORY, 2100, 1, AODB[25] );
initError := F_iecInitAOEntry( C_SC_TA_1, 12, 0, 0, MAP_AREA_MEMORY, 2100, 2, AODB[26] );
(* Double commands *)
initError := F_iecInitAOEntry( C_DC_NA_1, 20, 0, 0, MAP_AREA_MEMORY, 2200, 0, AODB[27] );
initError := F_iecInitAOEntry( C_DC_NA_1, 21, 0, 0, MAP_AREA_MEMORY, 2200, 2, AODB[28] );
initError := F_iecInitAOEntry( C_DC_TA_1, 22, 0, 0, MAP_AREA_MEMORY, 2200, 4, AODB[29] );
(* Regulating step commands *)
initError := F_iecInitAOEntry( C_RC_NA_1, 30, 0, 0, MAP_AREA_MEMORY, 2300, 0, AODB[30] );
initError := F_iecInitAOEntry( C_RC_NA_1, 31, 0, 0, MAP_AREA_MEMORY, 2301, 0, AODB[31] );
initError := F_iecInitAOEntry( C_RC_TA_1, 32, 0, 0, MAP_AREA_MEMORY, 2302, 0, AODB[32] );
(* 32 bit string commands *)
initError := F_iecInitAOEntry( C_BO_NA_1, 40, 0, 0, MAP_AREA_MEMORY, 2400, 0, AODB[33] );
initError := F_iecInitAOEntry( C_BO_NA_1, 41, 0, 0, MAP_AREA_MEMORY, 2404, 0, AODB[34] );
initError := F_iecInitAOEntry( C_BO_TA_1, 42, 0, 0, MAP_AREA_MEMORY, 2408, 0, AODB[35] );
(* Set point, normalized values*)
initError := F_iecInitAOEntry( C_SE_NA_1, 50, 0, 0, MAP_AREA_MEMORY, 2500, 0, AODB[36] );
initError := F_iecInitAOEntry( C_SE_NA_1, 51, 0, 0, MAP_AREA_MEMORY, 2502, 0, AODB[37] );
initError := F_iecInitAOEntry( C_SE_TA_1, 52, 0, 0, MAP_AREA_MEMORY, 2504, 0, AODB[38] );
(* Set point, scaled valuess *)
initError := F_iecInitAOEntry( C_SE_NB_1, 60, 0, 0, MAP_AREA_MEMORY, 2600, 0, AODB[39] );
initError := F_iecInitAOEntry( C_SE_NB_1, 61, 0, 0, MAP_AREA_MEMORY, 2602, 0, AODB[40] );
initError := F_iecInitAOEntry( C_SE_TB_1, 62, 0, 0, MAP_AREA_MEMORY, 2604, 0, AODB[41] );
(* Set point, short floating point values *)
initError := F_iecInitAOEntry( C_SE_NC_1, 70, 0, 0, MAP_AREA_MEMORY, 2700, 0, AODB[42] );
initError := F_iecInitAOEntry( C_SE_NC_1, 71, 0, 0, MAP_AREA_MEMORY, 2704, 0, AODB[43] );
initError := F_iecInitAOEntry( C_SE_TC_1, 72, 0, 0, MAP_AREA_MEMORY, 2708, 0, AODB[44] );
END_IF