Java 整合 Modbus TCP

这篇具有很好参考价值的文章主要介绍了Java 整合 Modbus TCP。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Modbus协议

1.概述

概念

Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气 Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式。

优势

  • Modbus协议标准开放、公开发表且无版权要求

  • Modbus协议支持多种电气接口,包括RS232、RS485、TCP/IP等,还可以在各种介质上传输,如双绞线、光纤、红外、无线等

  • Modbus协议消息帧格式简单、紧凑、通俗易懂。用户理解和使用简单,厂商容易开发和集成,方便形成工业控制网络

通讯方式

1、ASCII模式
当控制器设为在Modbus网络上以ASCII模式通信,在消息中的每个8Bit字节都作为两个ASCII字符发送。这种方式的主要优点是字符发送的时间间隔可达到1秒而不产生错误。

2、RTU模式
当控制器设为Modbus网络上以RTU(远程终端单元)模式通信,在消息中的每个8Bit字节包含两个4Bit的十六进制字符。这种方式的主要优点是:在同样的波特率下,可比ASCII方式传送更多的数据。

3、Modbus TCP
在Modbus TCP/IP协议中,串行链路中的主/从设备分别演变为客户端/服务器端设备。即客户端相当于主站设备,服务器端相当于从站设备。基于TCP/IP网络的传输特性,串行链路上一主多从的构造也演变为多客户端/多服务器端的构造模型。Modbus TCP/IP服务器端通常使用端口502作为接收报文的端口, IANA(Internet Assigned Numbers Authority,互联网编号分配管理机构)给Modbus协议赋予TCP端口号为502,这是目前在仪表与自动化行业中唯一分配到的端口号。

2.组成

物理模型

modbus4j tcp,日常学习,物联网协议,java,tcp/ip,物联网

线圈寄存器:实际上就可以类比为开关量(继电器状态),每一个bit对应一个信号的开关状态。所以一个byte就可以同时控制8路的信号。比如控制外部8路io的高低。 线圈寄存器支持读也支持写,写在功能码里面又分为写单个线圈寄存器和写多个线圈寄存器。对应上面的功能码也就是:0x01 0x05 0x0f

离散输入寄存器:如果线圈寄存器理解了这个自然也明白了。离散输入寄存器就相当于线圈寄存器的只读模式,他也是每个bit表示一个开关量,而他的开关量只能读取输入的开关信号,是不能够写的。比如我读取外部按键的按下还是松开。所以功能码也简单就一个读的 0x02

保持寄存器:这个寄存器的单位不再是bit而是两个byte,也就是可以存放具体的数据量的,并且是可读写的。一般对应参数设置,比如我我设置时间年月日,不但可以写也可以读出来现在的时间。写也分为单个写和多个写,所以功能码有对应的三个:0x03 0x06 0x10

输入寄存器:这个和保持寄存器类似,但是也是只支持读而不能写,一般是读取各种实时数据。一个寄存器也是占据两个byte的空间。类比我我通过读取输入寄存器获取现在的AD采集值。对应的功能码也就一个 0x0

ModbusTCP数据帧: MBAP + PDU

MBAP(报文头)

内容 大小 描述
00 00 2字节 报文的序列号,一般通信之后要加1来区分不同的通信数据报文。
00 00 2字节 00 00标识Modus TCP协议
00 06 2字节 数据的长度,单位字节
01 1字节 设备地址

PDU(数据体)

功能码(1字节)+数据(不确定)

例如

​ 0x03 : 读保持寄存器

​ 请求:MBAP(7字节) 功能码(1字节) 起始地址(2字节) 寄存器数量(2字节)

​ 响应:MBAP(7字节) 功能码(1字节) 数据长度(1字节) 数据n个(2n字节)

​ 请求

00 01 00 00 00 06 01 03 00 00 00 03

00 01 :代表该连接的第1个请求

​ 00 00 :代表Modbus TCP协议

00 06 :后面数据长度,单位字节

01 :设备地址

03 :功能码

00 00 :起始地址

​ 00 03 :寄存器数量

​ 响应

00 01 00 00 00 09 01 03 06 00 21 00 00 00 00

​ 06 :后面数据长度

​ 00 21 00 00 00 00:标识三个寄存器中的值(00 21代表第一个,00 00 第二 , 00 00 第三个 )

功能码

0x01: 读线圈寄存器

0x02: 读离散输入寄存器

0x03: 读保持寄存器

0x04: 读输入寄存器

0x05: 写单个线圈寄存器

0x06: 写单个保持寄存器

0x0f:  写多个线圈寄存器

0x10: 写多个保持寄存器

3.虚拟机

下载地址 : Modbus Slave Sim V3.2 x 64

1.进入页面

modbus4j tcp,日常学习,物联网协议,java,tcp/ip,物联网

2.连接

modbus4j tcp,日常学习,物联网协议,java,tcp/ip,物联网

3.配置选择不同的寄存器/线圈

modbus4j tcp,日常学习,物联网协议,java,tcp/ip,物联网

4.Java实现

关于Modbus相关的jar包

  • Jamod:Java Modbus实现:Java Modbus库。该库由Dieter Wimberger实施。
  • ModbusPal:ModbusPal是一个正在进行的Java项目,用于创建逼真的Modbus从站模拟器。由于预定义的数学函数和/或Python脚本,寄存器值是动态生成的。ModbusPal依赖于RxTx进行串行通信,而Jython则依赖于脚本支持
  • Modbus4J:Serotonin Software用Java编写的Modbus协议的高性能且易于使用的实现。支持ASCII,RTU,TCP和UDP传输作为从站或主站,自动请求分区,响应数据类型解析和节点扫描
  • JLibModbus:JLibModbus是java语言中Modbus协议的一种实现。jSSC和RXTX用于通过串行端口进行通信。该库是一个经过积极测试和改进的项目。

代码使用 Modbus4J 来演示

引入Modbus4Jjar包

        <!-- Modbus -->
<dependencies>
        <dependency>
            <groupId>com.infiniteautomation</groupId>
            <artifactId>modbus4j</artifactId>
            <version>3.0.4</version>
        </dependency>
</dependencies>

<!-- 若想引用modbus4j需要引入下列repository id:ias-snapshots id:ias-releases 两个 ,使用默认仓库下载,不要使用阿里云仓库-->
<repositories>
        <repository>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
            <id>ias-snapshots</id>
            <name>Infinite Automation Snapshot Repository</name>
            <url>https://maven.mangoautomation.net/repository/ias-snapshot/</url>
        </repository>
        <repository>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <id>ias-releases</id>
            <name>Infinite Automation Release Repository</name>
            <url>https://maven.mangoautomation.net/repository/ias-release/</url>
        </repository>
    </repositories>

代码实现读取和写入



import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.locator.BaseLocator;
import com.serotonin.modbus4j.msg.*;

/**
 * Modbus 工具类
 */
public class ModbusUtils {

    /**
     * 工厂
     */
    static ModbusFactory modbusFactory;
    static ModbusMaster modbusMaster;
    static {
        if(modbusFactory == null){
            modbusFactory = new ModbusFactory();
        }
    }


    /**
     * 获取master
     * @return
     */
    public static ModbusMaster getMaster() throws ModbusInitException {
        if(modbusMaster == null){
            IpParameters ipParameters = new IpParameters();
            ipParameters.setHost("127.0.0.1");
            ipParameters.setPort(502);
            modbusMaster = modbusFactory.createTcpMaster(ipParameters, true);
            modbusMaster.init();
            return modbusMaster;
        }
        return modbusMaster;
    }


    /**
     * 读取线圈开关状态数据  0x01
     * @param slaveId
     * @param offset
     * @return
     * @throws ModbusInitException
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     */
    public static Boolean readCoilStatus(int slaveId,int offset) throws ModbusInitException, ModbusTransportException, ErrorResponseException {
        BaseLocator<Boolean> coilStatus = BaseLocator.coilStatus(slaveId, offset);
        Boolean res = getMaster().getValue(coilStatus);
        return res;
    }

    /**
     * 读离散输入寄存器状态数据  0x02
     * @param slaveId
     * @param offset
     * @return
     * @throws ModbusInitException
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     */
    public static Boolean inputStatus(int slaveId,int offset) throws ModbusInitException, ModbusTransportException, ErrorResponseException {
        BaseLocator<Boolean> inputStatus = BaseLocator.inputStatus(slaveId, offset);
        Boolean res = getMaster().getValue(inputStatus);
        return res;
    }

    /**
     * 读保持寄存器数据  0x03
     * @param slaveId
     * @param offset
     * @param dataType
     * @return
     * @throws ModbusInitException
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     */
    public static Number holdingRegister(int slaveId, int offset, int dataType) throws ModbusInitException, ModbusTransportException, ErrorResponseException {
        BaseLocator<Number> holdingRegister = BaseLocator.holdingRegister(slaveId, offset, dataType);
        Number value = getMaster().getValue(holdingRegister);
        return value;
    }

    /**
     * 读输入寄存器数据   0x04
     * @param slaveId
     * @param offset
     * @param dataType
     * @return
     * @throws ModbusInitException
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     */
    public static Number inputRegister(int slaveId, int offset, int dataType) throws ModbusInitException, ModbusTransportException, ErrorResponseException {
        BaseLocator<Number> inputRegister = BaseLocator.inputRegister(slaveId, offset, dataType);
        Number value = getMaster().getValue(inputRegister);
        return value;
    }


    /**
     * 写线圈开关状态数据  0x05
     * @param slaveId
     * @param offset
     * @param status
     * @return
     * @throws ModbusTransportException
     * @throws ModbusInitException
     */
    public static Boolean writeCoilStatus(int slaveId,int offset,boolean status) throws ModbusTransportException, ModbusInitException {
        boolean coilValue = status;
        WriteCoilRequest coilRequest = new WriteCoilRequest(slaveId, offset, coilValue);
        WriteCoilResponse coilResponse = (WriteCoilResponse) getMaster().send(coilRequest);
        return !coilResponse.isException();
    }


    /**
     * 写单个保持寄存器数据 0x06
     * @param slaveId
     * @param offset
     * @param vlaue
     * @return
     * @throws ModbusTransportException
     * @throws ModbusInitException
     */
    public static Boolean writeRegister(int slaveId,int offset,int vlaue) throws ModbusTransportException, ModbusInitException {
        WriteRegisterRequest registerRequest = new WriteRegisterRequest(slaveId,offset,vlaue);
        WriteRegisterResponse registerResponse = (WriteRegisterResponse) getMaster().send(registerRequest);
        return !registerResponse.isException();

    }

    /**
     * 写线圈开关状态数据【多】  0x0f
     * @param slaveId
     * @param offset
     * @param booleans
     * @return
     * @throws ModbusTransportException
     * @throws ModbusInitException
     */
    public static Boolean writeCoils(int slaveId,int offset,boolean[] booleans) throws ModbusTransportException, ModbusInitException {
        WriteCoilsRequest writeCoils = new WriteCoilsRequest(slaveId, offset, booleans);
        WriteCoilsResponse coilsResponse = (WriteCoilsResponse) getMaster().send(writeCoils);
        return !coilsResponse.isException();
    }


    /**
     * 写保存寄存器数据【多】  0x10
     * @param slaveId
     * @param offset
     * @param nums
     * @return
     * @throws ModbusTransportException
     * @throws ModbusInitException
     */
    public static Boolean writeRegisters(int slaveId,int offset,short[] nums) throws ModbusTransportException, ModbusInitException {
        WriteRegistersRequest writeRegisters = new WriteRegistersRequest(slaveId, offset, nums);
        WriteRegistersResponse registersResponse = (WriteRegistersResponse) getMaster().send(writeRegisters);
        return !registersResponse.isException();
    }




