Âåðñèÿ äëÿ ïå÷àòè

MODBUS: èñõîäíèê ôóíêöèè MODBUSCP îáùèé

Äàòà: 2014-10-16

Äîáàâëåíî: komatic

Òåìà: SCL



Èëè ïðèìåð, êàê íóæíî ðåàëèçîâûâàòü ïðîòîêîë îáìåíà äàííûìè.



modbus



Îäíà èç òðåõ ôóíêöèé îò Siemens, îáåñïå÷èâàþùèõ îáìåí ïî ïðîòîêîëó Open MODBUS/TCP.
Áëîê âîññòàíîâëåí ïî çàêàçó.





Êðàòêîå îïèñàíèå.



Îäíà èç òðåõ ôóíêöèé îò Siemens, îáåñïå÷èâàþùèõ îáìåí ïî ïðîòîêîëó Open MODBUS/TCP.



modbus


Ïîäðîáíåå â îôèöèàëüíîé äîêóìåíòàöèè- (çàãðóçèòü 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)*8THEN 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.

Íåîæèäàííî, íåìíîãî ìàãèè â èñõîäíèêå :):



modbus

×òîáû ýòî ìîãëî çíà÷èòü è çà÷åì ýòî? Íåïîíÿòíî...
Ìîæåò áûòü ó êîãî-òî åñòü âåðñèè?
Upd: ýòî íåîáõîäèìî äëÿ ôîðìèðîâàíèè îøèáêè îáðàùåíèÿ ê áëîêó äàííûõ, äëÿ ïîäòàëêèâàíèþ ê ïîêóïêå ëèöåíçèè :).



Ïðîâåðêà íà èäåíòè÷íîñòü:





modbus

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?

Äîáàâèòü êîììåíòàðèé

Âàøå èìÿ:

Òåêñò êîììåíòàðèÿ (4000 max):

Ââåäèòå ñóììó ñ êàðòèíêè: