0% found this document useful (0 votes)
133 views19 pages

(загрузить pdf, 1Mb) : release

This document contains the source code for a MODBUSCP function block. The function block can operate as either a MODBUS client or server for communicating with MODBUS devices over various networks. It includes inputs for configuration parameters like connection ID, address, monitoring time, and data areas. The block performs MODBUS communication using internal function blocks FB106 and FB107. It returns outputs indicating status, errors, and transaction results.

Uploaded by

Mauro Cellupica
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as RTF, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
133 views19 pages

(загрузить pdf, 1Mb) : release

This document contains the source code for a MODBUSCP function block. The function block can operate as either a MODBUS client or server for communicating with MODBUS devices over various networks. It includes inputs for configuration parameters like connection ID, address, monitoring time, and data areas. The block performs MODBUS communication using internal function blocks FB106 and FB107. It returns outputs indicating status, errors, and transaction results.

Uploaded by

Mauro Cellupica
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as RTF, PDF, TXT or read online on Scribd
You are on page 1/ 19

m o d b u s

Подробнее в официальной документации- (загрузить pdf, 1Mb)

Свойства блока:

Name: FB108
Symbolic Name: MODBUSCP
Symbol Comment:
Family: COMM
Version: 2.2
Author: SIEMENS
Last modified: 06/08/2011
Use: FB106,FB107,SFC20,SFC51,SFC52,SFC6
Size in work memory: 6244 bytes
Object name: fb 108nc
Signature: generiert vom SCL Übersetzer Version: SCLCOMP K05.03.05.00_01.03.00.01
release

Исходный текст:

{
Scl_ResetOptions ;
Scl_OverwriteBlocks:= 'y' ;
Scl_GenerateReferenceData := 'y' ;
Scl_S7ServerActive:= 'y' ;
Scl_CreateObjectCode:= 'y' ;
Scl_OptimizeObjectCode:= 'y' ;
Scl_MonitorArrayLimits:= 'n' ;
Scl_CreateDebugInfo := 'n' ;
Scl_SetOKFlag:= 'n' ;
Scl_SetMaximumStringLength:= '254'
}
FUNCTION_BLOCK FB1108
TITLE ='MODBUSCP'
{ S7_tasklist := 'OB100' }
AUTHOR : SIEMENS
FAMILY : COMM
NAME : MODBUSCP
VERSION : '2.2'
// reversed by komatic

LABEL
_EXIT;
END_LABEL