    public static void main(String[] args) throws ModbusInitException, ModbusTransportException, ErrorResponseException {
        // 01测试
//        Boolean v0001 = readCoilStatus(1, 0);
//        Boolean v0002 = readCoilStatus(1, 1);
//        Boolean v0008 = readCoilStatus(1, 7);
//        System.out.println("get v0001 :" + v0001);
//        System.out.println("get v0002 :" + v0002);
//        System.out.println("get v0008 :" + v0008);


        // 03测试
//        Number v0001 = holdingRegister(136, 3, DataType.TWO_BYTE_INT_SIGNED);
//        Number v0003 = holdingRegister(1, 2, DataType.TWO_BYTE_INT_SIGNED);
//        Number v0009 = holdingRegister(1, 8, DataType.TWO_BYTE_INT_SIGNED);
//        System.out.println("get v0001  result:" + v0001);
//        System.out.println("get v0003  result:" + v0003);
//        System.out.println("get v0009  result:" + v0009);

        // 04测试
//        Number v0001 = inputRegister(136, 0, DataType.TWO_BYTE_INT_SIGNED);
//        Number v0003 = inputRegister(136, 2, DataType.TWO_BYTE_INT_SIGNED);
//        Number v0009 = inputRegister(136, 8, DataType.TWO_BYTE_INT_SIGNED);
//        System.out.println("get v0001  result:" + v0001);
//        System.out.println("get v0003  result:" + v0003);
//        System.out.println("get v0009  result:" + v0009);


        // 05测试
//        Boolean v0001 = writeCoilStatus(1, 0, true);
//        Boolean v0002 = writeCoilStatus(1, 1, false);
//        Boolean v0007 = writeCoilStatus(1, 6, true);
//        System.out.println("update v0001 status result:" + v0001);
//        System.out.println("update v0002 status result:" + v0002);
//        System.out.println("update v0007 status result:" + v0007);


        // 06测试
//        Boolean v0001 = writeRegister(136, 0, 98);
//        Boolean v0002 = writeRegister(136, 1, 0);
//        Boolean v0007 = writeRegister(136, 6, 100);
//        System.out.println("update v0001 status result:" + v0001);
//        System.out.println("update v0002 status result:" + v0002);
//        System.out.println("update v0007 status result:" + v0007);


        // 0f测试
        //Boolean res1 = writeCoils(1, 1, new boolean[]{true, true, false, true});
        // 10测试
        //Boolean res2 = writeRegisters(136, 7, new short[]{1, 2, 3});
        //Boolean res3 = writeRegisters(136, 7, new short[]{991, 778, 25, 0});

    }


}

测试结果

​ 01测试 (读取线圈寄存器状态)

modbus4j tcp,日常学习,物联网协议,java,tcp/ip,物联网

 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Encap Request: 00 01 00 00 00 06 01 01 00 00 00 01 
 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Sending on port: 502
 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Response: 00 01 00 00 00 04 01 01 01 01 
 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Encap Request: 00 02 00 00 00 06 01 01 00 01 00 01 
 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Sending on port: 502
 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Response: 00 02 00 00 00 04 01 01 01 00 
 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Encap Request: 00 03 00 00 00 06 01 01 00 07 00 01 
 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Sending on port: 502
 [main] DEBUG com.serotonin.modbus4j.ip.tcp.TcpMaster - Response: 00 03 00 00 00 04 01 01 01 01 
get v0001 :true
get v0002 :false
get v0008 :true

读取对应的寄存器/线圈 系统中能获取到模拟器中的数据。

写入对应的寄存器/线圈 模拟器中的数据也会发生变化。文章来源地址https://www.toymoban.com/news/detail-541191.html

