物联网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月

  • 6
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论
Modbus是一种通信协议,用于在不同设备之间进行数据传输和通信。它广泛应用于工业自动化领域,包括监控和控制系统。 Modbus协议有多种变体,其两种常见的变体是Modbus TCPModbus RTUModbus TCP是基于传输控制协议TCP)的协议,而Modbus RTU使用串行通信接口,如RS-485或RS-232。 Modbus RTU协议是一种简单而高效的二进制协议。在Modbus RTU,数据以二进制形式通过串行线路传输。它使用Master-Slave模型,其Master设备发起请求,而Slave设备响应请求。 Modbus RTU协议的数据帧由多个字段组成,包括起始位、从站地址、功能码、数据字段、错误检测字段(CRC校验)和停止位。起始位用于同步设备之间的通信,从站地址用于标识Slave设备,功能码用于指定要执行的操作,数据字段包含实际数据,错误检测字段用于验证数据的完整性,停止位用于表示数据帧的结束。 对于Modbus TCP协议,数据通过以太网传输。与Modbus RTU相比,它使用了不同的数据帧格式,并且基于TCP/IP协议栈进行通信。Modbus TCP协议使用类似于Modbus RTU的功能码和数据字段,但在数据帧格式上有所不同。 总的来说,Modbus RTUModbus TCP是两种常见的Modbus协议变体,用于在不同设备之间进行通信。它们在通信介质、数据帧格式和传输方式等方面存在差异,但都用于实现设备之间的数据传输和控制。
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肖永威

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值