VAR_INPUT
id : WORD ; //Connection-ID as per configuration in NetPro 1 to 64
laddr : WORD ; // Input-Address of the CP in HW Config
MONITOR : TIME ; //Monitoring Time: Wait for data from communication partner Shortest
adjustable time is 20 ms
REG_KEY : STRING [17 ] := ' '; // Registration key to activate the license
REG_KEY_b AT REG_KEY :
STRUCT
length: BYTE;
act_length: BYTE;
str: ARRAY [0..15] OF BYTE;
END_STRUCT;
server_client : BOOL ; // CP/FB operates in server mode or client mode
single_write : BOOL ; // Write 1 Coil/Register: Function code 5 and 6 are used respectively
Function code 15 and 16 are used respectively
data_type_1 : BYTE ; // 1st data area: data type Coils Inputs Holding Register Input Register 0 to
4
db_1 : WORD ; // 1st data area: data block number 1 to 65535
start_1 : WORD ; // 1st data area: first Modbus address in this DB 0 to 65535
end_1 : WORD ; // 1st data area: last Modbus address in this DB 0 to 65535
data_type_2 : BYTE ; // 2nd data area: data type (Coils, Inputs, Holding Register, Input
Register), NULL if not used
db_2 : WORD ; // 2nd data area: data block number
start_2 : WORD ; // 2nd data area: first Modbus address in this DB
end_2 : WORD ; // 2nd data area: last Modbus address in this DB
data_type_3 : BYTE ; // ...
db_3 : WORD ;
start_3 : WORD ;
end_3 : WORD ;
data_type_4 : BYTE ;
db_4 : WORD ;
start_4 : WORD ;
end_4 : WORD ;
data_type_5 : BYTE ;
db_5 : WORD ;
start_5 : WORD ;
end_5 : WORD ;
data_type_6 : BYTE ;
db_6 : WORD ;
start_6 : WORD ;
end_6 : WORD ;
data_type_7 : BYTE ;
db_7 : WORD ;
start_7 : WORD ;
end_7 : WORD ;
data_type_8 : BYTE ;
db_8 : WORD ;
start_8 : WORD ;
end_8 : WORD ;
ENQ_ENR : BOOL ; // CP is client: Initiate request at TRUE signal CP is server: Ready to
receive at TRUE signal
END_VAR
VAR_OUTPUT
LICENSED : BOOL ; // License state of the function block: Block is licensed Block is not
licensed
BUSY : BOOL ; // Operating state of the functions AG_SEND and AG_RECV Job processing
No job processing active
DONE_NDR : BOOL ; // CP is client: Active request finished without errors CP is server:
Request from the client was executed and answered
ERROR : BOOL ; // An error has occurred No error has occurred
STATUS : WORD ; // Error number
STATUS_FUNC : STRING [8 ]; // Name of the function, which causes the error at STATUS
STATUS_FUNC_b AT STATUS_FUNC : ARRAY [0..1] OF BYTE ;
IDENT_CODE : STRING [18 ]; // Identification for licensing Please order your license with this
identification string.
END_VAR
VAR_IN_OUT
UNIT : BYTE ; // Unit identification (INPUT if in CLIENT mode, OUTPUT if in SERVER
mode) 0 to 255
DATA_TYPE : BYTE ; // Data type to be accessed: (INPUT if in CLIENT mode, OUTPUT if in
SERVER mode) Coils Inputs Holding registers Input registers
START_ADDRESS : WORD ; // MODBUS start address (INPUT if in CLIENT mode,
OUTPUT if in SERVER mode)
LENGTH : WORD ; // Number of registers to be processed (INPUT if in CLIENT mode,
OUTPUT if in SERVER mode) Coils: reading function
WRITE_READ : BOOL ; // INPUT if in CLIENT mode, OUTPUT if in SERVER mode: Write
access Read access
END_VAR
VAR
TI : WORD ; // Transaction Identifier (INPUT if in CLIENT mode, OUTPUT if in SERVER
mode)
SEND_BUFFER : ARRAY [1 .. 260 ] OF BYTE ;
RECV_BUFFER1 : ARRAY [1 .. 6 ] OF BYTE ;
RECV_BUFFER2 : ARRAY [1 .. 260 ] OF BYTE ;
MB_CPCLI : FB106;
MB_CPSRV : FB107;
TON : SFB4;
sIDB_Nr : WORD ;
sLADDR : WORD ;
sID : WORD ;
sSTATUS_TEMP : WORD ;
sSTATUS_TIMER : WORD ;
sSTATUS_FUNC : STRING [8 ];
sSTATUS_CODE : STRING [17 ];
sSTATUS_CODE_b AT sSTATUS_CODE :
STRUCT
length: BYTE;
act_length: BYTE;
str: ARRAY [0..15] OF BYTE;
END_STRUCT;
sDATA_AREAS : DINT ;
sSEND_BUFFER : DINT ;
sRECV1_BUFFER : DINT ;
sRECV2_BUFFER : DINT ;
sSERVER_CLIENT : BOOL ;
sSINGLE_WRITE : BOOL ;
sANLAUF_FEHLER : BOOL ;
sANLAUF : BOOL ;
sAREA_VALID : ARRAY [1 .. 8 ] OF BOOL ;
sAREA_1 : ARRAY [1 .. 2 ] OF CHAR := 'M', 'O';
sAREA_2 : ARRAY [1 .. 4 ] OF CHAR := 'D', 'B', 'U', 'S';
sStart_x : DINT ;
sEnd_x : DINT ;
sStart_y : DINT ;
sEnd_y : DINT ;
tDbNr : WORD ;
i : INT ;
j : INT ;
pos : INT ;
k : INT ;
reg : INT ;
sDataType : WORD ;
snd_time : BYTE ;
rcv_time : BYTE ;
sACODE : ARRAY [0 .. 17 ] OF BYTE ;
H_STATION : BYTE ;
H_STATION_TIME : TIME ;
RD_SINFO : STRUCT
RET_WERT : INT ;
TOP_SI : STRUCT
EV_CLASS : BYTE ;
EV_NUM : BYTE ;
PRIORITY : BYTE ;
NUM : BYTE ;
TYP2_3 : BYTE ;
TYP1 : BYTE ;
ZI1 : WORD ;
ZI2_3 : DWORD ;
END_STRUCT ;
START_UP_SI : STRUCT
EV_CLASS : BYTE ;
EV_NUM : BYTE ;
PRIORITY : BYTE ;
NUM : BYTE ;
TYP2_3 : BYTE ;
TYP1 : BYTE ;
ZI1 : WORD ;
ZI2_3 : DWORD ;
END_STRUCT ;
END_STRUCT ;
RDSYSST : STRUCT
RET_WERT : INT ;
REQ : BOOL ;
BUSY : BOOL ;
SZL_HEADER : STRUCT
LENTHDR : WORD ;
N_DR : WORD ;
END_STRUCT ;
SZL_11C_5 : STRUCT
index : WORD ;
serialn : ARRAY [0 .. 23 ] OF CHAR ;
res : ARRAY [1 .. 4 ] OF WORD ;
END_STRUCT ;
END_STRUCT ;
CPU_DATA : STRUCT
Index : WORD ;
CPUIdent : ARRAY [1 .. 20 ] OF BYTE ;
Reserved : WORD ;
MajorVersion : WORD ;
MinorVersion_1 : BYTE ;
MinorVersion_2 : BYTE ;
END_STRUCT ;
sdata_type_1 : BYTE ;
sdb_1 : WORD ;
sstart_1 : WORD ;
send_1 : WORD ;
sdata_type_2 : BYTE ;
sdb_2 : WORD ;
sstart_2 : WORD ;
send_2 : WORD ;
sdata_type_3 : BYTE ;
sdb_3 : WORD ;
sstart_3 : WORD ;
send_3 : WORD ;
sdata_type_4 : BYTE ;
sdb_4 : WORD ;
sstart_4 : WORD ;
send_4 : WORD ;
sdata_type_5 : BYTE ;
sdb_5 : WORD ;
sstart_5 : WORD ;
send_5 : WORD ;
sdata_type_6 : BYTE ;
sdb_6 : WORD ;
sstart_6 : WORD ;
send_6 : WORD ;
sdata_type_7 : BYTE ;
sdb_7 : WORD ;
sstart_7 : WORD ;
send_7 : WORD ;
sdata_type_8 : BYTE ;
sdb_8 : WORD ;
sstart_8 : WORD ;
send_8 : WORD ;
sHoldingRegisterState : ARRAY [0 .. 24 ] OF BYTE ;
END_VAR
VAR_TEMP
tSProductID : STRING [19 ];
tSProductID_b AT tSProductID : STRUCT
length : BYTE;
act_length : BYTE;
str : ARRAY [0..17] OF BYTE;
END_STRUCT;

