精华内容
下载资源
问答
  • ModbusTCP通讯协议学习及实践(台达&三菱PLC通讯)
    千次阅读
    2020-11-08 17:09:12

    1.简述

    工业控制中一般采用PLC进行一些简单的运动控制和IO控制,很多时候需要PC端能够操作PLC一些数据。在1979年MODICON公司定义了一种工业现场总线协议标准——Modbus(最初的Modbus协议一般是走串口),后来在1996年施耐德公司基于以太网TCP/IP协议重新对MODBUS协议进行定义——MODBUSTCP。

    该协议实现了外部设备与PLC进行简单通讯功能,其中主要包括寄存器读取和写入,通过此功能结合PLC内部实现从而实现联合编程目的。
    优势:相比于PLC内部的TCP通讯MODBUS直接对PLC寄存器进行操作,更加高效、方便等,无需再在PLC端开通TCP通讯口,一般PLC都会开放一个端口作为MODBUS服务器以供触摸屏等外部设备交互。

    三菱PLC较为特殊,可以走MODBUS但是没必要(因为三菱较为NB,自己开发定义了一个比MODBUS更方便的协议SLMP协议),一般三菱PLC网口连接触摸屏都采用SLMP接口(FX5U)

    台达PLC通讯建议使用MOUBUSTCP通讯(在这里说一点,台达PLC和三菱比较起来很多功能指令封装较差,但是自由度高,台达编程软件用起来真的难受,强烈推荐三菱GX3【应该本行业里面最在意用户体验最佳的软件】)

    另外再说一点,MODBUSRTU协议一般用于串口的MODBUS通讯,其中有一点需要注意是需要加入校验,校验方法为CRC16。具体协议此处不深入。

    2.MOUBUSTCP数据组成

    MODBUSTCP在TCP发送中数据主要分为两个部分:报文头(MBAP)+帧结构(PDU)。其中报文头由事务处理标识+协议标识+长度+单元标识符,帧结构由功能码+数据组成

    最终数据:事务处理标识+协议标识+长度+单元标识符+功能码+数据

    事务处理标识
    数据序列号,用于区别多次通讯数据(每次加一就好)

    协议标识符
    表示采用哪种通讯协议,其中MODBUSTCP用00 00表示

    长度
    后面数据长度(用于保证数据完整性)

    单元标识符
    设备地址,应该是串口遗留位(没啥用,搞个00就可以了)

    功能码
    0x01:读线圈
    0x05:写单个线圈
    0x0F:写多个线圈
    0x02:读离散量输入
    0x04:读输入寄存器
    0x03:读保持寄存器
    0x06:写单个保持寄存器
    0x10:写多个保持寄存器

    数据
    读取数据:起始地址(两个byte)+需要读取的数据量(两个byte)
    写入单个线圈:地址(两个byte)+请求数据(0xFF00请求输出为ON,0x000请求输出为OFF)

    写入多个线圈:起始地址(两个byte)+写入数量(两个byte)+后面字节长度(一个byte)+十六进制表示的线圈值(ox03———11000000)

    写入多个寄存器:起始地址(两个byte)+写入数量(两个byte)+后面字节长度(一个byte)+寄存器值(一个寄存器值对应两个字节)

    其他可参考参考1

    3.实例(验证PLC 台达AS228T)

    通过以上介绍看下面的实例(将D0和D1值都改为15):

        QByteArray array1;
        array1[0]=0x00;	//事务处理标识
        array1[1]=0x00;
        array1[2]=0x00;	//协议标识
        array1[3]=0x00;
        array1[4]=0x00;	//长度
        array1[5]=0x0B;
        array1[6]=0x01;	//站号
        array1[7]=0x10;	//功能码
        array1[8]=0x00;	//起始地址
        array1[9]=0x00;
        array1[10]=0x00;	//写入长度
        array1[11]=0x02;
        array1[12]=0x04;	//后面数据长度
        array1[13]=0x00;	//首个数据值
        array1[14]=0x0F;
        array1[15]=0x00;	//第二个数据值
        array1[16]=0x0F;
    

    将M0和M1继电器置位

        array1[0]=0x00;
        array1[1]=0x00;
        array1[2]=0x00;
        array1[3]=0x00;
        array1[4]=0x00;
        array1[5]=0x08;
        array1[6]=0x01;
        array1[7]=0x0F;
        array1[8]=0x00;
        array1[9]=0x00;
        array1[10]=0x00;
        array1[11]=0x02;
        array1[12]=0x01;
        array1[13]=0x03;
    
    更多相关内容
  • modbusTCP练习程序,可供学习研究使用。可供学习研究使用。
  • Modbus TCP通讯协议

    万次阅读 2021-11-18 15:30:36
    1996年施耐德公司推出基于以太网TCP/IP的Modbus协议ModbusTCP。 Modbus协议是一项应用层报文传输协议,包括ASCII、RTU、TCP三种报文类型。 标准的Modbus协议物理层接口有RS232、RS422、RS485和以太网接口,采用...

    一、简介

    Modbus由MODICON公司于1979年开发,是一种工业现场总线协议标准。1996年施耐德公司推出基于以太网TCP/IP的Modbus协议:ModbusTCP

    Modbus协议是一项应用层报文传输协议,包括ASCII、RTU、TCP三种报文类型。

    标准的Modbus协议物理层接口有RS232、RS422、RS485和以太网接口,采用master/slave方式通信。

    二、ModbusTCP数据帧

    ModbusTCP的数据帧可分为两部分:MBAP+PDU

    2.1 报文头MBAP

    MBAP为报文头,长度为7字节:

    事务处理标识

    协议标识

    长度单元标识符
    2字节2字节2字节1字节
    内容解释
    事务处理标识可以理解为报文的序列号,一般每次通信之后就要加1以区别不同的通信数据报文。
    协议标识符00 00表示ModbusTCP协议。
    长度表示接下来的数据长度,单位为字节。
    单元标识符可以理解为设备地址。

    2.2 帧结构PDU

    PDU由功能码+数据组成。功能码为1字节,数据长度不定,由具体功能决定。

    2.2.1 功能码

    Modbus的操作对象有四种:线圈、离散输入、保持寄存器、输入寄存器。

    对象含义
    线圈PLC的输出位,开关量,在Modbus中可读可写
    离散量PLC的输入位,开关量,在Modbus中只读
    输入寄存器PLC中只能从模拟量输入端改变的寄存器,在Modbus中只读
    保持寄存器PLC中用于输出模拟量信号的寄存器,在Modbus中可读可写

    根据对象的不同,Modbus的功能码有:

    功能码含义
    0x01读线圈
    0x05写单个线圈
    0x0F写多个线圈
    0x02读离散量输入
    0x04读输入寄存器
    0x03读保持寄存器
    0x06写单个保持寄存器
    0x10写多个保持寄存器

    三、ModbusTCP通信

    3.1 通信方式

    Modbus设备可分为主站(poll)和从站(slave)。主站只有一个,从站有多个,主站向各从站发送请求帧,从站给予响应。在使用TCP通信时,主站为client端,主动建立连接;从站为server端,等待连接。

    • 主站请求:功能码+数据
    • 从站正常响应:请求功能码+响应数据
    • 从站异常响应:异常功能码+异常码,其中异常功能码即将请求功能码的最高有效位置1,异常码指示差错类型
    • 注意:需要超时管理机制,避免无期限的等待可能不出现的应答

    IANA(Internet Assigned Numbers Authority,互联网编号分配管理机构)给Modbus协议赋予TCP端口号为502,这是目前在仪表与自动化行业中唯一分配到的端口号。

    3.2 通信过程

    1. connect 建立TCP连接
    2. 准备Modbus报文
    3. 使用send命令发送报文
    4. 在同一连接下等待应答
    5. 使用recv命令读取报文,完成一次数据交换
    6. 通信任务结束时,关闭TCP连接

    3.3 仿真软件

    • 我是用的仿真软件是Modbus slave,可以实现Modbus RTU、TCP、串口仿真等。
    • Modbus slave 作为服务器端处理请求,客户端用java代替。
    • 使用软件时,需要指定功能码,在Modbus slave的Setup->slave definition中指定。

    – slave ID:从站编号(事务标识符)
    – function:功能码,0x01对应线圈操作,0x02对应离散量操作,0x03对应保持寄存器操作,0x04对应输入寄存器操作
    – address:开始地址
    – quantity:寄存器/线圈/离散量 的数量

    参考:

    https://www.cnblogs.com/ioufev/p/10831289.html  Java实现modbustcp通信

    https://blog.csdn.net/zwxuse251/article/details/24154951 数据报文结构详细

    https://blog.csdn.net/lakerszhy/article/details/68927178?locationNum=4&fps=1  Modbus功能码

    3.4 概念

    原文链接:https://wenku.baidu.com/view/55595d0690c69ec3d5bb75ed.html

    1.开关量:

    一般指的是触点的“开”与“关”的状态,一般在计算机设备中也会用“0”或“1”来表示开关量的状态。开关量分为有源开关量信号和无源开关量信号,有源开关量信号指的是“开”与“关”的状态是带电源的信号,专业叫法为跃阶信号,可以理解为脉冲量,一般的都有220VAC, 110VAC,24VDC,12VDC等信号,无源开关量信号指的是“开”和“关”的状态时不带电源的信号,一般又称之为干接点。电阻测试法为电阻0或无穷大。

    2.数字量:

    很多人会将数字量与开关量混淆,也将其与模拟量混淆。数字量在时间和数量上都是离散的物理量,其表示的信号则为数字信号。数字量是由0和1组成的信号,经过编码形成有规律的信号,量化后的模拟量就是数字量。

    3.模拟量:

    模拟量的概念与数字量相对应,但是经过量化之后又可以转化为数字量。模拟量是在时间和数量上都是连续的物理量,其表示的信号则为模拟信号。模拟量在连续的变化过程中任何一个取值都是一个具体有意义的物理量,如温度,电压,电流等。

    4.离散量:

    离散量是将模拟量离散化之后得到的物理量。即任何仪器设备对于模拟量都不可能有个完全精确的表示,因为他们都有一个采样周期,在该采样周期内,其物理量的数值都是不变的,而实际上的模拟量则是变化的。这样就将模拟量离散化,成为了离散量。

    5.脉冲量:

    脉冲量就是瞬间电压或电流由某一值跃变到另一值的信号量。在量化后,其变化持续有规律就是数字量,如果其由0变成某一固定值并保持不变,其就是开关量。

    四、仿真软件的使用

    多处参考取自:https://www.cnblogs.com/ioufev/p/10831289.html

    验证4个常用功能码,仿真软件上面有F=01,F=02,F=03、F=04来显示

    • 0x01:读线圈
    • 0x02:读离散量输入
    • 0x03:读保持寄存器
    • 0x04:读输入寄存器

    代码参数的理解

    • saveid:看资料"从站在modbus总线上可以有多个",仿真软件就能模拟一个从站,就是ID=1,当然可以修改成ID=2
    • 功能码:4个功能码,对应写4个方法,,仿真软件上的F=1,或者F=2,3,4
    • addr:一开始看代码4个方法addr都是从0开始,是否重复?答案是:4个功能码表示4个区域或者设备,addr表示各自区域的地址编号。

    仿真软件激活后选择Connection --> Connection Setup 选择TCP模式,端口是固定的502

    4.1 地址类型

     操作:新建四个不同功能码的窗口,然后运行代码,修改仿真软件上的值。

    4.2 数据类型 

    功能码01:false/true  0/1

     功能码02:false/true  0/1

    功能码03:多种类型

    signed:有符号
    unsigned:无符号
    hex:十六进制
    binary:二进制

    big-endian:大端,将高序字节存储在起始地址(高位编址)
    little-endian:小端,将低序字节存储在起始地址(低位编址)

    swap:交换

     注意:双击第一个地址输入数据,会提示输入数据的类型,32位数据占2个地址,所以下一个地址是--

    功能码04:多种类型 

    注意: 

    数据类型 WORD:无符号双字节整型(字,16位)     取值:0~65535(非负)

    五、案例

    5.1 引入依赖

    Modbus4j开源库:Serotonin Software用Java编写的Modbus协议的高性能且易于使用的实现。支持ASCII,RTU,TCP和UDP传输作为从站或主站,自动请求分区,响应数据类型解析和节点扫描。

    Modbus的github地址

    公共 Maven 存储库现已可用,最新构建将此添加到您的 pom 中.xml

    <!-- 若想引用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>
    <!-- 依赖信息是: -->
    <dependency>
        <groupId>com.infiniteautomation</groupId>
        <artifactId>modbus4j</artifactId>
        <version>3.0.3</version>
    </dependency>

    5.2 编写Modbus4j工具类

    Modbus4jUtils.java

    package com.ioufev;
    
    import com.serotonin.modbus4j.BatchRead;
    import com.serotonin.modbus4j.BatchResults;
    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;
    
    /**
     * modbus通讯工具类,采用modbus4j实现
     *
     */
    public class Modbus4jUtils {
        /**
         * 工厂。
         */
        static ModbusFactory modbusFactory;
        static {
            if (modbusFactory == null) {
                modbusFactory = new ModbusFactory();
            }
        }
    
        /**
         * 获取master
         *
         * @return
         * @throws ModbusInitException
         */
        public static ModbusMaster getMaster() throws ModbusInitException {
            IpParameters params = new IpParameters();
            params.setHost("127.0.0.1");
            params.setPort(502);
            //
            // modbusFactory.createRtuMaster(wapper); //RTU 协议
            // modbusFactory.createUdpMaster(params);//UDP 协议
            // modbusFactory.createAsciiMaster(wrapper);//ASCII 协议
            ModbusMaster master = modbusFactory.createTcpMaster(params, false);// TCP 协议
            master.init();
    
            return master;
        }
    
        /**
         * 读取[01 Coil Status 0x]类型 开关数据
         *
         * @param slaveId
         *            slaveId
         * @param offset
         *            位置
         * @return 读取值
         * @throws ModbusTransportException
         *             异常
         * @throws ErrorResponseException
         *             异常
         * @throws ModbusInitException
         *             异常
         */
        public static Boolean readCoilStatus(int slaveId, int offset)
                throws ModbusTransportException, ErrorResponseException, ModbusInitException {
            // 01 Coil Status
            BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
            Boolean value = getMaster().getValue(loc);
            return value;
        }
    
        /**
         * 读取[02 Input Status 1x]类型 开关数据
         *
         * @param slaveId
         * @param offset
         * @return
         * @throws ModbusTransportException
         * @throws ErrorResponseException
         * @throws ModbusInitException
         */
        public static Boolean readInputStatus(int slaveId, int offset)
                throws ModbusTransportException, ErrorResponseException, ModbusInitException {
            // 02 Input Status
            BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
            Boolean value = getMaster().getValue(loc);
            return value;
        }
    
        /**
         * 读取[03 Holding Register类型 2x]模拟量数据
         *
         * @param slaveId
         *            slave Id
         * @param offset
         *            位置
         * @param dataType
         *            数据类型,来自com.serotonin.modbus4j.code.DataType
         * @return
         * @throws ModbusTransportException
         *             异常
         * @throws ErrorResponseException
         *             异常
         * @throws ModbusInitException
         *             异常
         */
        public static Number readHoldingRegister(int slaveId, int offset, int dataType)
                throws ModbusTransportException, ErrorResponseException, ModbusInitException {
            // 03 Holding Register类型数据读取
            BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
            Number value = getMaster().getValue(loc);
            return value;
        }
    
        /**
         * 读取[04 Input Registers 3x]类型 模拟量数据
         *
         * @param slaveId
         *            slaveId
         * @param offset
         *            位置
         * @param dataType
         *            数据类型,来自com.serotonin.modbus4j.code.DataType
         * @return 返回结果
         * @throws ModbusTransportException
         *             异常
         * @throws ErrorResponseException
         *             异常
         * @throws ModbusInitException
         *             异常
         */
        public static Number readInputRegisters(int slaveId, int offset, int dataType)
                throws ModbusTransportException, ErrorResponseException, ModbusInitException {
            // 04 Input Registers类型数据读取
            BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
            Number value = getMaster().getValue(loc);
            return value;
        }
    }
    

    5.3 测试 

    测试代码:

    public static void main(String[] args) {
            try {
    //            // 01测试
                Boolean v011 = readCoilStatus(1, 0);
                Boolean v012 = readCoilStatus(1, 1);
                Boolean v013 = readCoilStatus(1, 6);
                System.out.println("v011:" + v011);
                System.out.println("v012:" + v012);
                System.out.println("v013:" + v013);
                // 02测试
                Boolean v021 = readInputStatus(1, 0);
                Boolean v022 = readInputStatus(1, 1);
                Boolean v023 = readInputStatus(1, 2);
                System.out.println("v021:" + v021);
                System.out.println("v022:" + v022);
                System.out.println("v023:" + v023);
    //
                // 03测试
                Number v031 = readHoldingRegister(1, 0, DataType.TWO_BYTE_INT_SIGNED);// 注意,float
                Number v032 = readHoldingRegister(1, 1, DataType.TWO_BYTE_INT_SIGNED);// 同上
                System.out.println("v031:" + v031);
                System.out.println("v032:" + v032);
    
                // 04测试
                Number v041 = readInputRegisters(1, 0, DataType.FOUR_BYTE_FLOAT);//
                Number v042 = readInputRegisters(1, 2, DataType.FOUR_BYTE_FLOAT);//
                System.out.println("v041:" + v041);
                System.out.println("v042:" + v042);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    }

    5.4 代码解释

    5.5 仿真软件Modbus slave信息

     5.6 运行结果

    补充:

     举例:

    功能码监测项规约地址数据类型
    02直流输入过高停机1080HBOOL
    功能码描述PLC地址寄存器地址位/字操作操作数量
    01H读线圈寄存器00001-099990000H-FFFFH位操作单个或多个
    02H读离散输入寄存器10001-199990000H-FFFFH位操作单个或多个
    03H读保持寄存器40001-499990000H-FFFFH字操作单个或多个
    04H读输入寄存器30001-399990000H-FFFFH字操作单个或多个
    05H写单个线圈寄存器00001-099990000H-FFFFH位操作单个
    06H写单个保持寄存器40001-499990000H-FFFFH字操作单个
    0FH写多个线圈寄存器00001-099990000H-FFFFH位操作多个
    10H写多个保持寄存器40001-499990000H-FFFFH字操作多个

    直流输入过高停机监测项的规约地址为1080H

                    转10进制:1080H  ————>   4224

                    02功能码的PLC起始地址为:10001 ~ 19999

                    读离散输入寄存器值的地址为:PLC起始地址+规约地址  10001 + 4224 = 14225

    代码读离散输入寄存器的值:

    public static void main(String[] args) {
            try {
                // 读离散输入寄存器
                //参数1:slaveID  参数2:起始地址
                Boolean v021 = readInputStatus(1, 14225);
         
                System.out.println("v021:" + v021);
            } catch (Exception e) {
                e.printStackTrace();
            }
    }

    展开全文
  • modbustcp通信协议

    2015-06-08 15:52:23
    本文档是用来定义modbustcp通信协议,下载后可以直接了解相关领域的通信机制。
  • FANUC机器人MODBUS TCP通信相关设置步骤与参数
  • MODBUS-TCP协议解析

    2020-12-07 13:53:56
    Modbus协议是一项应用层报文传输协议,包括ASCII、RTU、TCP三种报文类型,协议本身并没有定义物理层,只是定义了控制器能够认识和使用的消息结构,而不管他们是经过何种网络进行通信的。
  • 本文对modbustcp协议以及modbustcp串行通信在智能楼宇工程中的应用作了简单介绍,重点分析研究了modbustcp读取plc的保持寄存器数据的过程,并提出实现modbustcp协议通信的解决方案,进行编程以及调试,成功实现了...
  • 西门子S7-200Smart Modbus TCP协议通讯,在使用S7-200smart进行以太网通讯,此时如果使用原生S7协议通讯效率及通用性都不好,此时就要使用自由口的通讯方式,这里提供了modbus TCP主站(客户端最大4链接)、modbus ...
  • qt下实现了modbus tcp通讯协议,能够通过modbus协议控制底层硬件工作,该代码可以用于PLC等硬件的控制,运行环境vs2017+QT5.1.12
  • C# Modbus-TCP协议封装

    2018-06-07 14:55:02
    C# Modbus-TCP协议封装。封装成class类,使用的时候只要创建一个modbus-tcp,就可以直接调用里面的方法。
  • ModBus Tcp 通讯C# +Demo

    热门讨论 2018-09-14 17:11:28
    C# ModBus Tcp读写数据 与服务器进行通讯,内包含客户端和服务端源码。
  • Modbustcp golang ModbusTCP库 持续集成 文件资料
  • 模拟Modbus协议硬件,为工业物联网工业4.0提供编程学习方便。打开服务端软件后通过C#编程语言编写通信连接软件的客户端。通过改变对应地址的电位实现控制工控设备的功能。
  • 1、概述。 2、Modbus协议规范。 3、Modbus协议在串行链路上的实现。 4、Modbus协议TCP/IP上的实现。
  • 工业通讯桥接器NET30-CS,可以用于欧姆龙CP和CJ系列PLC的以太网通讯,以太网同时支持FINSTCP和ModbusTCP两种通讯协议。桥接器主要为工业设备联网项目提供硬件支持,帮助上层终端通过以太网的方式采集底层工业设备的...
  • ModbusCom.cs
  • modbus tcp for delphi

    2022-03-26 14:48:11
    供做MODBUS TCP开发的朋友参考,如果是用DELPHI开发的话,可以直接使用
  • ModBusTcp协议(一)

    2022-04-14 19:42:17
    ModBusTcp协议 简介 Modbus由MODICON公司于1979年开发,是一种工业现场总线协议标准。1996年施耐德公司推出基于以太网TCP/IP的Modbus协议ModbusTCP。 Modbus协议是一项应用层报文传输协议,包括ASCII、RTU、...

    ModBusTcp协议

    简介

    • Modbus由MODICON公司于1979年开发,是一种工业现场总线协议标准。1996年施耐德公司推出基于以太网TCP/IP的Modbus协议:ModbusTCP

    • Modbus协议是一项应用层报文传输协议,包括ASCII、RTU、TCP三种报文类型。

    • 标准的Modbus协议物理层接口有RS232、RS422、RS485和以太网接口,采用master/slave方式通信。

    • Modbus的工作方式是请求/应答,每次通讯都是主站先发送指令,可以是广播,或是向特定从站的单播;从站响应指令,并按要求应答,或者报告异常。当主站不发送请求时,从站不会自己发出数据,从站和从站之间不能直接通讯。

    • Modbus协议是应用层(协议层)报文传输协议,它定义了一个与物理层无关的协议数据单元(PDU),即PDU=功能码+数据域,功能码1byte,数据域不确定。

    • Modbus协议能够应用在不同类型的总线或网络。对应不同的总线或网络,Modbus协议引入一些附加域映射成应用数据单元(ADU),即ADU=附加域+PDU,例如modbus tcp/ip------ ADU=MBAP+ADU。

    通讯方式

    • 以太网:对应的通信模式是Modbus TCP/IP
    • 异步串行传输(各种介质如有线RS-232-/422/485/;光纤、无线等):对应的通信模式是Modbus RTUModbus ASCII
    • 高速令牌传递网络:对应的通信模式是Modbus PLUS

    modbus tcp/ip通信方式

    • Modbus设备可分为主站(poll)和从站(slave)。主站只有一个,从站有多个,主站向各从站发送请求帧,从站给予响应。在使用TCP通信时,主站为client端,主动建立连接;从站为server端,等待连接。
      • 主站请求:功能码+数据
      • 从站正常响应:请求功能码+响应数据
      • 从站异常响应:异常功能码+异常码,其中异常功能码即将请求功能码的最高有效位置1,异常码指示差错类型
      • 注意:需要超时管理机制,避免无期限的等待可能不出现的应答
    • IANA(Internet Assigned Numbers Authority,互联网编号分配管理机构)给Modbus协议赋予TCP端口号为502,这是目前在仪表与自动化行业中唯一分配到的端口号。

    通信过程

    • connect 建立TCP连接
    • 准备Modbus报文
    • 使用send命令发送报文
    • 在同一连接下等待应答
    • 使用recv命令读取报文,完成一次数据交换
    • 通信任务结束时,关闭TCP连接

    报文格式

    • Modbus协议的报文(或帧)的基本格式是:表头 + 功能码 + 数据区 + 校验码
    • 对于Modbus TCP而言,主站通常称为Client,从站称为Server;而对于Modbus RTU和Modbus ASCII来说,主站是Master,从站是Slave。
    • ModbusTCP的数据帧可分为两部分:ADU=MBAP+PDU = MBAP + 功能码 + 数据域,MBAP 7byte,功能码1byte,数据域不确定,由具体功能决定。

    报文头MBAP

    • MBAP为报文头,长度为7字节,组成如下:

    • 事务处理标识协议标识长度单元标识符
      2字节2字节2字节1字节
    • 内容解释
      事务处理标识报文的序列号,每次通信之后就要加1以区别不同的通信数据报文
      协议标识符00 00表示ModbusTCP协议
      长度数据长度,单位为字节
      单元标识符可以理解为设备地址

    帧结构PDU

    • PDU由功能码+数据组成。功能码为1字节,数据长度不定,由具体功能决定。
    功能码
    • Modbus的操作对象有四种:线圈、离散输入、保持寄存器、输入寄存器。

    • 对象含义
      线圈PLC的输出位,开关量,在Modbus中可读可写
      离散量PLC的输入位,开关量,在Modbus中只读
      输入寄存器PLC中只能从模拟量输入端改变的寄存器,在Modbus中只读
      保持寄存器PLC中用于输出模拟量信号的寄存器,在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字操作多个
    展开全文
  • 用delphi7开发的一个modbus tcp/ip client 通信例子,希望可以帮助大家学习借鉴
  • 西门子Modbus TCP通讯

    2019-04-05 15:46:28
    学习与掌握西门子S7-1200系列PLC的Modbus TCP通讯,实用性高。
  • modbustcpplc通讯上位机
  • 可运行的java项目,分别用两种方案实现modbus协议读写1、jlibmodbus 2、modbus4j 有问题可联系QQ:361440206
  • Modbus通讯协议详解及与Modbus TCP通讯协议之间的区别

    万次阅读 多人点赞 2018-05-09 09:37:52
    Modbus通信协议由Modicon公司(现已经为施耐德公司并购,成为其旗下的子品牌)于1979年发明的,是全球最早用于工业现场的总线规约。由于其免费公开发行,使用该协议的厂家无需缴纳任何费用,Modbus通信协议采用的是...

    Modbus通信协议由Modicon公司(现已经为施耐德公司并购,成为其旗下的子品牌)于1979年发明的,是全球最早用于工业现场的总线规约。由于其免费公开发行,使用该协议的厂家无需缴纳任何费用,Modbus通信协议采用的是主从通信模式(即Master/Slave通信模式),其在分散控制方面应用极其广泛,从而使得Modbus协议在全球得到了广泛的应用。

    Modbus通信协议具有多个变种,其具有支持串口(主要是RS-485总线),以太网多个版本,其中最著名的是Modbus RTU,Modbus ASCII和Modbus TCP三种。其中Modbus RTU与Modbus ASCII均为支持RS-485总线的通信协议,其中Modbus RTU由于其采用二进制表现形式以及紧凑数据结构,通信效率较高,应用比较广泛。而Modbus ASCII由于采用ASCII码传输,并且利用特殊字符作为其字节的开始与结束标识,其传输效率要远远低于Modbus RTU协议,一般只有在通信数据量较小的情况下才考虑使用Modbus ASCII通信协议,在工业现场一般都是采用Modbus RTU协议,一般而言,大家说的基于串口通信的Modbus通信协议都是指Modbus RTU通信协议。

    在此我们着重讨论Modbus RTU协议,而Modbus TCP协议则是在RTU协议上加一个MBAP报文头,由于TCP是基于可靠连接的服务,RTU协议中的CRC校验码就不再需要,所以在Modbus TCP协议中是没有CRC校验码,用一句比较通俗的话说就是:Modbus TCP协议就是Modbus RTU协议在前面加上五个0以及一个6,然后去掉两个CRC校验码字节就OK.虽然这句话说得不是特别准确,但是也基本上把RTU与TCP之间的区别说得比较清楚了。

    RTU协议中的指令由地址码(一个字节),功能码(一个字节),起始地址(两个字节),数据(N个字节),校验码(两个字节)五个部分组成,其中数据又由数据长度(两个字节,表示的是寄存器个数,假定内容为M)和数据正文(M乘以2个字节)组成,而RTU协议是采用3.5个字节的空闲时间作为指令的起始和结束,一般而言,只有当从机返回数据或者主机写操作的时候,才会有数据正文,而其他时候比如主机读操作指令的时候,没有数据正文,只需要数据长度即可。(本章的讨论只涉及寄存器的读写,其他比如线圈的读写指令我们暂时不涉及)。在此我们通过两个指令(0x03H:读多个寄存器指令以及0x10H:写多个寄存器指令)来解释Modbus RTU协议。在此我们使用的RTU设备是深圳市国科伟业通信技术有限公司的ND-1084型485总线I/O模块

    ND-1084型485总线I/O模块采用RS-485总线通信,支持四路开关量输出以及八路开关量输入,我们只讲述读取开关量输出的状态以及通过写指令控制开关量的输出。其中储存开关量输出状态的四个寄存器分别:0x18E,0x18F,0x190,0x191。在此我们假设模块的地址为默认的0x01,当我们要去读取开关量输出对应的四个寄存器的状态的时候,我们下发的十六进制的指令为:“01 03 01 8E 00 04 25 DE”,其中“01”为模块的地址码,“03”为功能码,即表示读寄存器,“01 8E”为寄存器地址,即从该寄存器地址开始读取数据,“00 04”则表示读取4个寄存器,而“25 DE”则为前面“01 03 01 8E 00 04”的CRC校验码,该数值通过CRC16校验算法计算出来的,我们会在其他文章中阐述。该指令的完整解读就是,在地址码为“01”的模块中,从“01 8E”寄存器开始,读取4个寄存器的数据返回至主机。在此,我们可以看到,读取指令中并没有什么数据正文,因为它只是读取相应数量的寄存器,并不需要数据正文,而写操作指令则相反,我们会在后面讲到。

    模块返回的指令是:“01 03 08 00 01 00 01 00 01 00 01 28 D7”,返回的指令内容解读就是:“01”表示模块的地址码,“03”表示该指令是读操作返回的指令,“08”表示数据长度,在此表示的是8个字节数据正文(即4个寄存器,每个寄存器两个字节表示),“00 01 00 01 00 01 00 01”是数据正文,表示四个寄存器的状态,“28 D7”就是CRC16校验码。

    同样的当我们执行写操作的是,我们举例写第一个开关量输出,即寄存器“0x18E”,主机下发的指令为:“01 10 01 8e 00 01 02 00 00 A8 7E”,该指令的解读就是:“01”表示模块的地址,“10”表示该指令为写寄存器,“01 8E”表示从该寄存器地址开始执行写操作指令“00 01”表示写多少个寄存器,在此为写1个寄存器,“02”表示数据长度,表示数据长度为两个字节,“00 00”表示写入寄存器的数据,在此表示连通,“A8 7E”为CRC校验码。模块返回的指令和读取寄存器的返回的指令类似。

    前文所述,Modbus TCP协议是在RTU协议前面添加MBAP报文头,共七个字节长度,其分别的意义是:1.传输标志,两个字节长度,标志Modbus询问/应答的传输,一般默认是00 00。2.协议标志,两个字节长度,0表示是Modbus,1表示UNI-TE协议,一般默认也是00 00。3.后续字节计数,两个字节长度,其实际意义就是后面的字节长度,具体情况详见下文。4.单元标志,一个字节长度,一般默认为00,单元标志对应于Modbus RTU协议中的地址码,当RTU与TCP之间进行协议转换的时候,特别是Modbus网关转换协议的时候,在TCP协议中,该数据就是对应RTU协议中的地址码,具体情况详见下文。

    通过上面的描述我们差不多能够理解Modbus RTU协议,我们再说说Modbus TCP通信协议,前面就已经说过TCP协议就是在RTU协议的基础上去掉校验码以及加上五个0和一个6,当是读取相关寄存器的时候,该说法是没有错的,比如上文的“01 03 01 8E 00 04 25 DE”读取指令,用TCP协议来表述的话,指令是“00 00 00 00 00 06 00 03 01 8E 00 04”,由于TCP是基于TCP连接的,不存在所谓的地址码,所以06后面一般都是“00”(当其作为Modbus网关服务器挂接多个RTU设备的时候,数值从01-FF).即“00 03 01 8E 00 04”对应的是RTU中去掉校验码的指令,前面则是五个0以及一个6。其中6表示的是数据长度,即“00 03 01 8E 00 04”有6个字节长度。而当其为写操作指令的时候,其指令是“00 00 00 00 00 09 01 10 01 8e 00 01 02 00 00”,其中“00 09”表示后面有9个字节。

    Modbus RTU与Modbus TCP读指令对比

     
    MBAP报文头
    地址码
    功能码
    寄存器地址
    寄存器数量
    CRC校验
    Modbus RTU
    01
    03
    01 8E
    00 04
    25 DE
    Modbus TCP
    00 00 00 00 00 06 00
    03
    01 8E
    00 04

    指令的涵义:从地址码为01(TCP协议单元标志为00)的模块0x18E(01 8E)寄存器地址开始读(03)四个(00 04)寄存器。

    Modbus RTU与Modbus TCP写指令对比

     
    MBAP报文头
    地址码
    功能码
    寄存器地址
    寄存器数量
    数据长度
    正文
    CRC校验
    RTU
    01
    10
    01 8E
    00 01
    02
    00 00
    A8 7E
    TCP
    00 00 00 00 00 09 00
    10
    01 8E
    00 01
    02
    00 00

    指令的涵义:从地址码为01(TCP协议单元标志为00)的模块0x18E(01 8E)寄存器地址开始写(10)一个(00 01)寄存器,具体数据长度为2个字节(02),数据正文内容为00 00(00 00)。

    展开全文
  • 同步发送接受,消息处理
  • modbus TCP 练习,modbustcp通讯协议实例,Visual Basic源码
  • Netty NIO high performance高性能;Modbus Function sync/aync 同步/异步非阻塞;Modbus IoT Data Connector Supports工业物联网平台IoT支持。
  • ModbusTCP协议的例子

    2013-08-04 17:09:53
    这是一个关于ModBus TCP协议的使用案例
  • CoDeSys最新版本通过Modbus TCP工业协议与工厂I/O的完整配置过程创建一个简单的项目,用一个简单的密封电路(CoDeSys操作逻辑)来通信两个程序,该电路可以打开和关闭线性跑步机(工厂I/O中的3D场景视图侧
  • #资源达人分享计划#
  • modbus TCP完整功能程序,用于读取仪器仪表和远程PLC比较实用,PLC基本都支持modbus TCP

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,183
精华内容 2,073
关键字:

modbustcp通讯协议