作者

胡盛生

推荐理由

modbus协议概念特点以及java实现的整理,对于入门有一定的参考意义。
Modbus协议简介

Modbus是一种通讯协议,主要应用于电子控制器上的一种通用语言。Modbus支持多种电气接口,如RS232、RS485、TCP/IP等。多数Modbus设备通信是通过串口或TCP/IP进行连接。

通常情况下 Modbus是主从架构,即通信节点是Master,其它使用Modbus协议参与通信的是slave节点(最多247个,地址范围为1-247,0节点是广播地址)。每个slave设备都具有一个唯一的地址。总线上只能有一个Master节点。

javabus有新地址吗,上不了 javabus地址多少_物联网

Modbus寄存器介绍所有数据都存在寄存器中,寄存器可指物理寄存器,也可是一块内存区域。Modbus根据数据类型及各自读写特性,将寄存器分为了4个部分,分别如下。

javabus有新地址吗,上不了 javabus地址多少_上不了_02

Modbus消息结构

Modbus功能码介绍

功能码由1个字节构成,因此取值范围1-255。常用功能码如下:

01:读线圈状态

02:读输入状态

03:读保持寄存器

04:读输入寄存器

05:强制单线圈

06:预制单寄存器

15:强制多线圈

17:报告从设备ID

22:屏蔽写寄存器

23:读/写寄存器

Modbus TCP消息结构

javabus有新地址吗,上不了 javabus地址多少_客户端_03

传输标识:Transaction Identifier。占用2个字节。标记某个Modbus 查询/应答的传输过程,可设置为0,每次通讯+1;由客户端生成(主站设备),应答时复制该值。

协议标识:Protocol Identifier。占用2个字节。 Modbus协议为 0x00。由客户端生成,应答时复制该值。

字节长度:Length。占用2个字节。高4位为设置为0X00,因此后续字节必须在256个字节内;第四位记录后续的字节个数;由客户端生成(主站设备),应答时重新生成。

单位标识符:Unit Identifier。占用1个字节。用以识别从机设备。由客户端生成,应答时复制该值。

javabus有新地址吗,上不了 javabus地址多少_物联网_04


设备地址:从设备的地址编号

CRC校验:用来确认接收消息完整性和正确性

Java代码取值实现

网上有许多开源的modbos工具包,例如modbus4j、jamod等。这里选用jamod,以Modbus RTU通讯为例

maven依赖如下,同时需要在C://Windows//System32目录下,放入RXTXcomm.jar、rxtxParallel.dll、rxtxSerial.dll三个文件,用来实现串口通信

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

<dependency>

    <groupId>net.wimpi</groupId>

    <artifactId>jamod</artifactId>

    <version>1.2</version>

</dependency>

创建和串口的连接

public class ModBusConnection {

 

    public static SerialConnection getSerialConnection() throws Exception {

        SerialParameters parameters = new SerialParameters();

        // 串口名称

        parameters.setPortName("COM2");

        // 波特率

        parameters.setBaudRate(9600);

        // 数据位8位

        parameters.setDatabits(SerialPort.DATABITS_8);

        // 停止位2位

        parameters.setStopbits(SerialPort.STOPBITS_2);

        // 无奇偶校验位

        parameters.setParity(SerialPort.PARITY_NONE);

        // rtu模式,取代默认的ascii模式

        parameters.setEncoding("rtu");

 

        SerialConnection connection = new SerialConnection(parameters);

        connection.open();

        return connection;

    }

 

}

创建request取数工具类

public class ModBusUtil {

 

    /**

     * 读写 boolean类型 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();

    }

 

    /**

     * 只读 boolean类型 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();

    }

 

    /**

     * 读写 int类型 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();

    }

 

    /**

     * 只读 int类型 function code 04

     * @param connection con

     * @param param param

     * @return InputRegister

     */

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

 

        // 寄存器地址编号  属性数据数量

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

        // 从设备编号

        request.setUnitID(param.getSlaveId());

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

        return response.getRegisters();

    }

 

    /**

     * 获取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方法测试类

public class SerialPortTest {

 

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

 

        SerialConnection connection = ModBusConnection.getSerialConnection();

        ModBusRequest param = new ModBusRequest();

        // 从设备id编号

        param.setSlaveId(1);

        // 寄存器地址编号 这边使用了function 01,addressNo=0表示寄存器地址为00001

        param.setAddressNo(0);

        // 读取数据个数

        param.setWordCount(1);

 

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

        for (InputRegister register : registers) {

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

        }

 

        connection.close();

    }

 

}

javabus有新地址吗,上不了 javabus地址多少_客户端_05