tALicenseKey : ARRAY [0 .. 17 ] OF BYTE ;


IDB_Struct : STRUCT
ANY_id : WORD ;
Length : WORD ;
DB_Number : WORD ;
Byte_Pointer : DWORD ;
END_STRUCT ;
IDB_Struct_any AT IDB_Struct : ANY ;
END_VAR

BEGIN

RD_SINFO.RET_WERT := RD_SINFO(TOP_SI:=RD_SINFO.TOP_SI,
START_UP_SI:=RD_SINFO.START_UP_SI);

IF RD_SINFO.RET_WERT <> 0
THEN
ERROR:=true;
STATUS:=INT_TO_WORD(RD_SINFO.RET_WERT);
sSTATUS_FUNC:='RD_SINFO';
ELSE // call in cyclic OB (normal work)
IF RD_SINFO.TOP_SI.NUM=1 OR (BYTE_TO_INT(RD_SINFO.TOP_SI.NUM) >= 30 AND
BYTE_TO_INT(RD_SINFO.TOP_SI.NUM) <= 38)
THEN
BUSY:=false;
DONE_NDR:=false;
ERROR:=false;
STATUS:=W#16#0;
STATUS_FUNC:=' ';
STATUS_FUNC_b[1]:=B#16#0;
IF sSERVER_CLIENT
THEN
UNIT:=0;
DATA_TYPE:=0;
START_ADDRESS:=0;
LENGTH:=0;
WRITE_READ:=false;
END_IF;

IDB_Struct_any:=sIDB_Nr;

IF sIDB_Nr <> IDB_Struct.DB_Number OR sANLAUF_FEHLER


THEN
ERROR:=true;
IF sANLAUF_FEHLER
THEN
STATUS_FUNC:=sSTATUS_FUNC;
STATUS:=sSTATUS_TEMP;
ELSE
STATUS:=W#16#A080; // Different instance DBs were used for the call of MODBUSCP in
OB100 and the cyclic OB.
STATUS_FUNC:='MODBUSCP';
END_IF;
ELSE
IF NOT ERROR
THEN
IF NOT sSERVER_CLIENT
THEN
IF ENQ_ENR
THEN
TI:=DINT_TO_WORD(WORD_TO_DINT(TI)+1);
END_IF;
// call client
MB_CPCLI(
ID := WORD_TO_INT(sID)
,LADDR := sLADDR
,IDB_NR := WORD_TO_BLOCK_DB(sIDB_Nr)
,MONITOR := MONITOR
,ENQ_ENR := ENQ_ENR
,SERVER_CLIENT := sSERVER_CLIENT
,ANLAUF := sANLAUF
,SINGLE_WRITE := sSINGLE_WRITE
,DATA_AREAS := sDATA_AREAS
,SEND_BUFFER := sSEND_BUFFER
,RECV1_BUFFER := sRECV1_BUFFER
,RECV2_BUFFER := sRECV2_BUFFER
,AREA_VALID := sAREA_VALID
,UNIT := UNIT
,DATA_TYPE := DATA_TYPE
,START_ADDRESS := START_ADDRESS
,LENGTH := LENGTH
,TI := TI
,WRITE_READ := WRITE_READ
);

DONE_NDR := MB_CPCLI.DONE_NDR;
BUSY := MB_CPCLI.BUSY;
ERROR := MB_CPCLI.ERROR;
STATUS := MB_CPCLI.STATUS;
STATUS_FUNC := MB_CPCLI.STATUS_FUNC;

ELSE
// call server
MB_CPSRV(
ID := WORD_TO_INT(sID)
,LADDR := sLADDR
,IDB_NR := WORD_TO_BLOCK_DB(sIDB_Nr)
,MONITOR := MONITOR
,ENQ_ENR := ENQ_ENR
,DATA_AREAS := sDATA_AREAS
,SERVER_CLIENT := sSERVER_CLIENT
,ANLAUF := sANLAUF
,SEND_BUFFER := sSEND_BUFFER
,RECV1_BUFFER := sRECV1_BUFFER
,RECV2_BUFFER := sRECV2_BUFFER
);
UNIT := MB_CPSRV.UNIT;
DATA_TYPE := MB_CPSRV.DATA_TYPE;
START_ADDRESS := MB_CPSRV.START_ADDRESS;
LENGTH := MB_CPSRV.LENGTH;
TI := MB_CPSRV.TI;
WRITE_READ := MB_CPSRV.WRITE_READ;
DONE_NDR := MB_CPSRV.DONE_NDR;
BUSY := MB_CPSRV.BUSY;
ERROR := MB_CPSRV.ERROR;
STATUS := MB_CPSRV.STATUS;
STATUS_FUNC := MB_CPSRV.STATUS_FUNC;
END_IF;
sANLAUF:=false;
END_IF;
END_IF;

