modbusSend (Function)

Top  Previous  Next

Architecture:

X32 / NX32 / NX32L

Firmware version:

1.50 / 1.00.00


This function will send a package to a device on a MODBUS connection.

 

Input:

net_id : INT

The ID of the MODBUS connection.

 

unit_id : INT

The address of the device on the MODBUS connection to receive the data.

Note: if the MODBUS connection is opened in slave mode, this parameter is ignored.

 

ip : DINT

The IP address of the receiving device. This parameter is only used by MODBUS TCP connections.

Note: if the MODBUS connection is opened in slave mode, this parameter is ignored.

 

port : DINT (default 502)

The IP port of the receiving device. This parameter is only used by MODBUS TCP connections.

Note: if the MODBUS connection is opened in slave mode, this parameter is ignored.

 

iface : SINT (default 2)

The network interface to use. 1 = Cellular network, 2 = LAN network, etc. (See Network)

This parameter is only used on NX32L devices for MODBUS TCP connections.

Note: if the MODBUS connection is opened in slave mode, this parameter is ignored.

 

tid : DINT

The transaction ID of the package. This parameter is only used by MODBUS TCP connections.

 

frame : PTR

Address of the buffer that contains the package to send.

 

size : INT (1..253)

Number of bytes to send from the buffer.

 

 

Returns: INT

0

- Success.

-1

- Illegal MODBUS connection ID.

-2

- The size is too large.

-3

- No data to send.

-4

- MODBUS connection is busy.

-5

- Illegal IP parameters. (MODBUS TCP only)

-6

- TCP communication error. (MODBUS TCP only)

 

Declaration:

FUNCTION modbusSend;
VAR_INPUT
   net_id  : INT;
   unit_id : INT;
   frame   : PTR;
   size    : INT;
   ip      : DINT;
   port    : DINT;
   iface   : SINT;
   tid     : DINT;
END_VAR;

 

 

Example:

INCLUDE rtcu.inc
 
VAR
   mbNet : INT;
   mbRcv : modbusReceive;
END_VAR;
 
FUNCTION setINT;
VAR_INPUT
   adr : PTR;
   v   : INT;
END_VAR;
   memcpy(dst := adr + 1, src := ADDR(v)    , len := 1);
   memcpy(dst := adr    , src := ADDR(v) + 1, len := 1);
END_FUNCTION;
 
FUNCTION_BLOCK modbusReadDiscreteInputs;
VAR_INPUT
   net_id  : INT;
   unit_id : INT;
   index   : INT;
   length  : INT;
END_VAR;
VAR_OUTPUT
   status : INT;
   size   : INT;
   input  : ARRAY[1..32] OF BOOL;
END_VAR;
VAR
   rc, i  : INT;
   buf    : ARRAY[1..253] OF SINT;
   mask   : SINT;
END_VAR;
 
   // Check length
   IF length < 1 OR length > 32 THEN
      status := 1;
      RETURN;
   END_IF;
   IF index < 1 THEN
      status := 2;
      RETURN;
   END_IF;
 
   // Build command
   buf[1] := 16#02;
   setINT(adr := ADDR(buf[2]), v := index - 1);
   setINT(adr := ADDR(buf[4]), v := length);
 
   // Send command
   rc := modbusSend(net_id := net_id, unit_id := unit_id, frame := ADDR(buf), size := 5);
   IF rc <> 0 THEN
      status := 3;
      RETURN;
   END_IF;
 
   // Wait for reply
   IF NOT modbusWaitData(net_id := net_id, timeout := 5000) THEN
      status := 4;
      RETURN;
   END_IF;
 
   // Read reply
   mbRcv(net_id := net_id, frame := ADDR(buf), maxsize := SIZEOF(buf));
   IF mbRcv.status <> 0 THEN
      status := 5;
      RETURN;
   END_IF;
   IF mbRcv.unit_id <> unit_id THEN
      status := 6;
      RETURN;
   END_IF;
   IF buf[1] <> 16#02 THEN
      status := 7;
      RETURN;
   END_IF;
 
   // Parse reply
   mask := 1;
   FOR i := 1 TO length DO
      input[i] := BOOL(buf[3 + ((i - 1) / 8)] AND mask);
      mask := shl8(in := mask, n := 1);
      IF mask = 0 THEN mask := 1; END_IF;
   END_FOR;
   size   := length;
   status := 0;
END_FUNCTION_BLOCK;
 
PROGRAM ModbusExample;
VAR
   dinRead : modbusReadDiscreteInputs;
   linsec  : DINT;
   i       : INT;
END_VAR;
 
   DebugMsg(message := "Initializing...");
   mbNet := modbusOpen(port := 2, baud := 19200, parity := 0, mode := 0);
   DebugFmt(message := "modbus...\1", v1 := mbNet);
 
BEGIN
   IF clockNow() > linsec THEN
      DebugMsg(message := "------------------------------");
      DebugMsg(message := "Reading inputs:");
      dinRead(net_id := mbNet, unit_id := 9, index := 1, length := 4);
      DebugFmt(message := "-status=\1", v1 := dinRead.status);
      IF dinRead.status = 0 THEN 
         FOR i := 1 TO dinRead.size DO
            DebugFmt(message := "-input[\1]=\2", v1 := i, v2 := INT(dinRead.input[i]));
         END_FOR;
      END_IF;
      // Set next reading
      linsec := clockNow() + 5;
   END_IF;
END;
END_PROGRAM;