物联网RTU(Modbus TCP协议)Java接口开发及Modbus Slave仿真使用

  在物联网体系中,经常用到RTU(远程终端单元),RTU是负责对现场信号、工业设备的监测和控制,通常由信号输入/出模块、微处理器、有线/无线通讯设备、电源及外壳等组成,由微处理器控制,并支持网络系统。

  在物联网应用平台上,需要通过RTU与现场设备对接,采集现场数据、控制设备,通过网络与RTU连接,主要是采用Modbus TCP协议。

  Modbus是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。它已经成为一种通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一个控制器请求访问其它设备的过程,如何回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。

  物联网应用软件开发,需要与RTU接口,为了方便软件开发,降低对物联网设备的依赖,Modbus仿真软件也就出现,对此,物联网开发人员应该很熟悉,但是对于普通互联网开发人员,还是很陌生的,为此,此文介绍ModbusTCP仿真软件使用和基于Netty的RTU java接口开发。

1、ModbusTCP仿真

  ModbusSlave(软件官方网站地址)是一个从站设备仿真软件,它用于接收主设备的命令包,并回送数据包;可用于测试和调试Modbus主站设备,便于观察Modbus通信过程中的各种报文。ModbusPoll及ModbusSlave支持ModbusRTU, ASCII,TCP/IP等协议。

  首先,了解MODBUS支持的部分功能代码,以十进制表示,如下表所示。

代码 中文名称 英文名称 位操作/字操作 操作数量
01 读线圈状态 READ COIL STATUS 位操作 单个或多个
02 读离散输入状态 READ INPUT STATUS 位操作 单个或多个
03 读保持寄存器 READ HOLDING REGISTER 字操作 单个或多个
04 读输入寄存器 READ INPUT REGISTER 字操作 单个或多个
05 写线圈状态 WRITE SINGLE COIL 位操作 单个
06 写单个保持寄存器 WRITE SINGLE REGISTER 字操作 单个
15 写多个线圈 WRITE MULTIPLE COIL 位操作 多个
16 写多个保持寄存器 WRITE MULTIPLE REGISTER 字操作 多个

  参数设置:
  点击菜单“Setup”中“Slave Definition.. F2”进行参数设置,会弹出如下图对话框

这里写图片描述

  其中:
  (1)Slave ID:设备ID;
  (2)Function:对应上表所对应的Modbus功能,例如本文所选用的“03 Holding Register…”,与下文Java代码“见类ReadHoldingRegistersResponse ”所对应
  (3)Address:寄存器地址;
  (4)Quantity:数量。

  打开ModbusSlave软件,为方便起见,本文采用默认的地址(localhost,与下文第二段代码对应“见类ClientForTests ”),功能码,寄存器数量,单击Connection->connect,在弹出的窗口设置connection为TCP/IP,端口Port设置为30502,点击OK,如下图所示,从端配置完毕。

这里写图片描述

  注意:
  (1)本文连接Connection采用Modbus TCP/IP协议;
  (2)网络地址为本地地址,127.0.0.1;
  (3)端口与下文第二段代码“见类ClientForTests”中的地址和端口设置为“30502”;
  (4)选择“Ignore Unit ID”,如果不选择,测试程序返回空值。

2、基于Netty实现RTU接口

  本文Java代码,来源于modjn(https://github.com/klymenek/modjn),基于Netty 4.x实现Modbus TCP客户端和服务端(Modbus TCP client/server implementation in Java with Netty 4.x)。

package de.gandev.modjn.example;

import de.gandev.modjn.ModbusClient;
import de.gandev.modjn.entity.exception.ConnectionException;
import de.gandev.modjn.entity.exception.ErrorResponseException;
import de.gandev.modjn.entity.exception.NoResponseException;
import de.gandev.modjn.entity.func.response.ReadCoilsResponse;
import de.gandev.modjn.entity.func.response.ReadHoldingRegistersResponse;

import java.util.logging.Level;
import java.util.logging.Logger;
/**
 * @author XiaoYW
 *
 */
public class TestModbusSlave {

    public static void main(String[] args) {
        ModbusClient modbusClient = ClientForTests.getInstance().getModbusClient();

        ReadCoilsResponse readCoils = null;
        try {
            readCoils = modbusClient.readCoils(12321, 5);
        } catch (NoResponseException | ErrorResponseException | ConnectionException ex) {
            Logger.getLogger(Example.class.getName()).log(Level.SEVERE, ex.getLocalizedMessage());
        }
        System.out.println(readCoils);

        ReadHoldingRegistersResponse readHolding = null; 
        try {
            readHolding = modbusClient.readHoldingRegisters(2200,10);
        } catch (NoResponseException | ErrorResponseException | ConnectionException ex) {
            Logger.getLogger(Example.class.getName()).log(Level.SEVERE, ex.getLocalizedMessage());
        }
        System.out.println(readHolding);
        modbusClient.close();
    }
}

  客户端测试代码,如下文所示。

package de.gandev.modjn.example;

import de.gandev.modjn.ModbusClient;
import de.gandev.modjn.entity.exception.ConnectionException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author ares
 */
public class ClientForTests {

    private final ModbusClient modbusClient;

    private ClientForTests() {
        modbusClient = new ModbusClient("localhost" /*
                 * "192.168.1.55"
                 */, 30502); //ModbusConstants.MODBUS_DEFAULT_PORT);

        try {
            modbusClient.setup();
        } catch (ConnectionException ex) {
            Logger.getLogger(ClientForTests.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public ModbusClient getModbusClient() {
        return modbusClient;
    }

    public static ClientForTests getInstance() {
        return ClientAndServerHolder.INSTANCE;
    }

    private static class ClientAndServerHolder {

        private static final ClientForTests INSTANCE = new ClientForTests();
    }
}

这里写图片描述

  以Java应用程序运行,运行结果:

ReadCoilsResponse{byteCount=1, coilStatus={0, 3}}
ReadHoldingRegistersResponse{byteCount=20, 
inputRegisters={register_0=2, register_1=0, register_2=0, register_3=3, register_4=0, register_5=0, register_6=8, register_7=0, register_8=0, register_9=0}}

参考:

《谈谈基于Netty实现Restful搭建服务架构思路》 CSDN博客 肖永威 2018年7月
《Modbus学习总结》 CSDN博客 深之JohnChen的专栏 2017年9月

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值