IF H_STATION = B#16#0
THEN // check if H-CPU
RDSYSST.RET_WERT:=RDSYSST( // Module identification
REQ := true
,SZL_ID := W#16#111 // W#16#0111: a single identification data record
,INDEX := W#16#1 // W#16#0001: identification of the module
,BUSY := RDSYSST.BUSY
,SZL_HEADER := RDSYSST.SZL_HEADER
,DR := CPU_DATA // Order number of the module; String consists of 19 characters and a blank
(20H); such as for CPU 314: "6ES7 314-0AE01-0AB0"
);
IF NOT RDSYSST.BUSY
THEN
IF RDSYSST.RET_WERT = 0
THEN
IF BYTE_TO_INT(CPU_DATA.CPUIdent[11]) = 72 // 'H' if H-CPU
THEN
H_STATION:= B#16#1;
H_STATION_TIME:=T#1M;
ELSE
H_STATION:=B#16#2;
H_STATION_TIME:=T#4S;
END_IF;
ELSE
ERROR:=true;
STATUS:=INT_TO_WORD(RDSYSST.RET_WERT);
STATUS_FUNC:='RDSYSST';
END_IF;
END_IF;
ELSE
j:=0;
REG_KEY_b.act_length:=B#16#11;
tSProductID:='MODCP2XV94501MB00';