到了这里,关于Java 整合 Modbus TCP的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • springboot整合neo4j-使用原生cypher Java API

    该文的实现有更简单的方式,详见我的另一篇博客springboot整合neo4j–采用Neo4jClient和Neo4jTemplate方式 Neo4j 提供 JAVA API 以编程方式执行所有数据库操作。它支持三种类型的API: 1、Neo4j 原生的 Java API 原生 Java API 是一种低级别的纯 JAVA API,用于执行数据库操作。 2、Neo4j Cypher Jav

    2024年02月09日
    浏览(53)
  • Java也能做OCR!SpringBoot 整合 Tess4J 实现图片文字识别

    先简单给没听过的xdm解释下,这里要分清楚Tesseract和Tess4j的区别。 Tesseract是一个开源的光学字符识别(OCR)引擎,它可以将图像中的文字转换为计算机可读的文本。支持多种语言和书面语言,并且可以在命令行中执行。它是一个流行的开源OCR工具,可以在许多不同的操作系统

    2024年02月04日
    浏览(37)
  • Modbus tcp转ETHERCAT网关modbus tcp/ip协议

    捷米JM-ECT-TCP网关能够连接到Modbus tcp总线和ETHERCAT总线中,实现两种不同协议设备之间的通讯。这个网关能够大大提高工业生产的效率和生产效益,让生产变得更加智能化。捷米JM-ECT-TCP 是自主研发的一款 ETHERCAT 从站功能的通讯网关。该产品主要功能是将 ETHERCAT 网络和 MODB

    2024年02月15日
    浏览(78)
  • Modbus TCP转Profinet网关modbus tcp转以太网

    大家好,今天我们来聊一聊如何使用捷米特的Profinet转modbusTCP协议转换网关在博图上进行非透传型配置。 1, 首先,我们需要安装捷米特JM-TCP-PN的GSD文件,并根据现场设备情况配置modbusTCP地址。然后,在博图中添加该GSD文件,并根据实际需求对数据进行图形化配置。比如,我们

    2024年02月14日
    浏览(48)
  • Linux网络高级——Modbus TCP及Modbus库

    Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气 Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式。 Modbus协议是一项应用层报文传输协议,包

    2024年02月12日
    浏览(38)
  • PMAC与Modbus主站进行Modbus Tcp通讯

    在项目的PMAC Script LanguageGlobal Includes下创建一个名为00_Modbus_Para.pmh的pmh文件。 具体的参数查看手册,样例使用的是本机的回环地址。 在C LanguageBackground Programs下添加一个后台C应用程序,名为capp1。在capp1文件夹下创建一个capp1.c的source文件。 在PMAC Script LanguagePLC Programs文件夹

    2024年02月11日
    浏览(35)
  • 嵌入式通信协议【Modbus】Modbus TCP的帧格式

    Client request:例: 19 B2 00 00 00 06 06 03 00 27 00 02 上面是modbus客户端发出的报文内容,为modbus tcp/ip协议格式,其前面的六个字节为头字节( header handle); 19 B2 00 00 00 06 19 B2  00 00 00 06 两个Client发出的检验信息,Sever端只是需要将这两个字节的内容copy以后再放到response的报文的相应位

    2024年02月05日
    浏览(85)
  • modbus TCP 应用

    Modbus TCP 应用介绍 Modbus TCP/IP 协议是工业通信系统领域的基石。它是一种与以太网结合使用的应用层消息传递协议,可实现不同类型网络上连接的设备之间的客户端/服务器通信。Modbus 最初是一种 Modbus 串行协议 (Modbus RTU),现已发展到包含 TCP/IP 等现代技术,在从楼宇自动化和

    2024年02月03日
    浏览(34)
  • Modbus tcp和Tcp/ip有什么区别

             Modbus TCP是一种基于TCP/IP协议的应用层协议 ,它是Modbus协议的扩展。Modbus协议是一种串行通信协议,最初是由Modicon公司在1979年开发的,用于工业自动化控制系统中设备之间的通信。 Modbus TCP则是将Modbus协议转换为基于以太网的TCP/IP协议 ,以支持更广泛的设备和系

    2024年02月10日
    浏览(41)
  • Modbus TCP通信协议详解

    一、Modbus TCP通信概述 MODBUS/TCP是简单的、中立厂商的用于管理和控制自动化设备的MODBUS系列通讯协议的派生产品,显而易见,它覆盖了使用TCP/IP协议的“Intranet”和“Internet”环境中MODBUS报文的用途。协议的最通用用途是为诸如PLC,I/O模块,以及连接其它简单域总线或I/O模块的

    2024年02月08日
    浏览(161)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包