MODBUS: èñõîäíèê ôóíêöèè MODBUSCP îáùèé
Äàòà: 2014-10-16
Äîáàâëåíî: komatic
Òåìà: SCL
Èëè ïðèìåð, êàê íóæíî ðåàëèçîâûâàòü ïðîòîêîë îáìåíà äàííûìè.
Îäíà èç òðåõ ôóíêöèé îò Siemens, îáåñïå÷èâàþùèõ îáìåí ïî ïðîòîêîëó Open MODBUS/TCP.
Áëîê âîññòàíîâëåí ïî çàêàçó.
Êðàòêîå îïèñàíèå.
Îäíà èç òðåõ ôóíêöèé îò Siemens, îáåñïå÷èâàþùèõ îáìåí ïî ïðîòîêîëó Open MODBUS/TCP.
Ïîäðîáíåå â îôèöèàëüíîé äîêóìåíòàöèè- (çàãðóçèòü 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.
Íåîæèäàííî, íåìíîãî ìàãèè â èñõîäíèêå :):
×òîáû ýòî ìîãëî çíà÷èòü è çà÷åì ýòî? Íåïîíÿòíî...
Ìîæåò áûòü ó êîãî-òî åñòü âåðñèè?
Upd: ýòî íåîáõîäèìî äëÿ ôîðìèðîâàíèè îøèáêè îáðàùåíèÿ ê áëîêó äàííûõ, äëÿ ïîäòàëêèâàíèþ ê ïîêóïêå ëèöåíçèè :).
Ïðîâåðêà íà èäåíòè÷íîñòü:
Block checksum îðèãèíàëüíîãî è âîññòàíîâëåííîãî áëîêà ñîâïàäàåò.
Îðèãèíàëüíûå áëîêè ìîæíî âçÿòü èç ïðîåêòà, ñ ïðèìåðàìè èõ èñïîëüçîâàíèÿ (zip, 3Mb)
Ïðîñìîòðîâ: 32259
Êîììåíòàðèè ê ìàòåðèàëó
Äîáàâëåí: Control Äàòà: 2017-02-04
After compile, i don't have same block checksum as yours and siemens 0x0DCA.
Äîáàâëåí: Majk Äàòà: 2017-09-05
ñïàñèáà áîëøîå!
Äîáàâëåí: Petr Äàòà: 2019-06-17
Çäðàâñòâóéòå.
Ïîäñêàæèòå, êàê âû ïîëó÷èëè èñõîäíûé êîä MODBUSCP â SCL? Çàùèòó ÿ ñ MODBUSCP ñíÿë, íî êàê äàëüøå ïîëó÷èòü SCL?
Äîáàâèòü êîììåíòàðèé