modbusOpen (Function)

Top  Previous  Next

Architecture:

X32 / NX32 / NX32L

Device support:

All devices with RS485

Firmware version:

1.50 / 1.00.00


This function will open a connection to a MODBUS RTU network.

 

The device supports both master mode, where the device controls the MODBUS network and polls the slaves, and slave mode, where the device waits for commands from the master.

 

 

Input:

mode : SINT (0/1)

0

- The RTCU device is master on the MODBUS network.

1

- The RTCU device is a slave on the MODBUS network.

 

unit_id : INT (1..247)

The address of the RTCU device on the MODBUS network.

Note: this parameter is ignored if mode is set to master.

 

port : DINT (0..2) (default 0)

Selects which serial port to use (see serial port enumeration).

 

baud : DINT (9600,19200,38400,57600,115200) (default 115200)

Selects the desired baud rate.

 

bit : SINT (7/8) (default 8)

Selects the number of bits per character.

Note: 7 bit only works when parity is used (even or odd).

 

parity : SINT (0..2) (default 1)

Selects the desired parity, 0 is none, 1 is even, and 2 is odd.

 

stopbit : SINT (1/2) (default 1)

Selects number of stop bits.

 
Note: Only 1 stop bit is supported on the RS485 ports on NX32L devices.

 

Returns: INT

ID of the MODBUS connection.

-2

- Illegal unit_id selected.

-5

- Illegal serial port.

-6

- All MODBUS connections are in use.

-7

- Illegal serial port parameters.

 

Declaration:

FUNCTION modbusOpen : INT;
VAR_INPUT
  mode   : INT;
  unit_id : INT;
  port   : DINT := 0;
  baud   : DINT := 115200;
  bit     : SINT := 8;
  parity : SINT := 1;
  stopbit : SINT := 1;
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;