Introduction to Modbus protocol and implementation of Java code

author

Sheng Sheng Hu

Reasons for recommendation

The concept and characteristics of modbus protocol and the arrangement of java implementation have certain reference significance for entry.
Introduction to Modbus Protocol

Modbus is a communication protocol, which is a general language mainly used in electronic controllers. Modbus supports a variety of electrical interfaces, such as RS232, RS485, TCP/IP, etc. Most MODBUS device communication is connected through serial port or TCP/IP.

In general, MODBUS is the Master-slave architecture, that is, the communication node is the Master, and other slave nodes that use Modbus protocol to participate in communication (up to 247, the address range is 1-247, and node 0 is the broadcast address). Each slave device has a unique address. There can only be one Master node on the bus.
Introduction to Modbus register

All data is stored in registers, which can refer to physical registers or a memory area. Modbus divides the register into four parts according to the data type and their reading and writing characteristics, as follows.
Modbus message structure

Introduction to Modbus function code

The function code is composed of 1 byte, so the value range is 1-255. Common function codes are as follows:

01: read coil status

02: read input status

03: read hold register

04: read input register

05: forced single coil

06: Prefabricated single register

15: Forced multi coil

17: Report slave device ID

22: Mask write register

23: read / write register

Modbus TCP message structure
Transmission ID: Transaction Identifier. Occupy 2 bytes. Mark the transmission process of a Modbus query / response, which can be set to 0 and + 1 for each communication; It is generated by the client (master station equipment), and the value is copied when answering.

Protocol Identifier: Protocol Identifier. Occupy 2 bytes. The Modbus protocol is 0x00. Generated by the client and copied when answering.

Byte Length: Length. Occupy 2 bytes. The upper 4 bits are set to 0X00, so the subsequent bytes must be within 256 bytes; The number of subsequent bits of the record; Generated by the client (master station equipment) and regenerated when answering.

Unit Identifier: Unit Identifier. Occupy 1 byte. Used to identify slave devices. Generated by the client and copied when answering.

Device address: the address number of the slave device

CRC verification: used to confirm the integrity and correctness of received messages

Java code implementation

There are many open source modbos toolkits on the Internet, such as modbus4j, jamod, etc. Jamod is selected here, taking Modbus RTU communication as an example

maven depends on the following. At the same time, rxtxcomm jar,rxtxParallel.dll,rxtxSerial.dll three files, used to achieve serial communication

<!-- https://mvnrepository.com/artifact/net.wimpi/jamod -->

<dependency>

    <groupId>net.wimpi</groupId>

    <artifactId>jamod</artifactId>

    <version>1.2</version>

</dependency>

Create connection with serial port

public class ModBusConnection {

 

    public static SerialConnection getSerialConnection() throws Exception {

        SerialParameters parameters = new SerialParameters();

        // Serial port name

        parameters.setPortName("COM2");

        // Baud rate

        parameters.setBaudRate(9600);

        // Data bit 8 bits

        parameters.setDatabits(SerialPort.DATABITS_8);

        // Stop bit 2 bits

        parameters.setStopbits(SerialPort.STOPBITS_2);

        // No parity bit

        parameters.setParity(SerialPort.PARITY_NONE);

        // rtu mode, replacing the default ascii mode

        parameters.setEncoding("rtu");

 

        SerialConnection connection = new SerialConnection(parameters);

        connection.open();

        return connection;

    }

 

}

Create request fetching tool class

public class ModBusUtil {

 

    /**

     * Read / write boolean type function code 01

     * @param connection con

     * @param param param

     * @return BitVector

     */

    public static BitVector readCoils(SerialConnection connection, ModBusRequest param) throws Exception {

 

        ReadCoilsRequest request = new ReadCoilsRequest(param.getAddressNo(), param.getWordCount());

        request.setUnitID(param.getSlaveId());

 

        ReadCoilsResponse response = (ReadCoilsResponse) getResponse(connection, request);

        return response.getCoils();

    }

 

    /**

     * Read only boolean type function code 02

     * @param connection con

     * @param param param

     * @return BitVector

     */

    public static BitVector readInputDiscretes(SerialConnection connection, ModBusRequest param) throws Exception {

        ReadInputDiscretesRequest request = new ReadInputDiscretesRequest(param.getAddressNo(), param.getWordCount());

        request.setUnitID(param.getSlaveId());

 

        ReadInputDiscretesResponse response = (ReadInputDiscretesResponse) getResponse(connection, request);

        return response.getDiscretes();

    }

 

    /**

     * Reading and writing int type function code 03

     * @param connection con

     * @param param param

     * @return InputRegister

     */

    public static InputRegister[] readMultipleRegisters(SerialConnection connection, ModBusRequest param) throws Exception {

        ReadMultipleRegistersRequest request = new ReadMultipleRegistersRequest(param.getAddressNo(), param.getWordCount());

        request.setUnitID(param.getSlaveId());

 

        ReadMultipleRegistersResponse response = (ReadMultipleRegistersResponse) getResponse(connection, request);

        return response.getRegisters();

    }

 

    /**

     * Read only int type function code 04

     * @param connection con

     * @param param param

     * @return InputRegister

     */

    public static InputRegister[] readInputRegisters(SerialConnection connection, ModBusRequest param) throws Exception {

 

        // Register address number attribute data quantity

        ReadInputRegistersRequest request = new ReadInputRegistersRequest(param.getAddressNo(), param.getWordCount());

        // Slave device number

        request.setUnitID(param.getSlaveId());

        ReadInputRegistersResponse response = (ReadInputRegistersResponse) getResponse(connection, request);

        return response.getRegisters();

    }

 

    /**

     * Get response

     * @param connection con

     * @param request req

     * @return ModbusResponse

     */

    private static ModbusResponse getResponse(SerialConnection connection, ModbusRequest request) throws Exception {

        ModbusSerialTransaction transaction = new ModbusSerialTransaction(connection);

        transaction.setRequest(request);

        transaction.execute();

        return transaction.getResponse();

    }

 

}

main method test class

public class SerialPortTest {

 

    public static void main(String[] args) throws Exception {

 

        SerialConnection connection = ModBusConnection.getSerialConnection();

        ModBusRequest param = new ModBusRequest();

        // Slave device id number

        param.setSlaveId(1);

        // function 01 is used for the register address number. addressNo=0 indicates that the register address is 00001

        param.setAddressNo(0);

        // Number of read data

        param.setWordCount(1);

 

        InputRegister[] registers = ModBusUtil.readInputRegisters(connection, param);

        for (InputRegister register : registers) {

            System.out.println(register.getValue());

        }

 

        connection.close();

    }

 

}

Tags: Java IoT

Posted by jtacon on Mon, 16 May 2022 07:40:41 +0300