IF (sSTATUS_TIMER AND W#16#60) <> W#16#0


THEN
IF (sSTATUS_TIMER AND W#16#20) <> W#16#0
THEN
RDSYSST.REQ:=true;
sSTATUS_TIMER:=sSTATUS_TIMER OR W#16#4000;
ELSE
RDSYSST.REQ:=false;
END_IF;

RDSYSST.RET_WERT:=RDSYSST(
REQ := RDSYSST.REQ
,SZL_ID := W#16#11C // SSL-ID W#16#xy1C - Component Identification
,INDEX := W#16#5 // W#16#0005: Serial number of the module
,BUSY := RDSYSST.BUSY
,SZL_HEADER := RDSYSST.SZL_HEADER
,DR := RDSYSST.SZL_11C_5
);
// Serial number OF the module; character STRING with MAX. length OF 24
// characters. Shorter numbers are filled with B#16#00.
// Note: This serial number is unique world-wide FOR SIMATIC components AND
// permanently associated TO the CPU hardware, that is, it remains unchanged
// when a firmware update is performed.
IF RDSYSST.RET_WERT<>0 AND
RDSYSST.RET_WERT<>129 AND // W#16#0081 Result field too short. (Nevertheless as many
data records as possible are supplied. The SSL header indicates this number.)
RDSYSST.RET_WERT<>-32638 AND // W#16#8082 SSL_ID is wrong or is unknown in the
CPU or SFC.
RDSYSST.RET_WERT<>-32637 // W#16#8083 INDEX wrong or not permitted.
THEN
IF RDSYSST.RET_WERT=-32635 // W#16#8085 Due to a problem in the system, information
is not currently available (for example, due to a lack of resources).
THEN
tSProductID:='CPU0 not reachable';

j:=BLKMOV(SRCBLK := tSProductID, DSTBLK := IDENT_CODE);


END_IF;

ERROR:=true;
STATUS:=INT_TO_WORD(RDSYSST.RET_WERT);
STATUS_FUNC:='RDSYSST';
ELSE
IF RDSYSST.BUSY
THEN
sSTATUS_TIMER:=(sSTATUS_TIMER AND W#16#FFBF) OR W#16#40;
ELSE
sSTATUS_TIMER:=sSTATUS_TIMER AND W#16#FF9F;

FOR i:= 0 TO 16 BY 1 DO
// result - string with symbols in range 'A'-'M'
sACODE[INT_TO_DINT(i)]:=INT_TO_BYTE(BYTE_TO_INT(CHAR_TO_BYTE(RDSYSST
.SZL_11C_5.serialn[INT_TO_DINT(i)]) XOR (tSProductID_b.str[INT_TO_DINT(i)])) MOD
13 + 65);
END_FOR;

sACODE[17]:=B#16#32; // '2'
j:=BLKMOV( SRCBLK := sACODE, DSTBLK := IDENT_CODE);

END_IF;
END_IF;
END_IF;

IF sACODE[17]=B#16#32 // '2'
THEN
reg:=0;

WHILE reg<=16 DO
IF REG_KEY_b.str[reg] <> sSTATUS_CODE_b.str[reg]
THEN
j:=BLKMOV(SRCBLK := IDENT_CODE, DSTBLK := sACODE );

IF j=0
THEN
FOR i:=0 TO 16 BY 1 DO
rcv_time:= SHL(IN:=B#16#1, N:=BYTE_TO_INT(INT_TO_BYTE(i) AND 7));

FOR k:=0 TO 7 BY 1 DO
snd_time:= SHL(IN:=B#16#1, N:=7-k);
pos:=i/8*8+k;

IF (tSProductID_b.str[i] AND snd_time) = snd_time


THEN
sHoldingRegisterState[pos]:=sHoldingRegisterState[pos] OR rcv_time ;

END_IF;
END_FOR;
END_FOR;

FOR i:=0 TO 16 BY 1 DO
tALicenseKey[i]:=(sACODE[i] XOR sHoldingRegisterState[i]) XOR INT_TO_BYTE(i+1);
tALicenseKey[i]:=INT_TO_BYTE(BYTE_TO_INT(tALicenseKey[i]) MOD 26 + 65); // 65='A'
END_FOR;

tALicenseKey[17]:=B#16#0;

FOR i:=0 TO 23 BY 1 DO
sHoldingRegisterState[i]:=B#16#0;
END_FOR;

j:=BLKMOV(SRCBLK :=REG_KEY,DSTBLK :=sACODE);

IF j=0
THEN
FOR i:=0 TO 16 BY 1 DO
IF tALicenseKey[i]<>sACODE[i]
THEN
sSTATUS_TIMER:=sSTATUS_TIMER AND W#16#FFFB;
LICENSED:=false;
EXIT;
END_IF;
IF i=16
THEN
sSTATUS_TIMER:=sSTATUS_TIMER OR W#16#4;
LICENSED:=true;
END_IF;
END_FOR;
END_IF;
END_IF;

j:=BLKMOV(SRCBLK := REG_KEY,DSTBLK := sSTATUS_CODE);


END_IF;
reg:=reg+1;
END_WHILE;
END_IF;

IF ((sSTATUS_TIMER AND W#16#4) = W#16#0) AND NOT sANLAUF_FEHLER


THEN

TON(IN := TON.IN ,PT := H_STATION_TIME);


TON.IN:=true;

IF TON.Q
THEN
TON.IN:=DB0.DBX0.0; //???????
TON.IN:=false;

sSTATUS_TEMP:=INT_TO_WORD(WR_USMSG(SEND := false
,EVENTN := W#16#A090 // The block MODBUSCP is not licensed for this CPU. This is a
status information. The bit ERROR is not set. The Modbus communication runs without a
license as well.
,INFO1 := sAREA_1
,INFO2 := sAREA_2
));

IF sSTATUS_TEMP<>W#16#0
THEN
ERROR:=true;
STATUS:=sSTATUS_TEMP;
STATUS_FUNC:='WR_USMSG';
END_IF;
END_IF;
IF STATUS = W#16#0 THEN STATUS:=W#16#A090; END_IF; // The block MODBUSCP is
not licensed for this CPU. This is a status information. The bit ERROR is not set. The Modbus
communication runs without a license as well.
END_IF;
IF j<>0
THEN
ERROR:=true;
STATUS:=W#16#A085;// An error occurred during the license handling due to an invalid write
access.
STATUS_FUNC:='MODBUSCP';
END_IF;
END_IF;
ELSE

// this part work in start OB100..OB102 (initialization)


IF BYTE_TO_INT(RD_SINFO.TOP_SI.NUM)>=100 AND
BYTE_TO_INT(RD_SINFO.TOP_SI.NUM)<=102
THEN
BUSY:=false;
DONE_NDR:=false;
ERROR:=false;
STATUS:=W#16#0;
STATUS_FUNC:=' ';
STATUS_FUNC_b[1]:=B#16#0;
IF sSERVER_CLIENT
THEN
UNIT:=0;
DATA_TYPE:=0;
START_ADDRESS:=0;
LENGTH:=0;
WRITE_READ:=false;
END_IF;
sANLAUF_FEHLER:=false;
sSTATUS_TEMP:=W#16#0;
sSTATUS_FUNC:='';
sSTATUS_CODE:='';

FOR i:=1 TO 8 BY 1 DO sAREA_VALID[i]:=false; END_FOR;

IF WORD_TO_INT(id)<=0 OR WORD_TO_INT(id)>64 // An invalid value id is


parameterized. Range of values is 1 to 64.
THEN
STATUS:=W#16#A07A;
ELSE

sID:=id;
sLADDR:=laddr;
sSERVER_CLIENT:=server_client;
sSINGLE_WRITE:=single_write;

IDB_Struct_any:=sIDB_Nr;
sIDB_Nr:=IDB_Struct.DB_Number;
IDB_Struct_any:=sdata_type_1;
sDATA_AREAS:=DWORD_TO_DINT(SHR(IN:=DW#16#FFFFFF AND
IDB_Struct.Byte_Pointer, N:=3));
IDB_Struct_any:=SEND_BUFFER[1];
sSEND_BUFFER:=DWORD_TO_DINT(SHR(IN:=DW#16#FFFFFF AND
IDB_Struct.Byte_Pointer, N:=3));

IDB_Struct_any:=RECV_BUFFER1[1];
sRECV1_BUFFER:=DWORD_TO_DINT(SHR(IN:=DW#16#FFFFFF AND
IDB_Struct.Byte_Pointer, N:=3));

IDB_Struct_any:=RECV_BUFFER2[1];
sRECV2_BUFFER:=DWORD_TO_DINT(SHR(IN:=DW#16#FFFFFF AND
IDB_Struct.Byte_Pointer, N:=3));

sdata_type_1 :=data_type_1;
sdb_1 :=db_1;
sstart_1 :=start_1;
send_1 :=end_1;
sdata_type_2 :=data_type_2;
sdb_2 :=db_2;
sstart_2 :=start_2;
send_2 :=end_2;
sdata_type_3 :=data_type_3;
sdb_3 :=db_3;
sstart_3 :=start_3;
send_3 :=end_3;
sdata_type_4 :=data_type_4;
sdb_4 :=db_4;
sstart_4 :=start_4;
send_4 :=end_4;
sdata_type_5 :=data_type_5;
sdb_5 :=db_5;
sstart_5 :=start_5;
send_5 :=end_5;
sdata_type_6 :=data_type_6;
sdb_6 :=db_6;
sstart_6 :=start_6;
send_6 :=end_6;
sdata_type_7 :=data_type_7;
sdb_7 :=db_7;
sstart_7 :=start_7;
send_7 :=end_7;
sdata_type_8 :=data_type_8;
sdb_8 :=db_8;
sstart_8 :=start_8;
send_8 :=end_8;

FOR i:= 1 TO 8 BY 1 DO
sDataType:=BYTE_TO_WORD(WORD_TO_BLOCK_DB(sIDB_Nr).DB[(i-
1)*8+sDATA_AREAS]);

IF WORD_TO_INT(sDataType)<0 OR WORD_TO_INT(sDataType)>4 THEN


STATUS:=W#16#A07C; EXIT; END_IF; // An invalid value data_type_x was given. The value
range is 0 to 4.
IF sDataType<>W#16#0
THEN
sAREA_VALID[i]:=true;
ELSE
IF i=1 THEN STATUS:=W#16#A07D; EXIT; END_IF; // Parameter data_type_1 is not
defined. The parameter area _1 is the default area and must be defined.
END_IF;
END_FOR;

FOR i:= 1 TO 8 BY 1 DO
IF sAREA_VALID[i]
THEN
sDataType:= BYTE_TO_WORD(WORD_TO_BLOCK_DB(sIDB_Nr).DB[(i-
1)*8+sDATA_AREAS]);
sStart_x:= WORD_TO_DINT(WORD_TO_BLOCK_DB(sIDB_Nr).DW[sDATA_AREAS+4+(i-
1)*8]);
sEnd_x:= WORD_TO_DINT(WORD_TO_BLOCK_DB(sIDB_Nr).DW[sDATA_AREAS+6+(i-
1)*8]);
IF sStart_x>sEnd_x THEN STATUS:=W#16#A002; EXIT; END_IF; // The parameter end_x is
less than start_x.
tDbNr:= WORD_TO_BLOCK_DB(sIDB_Nr).DW[sDATA_AREAS+2+(i-1)*8];
IF tDbNr=W#16#0 THEN STATUS:=W#16#A019; EXIT; END_IF; // 0 is assigned to one of
the parameters db_x while the according data_type_x is <> 0. DB 0 can’t be used; it is reserved
for system functions.
IF tDbNr=sIDB_Nr THEN STATUS:=W#16#A07E; EXIT; END_IF; // The DB number of
db_x is identical to the number of the instance DB.

FOR j:= i+1 TO 8 BY 1 DO


IF sAREA_VALID[j]
THEN

IF tDbNr=WORD_TO_BLOCK_DB(sIDB_Nr).DW[sDATA_AREAS+2+(j-1)*8] THEN
STATUS:=W#16#A010; EXIT; END_IF; // In the parameterized area db_1 to db_8 a DB
number is used twice.
sStart_y:=WORD_TO_DINT(WORD_TO_BLOCK_DB(sIDB_Nr).DW[sDATA_AREAS+4+(j-
1)*8]);
sEnd_y :=WORD_TO_DINT(WORD_TO_BLOCK_DB(sIDB_Nr).DW[sDATA_AREAS+6+(j-
1)*8]);

IF BYTE_TO_WORD(WORD_TO_BLOCK_DB(sIDB_Nr).DB[(j-
1)*8+sDATA_AREAS])=sDataType
THEN
IF (sStart_y>=sStart_x AND sStart_y<=sEnd_x) OR (sEnd_y>=sStart_x AND
sEnd_y<=sEnd_x)
THEN
STATUS:=SHL(IN:=INT_TO_WORD(i),N:=4) OR W#16#A000 OR INT_TO_WORD(j); // The
parameterized areas overlap.
EXIT;
END_IF;
END_IF;
END_IF;
END_FOR;

IF STATUS<>W#16#0 THEN EXIT; END_IF;


END_IF;
END_FOR;
END_IF;
IF STATUS <> W#16#0
THEN
ERROR:=true;
sANLAUF_FEHLER:=true;
sSTATUS_TEMP:=STATUS;
sSTATUS_FUNC:='MODBUSCP';
STATUS_FUNC:=sSTATUS_FUNC;
END_IF;
H_STATION:=B#16#0;
sSTATUS_TIMER:=sSTATUS_TIMER OR W#16#20;
sANLAUF:=true;
END_IF;
END_IF;
END_IF;

END_FUNCTION_BLOCK

Интересные места:

Определение выполнения программы на H-CPU


IF H_STATION = B#16#0
THEN // check if H-CPU
RDSYSST.RET_WERT:=RDSYSST( // Module identification
REQ := true
,SZL_ID := W#16#111 // W#16#0111: a single identification data record
,INDEX := W#16#1 // W#16#0001: identification of the module
,BUSY := RDSYSST.BUSY
,SZL_HEADER := RDSYSST.SZL_HEADER
,DR := CPU_DATA // Order number of the module; String consists of 19 characters and a blank
(20H); such as for CPU 314: "6ES7 314-0AE01-0AB0"
);
IF NOT RDSYSST.BUSY
THEN
IF RDSYSST.RET_WERT = 0
THEN
IF BYTE_TO_INT(CPU_DATA.CPUIdent[11]) = 72 // 'H' if H-CPU
THEN
H_STATION:= B#16#1;
H_STATION_TIME:=T#1M;

Чтение серийного номера модуля

RDSYSST.RET_WERT:=RDSYSST(
REQ := RDSYSST.REQ
,SZL_ID := W#16#11C // SSL-ID W#16#xy1C - Component Identification
,INDEX := W#16#5 // W#16#0005: Serial number of the module
,BUSY := RDSYSST.BUSY
,SZL_HEADER := RDSYSST.SZL_HEADER
,DR := RDSYSST.SZL_11C_5
);
// Serial number OF the module; character STRING with MAX. length OF 24
// characters. Shorter numbers are filled with B#16#00.
Неожиданно, немного магии в исходнике :):
m o d b u s

Чтобы это могло значить и зачем это? Непонятно...


Может быть у кого-то есть версии?
Upd: это необходимо для формировании ошибки обращения к блоку данных, для
подталкиванию к покупке лицензии :).

Проверка на идентичность:

m o d b u s

Block checksum оригинального и восстановленного блока совпадает.

Оригинальные блоки можно взять из проекта, с примерами их использования (zip, 3Mb)

You might also like