Modbus的报文格式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Modbus的报文格式相关的知识,希望对你有一定的参考价值。

参考技术A

Modbus ASCII或RTU模式仅使用于标准的Modbus协议串行网络,它定义了在这些网络上连续传输的消息段的每一个字节,以及决定怎样将信息打包成消息域和如何解码等功能。

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

在ASCII模式下,消息以冒号(:)字符(ASCII码0x3A)开始,以回车换行符结束(ASCII码0x0D,0x0A)。消息帧的其他字段可以使用的传输字符是十六进制的0 9,A F。处于网络上的Modbus设备不断侦测 “:” 字符,当有一个冒号接收到时,每个设备进入解码阶段,并解码下一个字段(地址域)来判断是否是发给自己的。消息帧中的字符间发送的时间间隔最长不能超过1s,否则接收的设备将认为发生传输错误。

传输设备将Modbus报文放置在带有已知起始和结束电的消息帧中,这就要求接收消息真的设备在报文的起始处开始接收,并且要知道报文传输何时结束。另外还必须能够检测到不完整的报文,且能够清晰地设置错误标志。

在RTU模式中,消息的发送和接收以至少3.5个字符时间的停顿间隔为标志。实际使用中,网络设备不断侦测网络总线,计算字符间的停顿间隔时间,判断消息帧的起始点。当接收到第一个域(地址域)时,每个设备都进行解码以判断时否时发给自己的。在最后一个传输字符结束之后,一个至少3.5个字符时间的停顿标定了消息的结束,而一个新的消息可以在此停顿后开始。另外,在一帧报文中,必须以连续的字符流发送整个报文帧。如果两个字符之间的空闲间隔大于1.5个字符时间,那么认为报文帧不完整,该报文将丢失。 简单来说,3.5个字符时间间隔的目的是作为区别前后两帧数据的分隔符

例如:
串口参数设置为1位起始位,8位数据位,1位校验位,1位停止位。这样1个字符就博爱阔11位,那么3.5个字符就是3.5*11=38.5位。此时波特率设置位9600bps,即每秒传输数据为9600个位的数据。那么换算一下,38.5个二进制位数据需要的时间就是38.5*(1000/9600)=4.0104167ms。那么在波特率9600bps的情况下,相邻的两帧数据的起始和结束之间至少有≥4.0104167ms的时间间隔。

为了时间RTU通信中的时间间隔管理,定时器将引起大量的中断处理,在较高的通信波特率下将导致CPU沉重负担。为此,规定当波特率≤19200bps时,需要严格遵守时间间隔。在波特率>19200bps时,时间间隔使用固定值。

地址域即通信帧中的地址字段,内容为从设备地址。Modbus消息帧的地址域包含2个字符(ASCII模式)或者1个字节(RTU模式)。

从设备的地址是0~247(十进制),单个设备的实际地址范围是1~247,地址0作为广播地址。主设备发送消息时将从设备地址放到地址域中以便从设备识别此消息是否是发给自己的。从设备回复主设备时会将自己的地址放到回应消息的地址域中以便主设备识别是哪个从设备返回的数据。

功能吗用于表示消息帧的功能。功能码域由1个字节构成,取值范围为1~255(十进制)。从设备根据功能码执行相应的功能,执行完成后在响应消息帧中设置同样的功能码。如果出现异常,返回的消息帧中将功能码最高位(MSB)设置为1。

数据域存放功能码需要操作的具体数据。数据域以字节为单位,长度可变。

在Modbus串行通信中,更具传输模式(ASCII和RTU)的不同,差错校验域采用了不同的校验方式。

在Modbus TCP/IP协议中,串行链路中的主/从设备分别演变位客户端/服务器端设备。

Modbus协议在TCP/IP上的实现实在TCP/IP协议层上的应用,它需要一个完整的TCP/IP协议栈作为支撑,Modbus TCP/IP服务器端通常使用端口502作为接收报文的端口。

为了便于传输或者提取各报文,保证报文传输的完整性,Modbus协议在应用数据单元(ADU)中引入了附加字段。如串行链路中的报文分隔符+LRC校验和时间间隔+CRC校验。同样的,在TCP/IP网络上的Modbus协议也引入了一个称为MBAP(Modbus Application Header)报文头的字段。

Modbus TCP/IP协议最大帧数据长度为260字节,其中字节0~6构成MBAP报头。

单元标识符
如果是Modbus服务器连接到Modbus+或Modbus串行链路子网,并通过一个网桥或网关配置这个服务器的IP地址,则Modbus单元标识符对识别连接到网桥或网关后的子网的从站设备是必须的。TCP连接中的目的IP地址识别了网桥本身的地址,而网桥则使用Modbus单元标识符将请求转交给正确的从站设备。

对单纯的Modbus TCP/IP设备来说,利用IP地址即可寻址Modbus服务器端设备,此时Modbus单元标识符是无用的,必须使用0xFF填充。当对直接连接到TCP/IP网络上的Modbus服务器寻址时,建议不要在“单元标识符”域使用有效的Modbus从站地址。

查询与响应报文举例

在Modbus TCP/IP模式下,不需要校验字段。但在特殊场合,例如串行Modbus协议转Modbus TCP的情况下,串行协议数据可以完整的装在到Modbus TCP协议的数据字段,这时CRC或者LRC差错校验字段仍然存在。例如Modbus RTU Over TCP/IP或modbus ASCII Over TCP/IP等。

Modbus 协议从站开发通信西门子 PLC

文章目录

1. Modbus 协议

    Modbus 串行链路协议是一个主从模式的半双工数据传输协议
    Modbus 是施耐德电气公司,于 1979 年发明的,是全球第一个真正用于工业现场的总线协议,广泛应用于工业控制领域,且免费、便于部署维护。
    主从模式是指总线上包含一个主站和多个从站,每个从站具有唯一的从站标识 ID,主站通过 ID 进行寻址,然后和从站进行数据传输通信。主站最多可和 1-247 个从站通信。

Poll 端作为主站,Slave 端作为从站
有且只有一个主站,工业中 PLC 通常作为主站
主站请求从站,不支持从站向主站发起请求
根据主站从站商定好的格式发出寻址数据帧,主站请求从站,从站响应主站
测试工具包 Modbus Poll、Modbus Slave 下载 网盘提取码: bbdb

1.1 传输模式:单工模式、全双工模式、半双工模式

    单工模式、全双工模式、半双工模式类似交通道路中的单向单行道、双向双行道,双向单行道

  • 单工模式
    允许数据在单个方向上传输,发送数据仅支持从站点 A 传输到 B,就不支持从站点 B 传输到 A;A→B
  • 全双工模式
    允许数据在两个方向上错时传输,即站点在发送数据的同时也允许接收数据;A⇆B
  • 半双工模式
    允许数据在两个方向上同时传输,即站点在发送数据时不能接收数据,在接收数据时不能发送数据;A→B 或 B→A

1.2 广播模式、单播模式

  • 广播模式
    主站可向多个从站进行发送,设备地址设置为 0 用于广播模式,从站收到请求后不对主站进行响应;
  • 单播模式
    主站根据从站 ID 进行寻址可向指定从站发送请求,从站接收应答把消息返回给主站

1.3 Modbus 通信模式:ASCII、RTU

    在主从设备的通信中,可以使用 ASCII 通信模式和 RTU 通信模式,在一个 Modbus 网络上所有设备要统一通信模式和其他串口参数。

  • ASCII 模式:美国标准信息交换代码
    以 ASCII 模式通信时,在消息中,每个 8bit 字节作为两个 ASCII 字符发送;
    优点:字符发送的时间间隔可达到 1 秒而不产生错误。
    报文格式: 英文冒号 + 地址 + 功能编码 + 数据梳理 + 数据1 + ... + 数据n + LRC 高字节 + LRC 低字节 + 回车 + 换行

  • RTU (Remote Terminal Unit):远程终端单元
    在消息中,每个 8bit字节包含两个 4bit 的十六进制字符;
    优点:是相同波特率下比 ASCII 方式传送更多的数据;
    报文格式:地址 + 功能编码 + 数据数量 + 数据1 + ... + 数据n + CRC 低字节 + CRC 高字节

一个十六进制数据 0xAF,需要两个字节传输需要两个 ASCII 字符 ‘A’,‘F’ ;
数据 0xAF 在 RTU 模式下需要一个字节,在 ASCII 模式下需要占用两个字节;
由于 ASCII 通信方式有开始标志和结束标志,所以一个数据包之间的各字节间的传输间隔时间可以大于1秒;而 RTU 通信方式下,由于没有规定开始和结束标记,所以协议规定每两个字节之间发送或者接收的时间间隔不能超过3.5倍字符传输时间,超过则认为一帧数据已经完成接收,超过后的数据是新一帧的数据;

通信模式RTUASCII
优点同波特率下,比 ASCII 多传输一倍的数据字符发送时间间隔超出 1 秒不会产生错误,因为一帧数据包含开始标记结束标记
缺点同一帧数据的两个字节间的传输时间间隔不能超出 3.5 倍字符传输时间同波特率下,比 RTU 少传输一倍的数据
字符集8bit 二进制,十六进制数 0…9,A…F十六进制,ASCII 字符 0…9,A…F
开始标记:
结束标记CR,LF
校验方式CRC 循环冗长检测LRC 纵向冗长检测
传输效率
程序处理较复杂ASCII 字符直观易调试
起始位1bit1bit
数据位8bit7bit
奇偶校验位1bit,无校验则无1bit,无校验则无
停止位1bit,无校验时 2bit1bit,无校验时 2bit

1.4 基本数据类型

  • 位 bit
    BOOL 布尔型,值为 0 或 1;如 I0.0、Q0.1
  • 字节 byte
    1 byte = 8 bit
    短整形类型;如 IB0 包括 I0.1~I0.7
  • 字 word
    1 word = 2 byte = 16 bit
    相邻的两个字节组成一个字,来表示一个无符号数
  • 双字 double word
    1 double word = 2 word = 4 byte = 32 bit
    相邻的两个字组成一个双字

2. 功能编码 function


    功能编码在报文中占用一个字节,编号范围限制 1 ~ 255。
    功能代码编号为 1 ~ 127,其中 65 ~ 72,100 ~ 110 是用户自定义编码,其他为通用功能编码。
    128 ~ 255 为保留值用于异常信息应答报文。

传输模式RTUASCIIPLC 单片机地址范围
0x01读线圈位bit00001-09999
0x02读离散量输入位bit10001-19999
0x03读保持寄存器字word40001-49999
0x04读输入寄存器位bit30001-39999
0x05写单个线圈位bit
0x06写单个寄存器字word
0x07读取异常状态诊断
0x08诊断诊断
0x0F写多个线圈位bit
0x10写多个寄存器字word

3. 报文格式说明

3.1 报文格式

传输模式报文格式
ASCII英文冒号 + 地址 + 功能编码 + 数据数量 + 数据1 + ... + 数据n + LRC 高字节 + LRC 低字节 + 回车 + 换行
RTU地址 + 功能编码 + 数据数量 + 数据1 + ... + 数据n + CRC 低字节 + CRC 高字节


    主站 Poll 端发送请求报文,从站 Slave 端响应报文;主从统一 Modbus 协议,功能编码,从站地址,传输方式,端口等信息;使用 Modbus 协议;
    Slave Id 从站唯一标识为 255,十六进制 0xFF;
    Function 功能编码统一读保持寄存器 03,十六进制 0x03;
    Address 规定从下标 0 开始读取,十六进制 0x0000;
    Quantity 规定读取数量为 2,十六进制 0x0002;

通过 Modbus Poll 工具可以看到:
RTU 传输模式下请求报文 FF 03 00 00 00 02 D1 D5
ASCII 传输模式下请求报文 3A 46 46 30 33 30 30 30 30 30 30 30 32 46 43 0D 0A ;

3.2 Modbus RTU 报文说明

Tx:000309-FF 03 00 00 00 02 D1 D5
Rx:000310-FF 03 04 00 0C 00 0A A5 F8

请求报文,主站寻址 Slave Id 为 255 的从站,从读保持寄存器起始位置 0 开始读取两个数据;
响应报文,Slave ID 为 255 的从站响应请求,从读保持寄存器返回两个数据 12、10;
rx 是接收,tx是发送。
请求报文 + 报文编号 + 地址 + 功能编码 + 起始地址 + 读取数量 + CRC 低字节 + CRC 高字节
请求报文 + 报文编号 + 地址 + 功能编码 + 数据数量 + 数据1 + ... + 数据n + CRC 低字节 + CRC 高字节

  • Modbus RTU 请求报文
请求报文说明
Slave ID 从站地址0xFF
Function 功能编码0x03
Address 起始位置0x0000
Quantity 读取数量0x0002
CRC 低校验位0xD1
CRC 高校验位0xD5
  • Modbus RTU 响应报文
响应报文说明
Slave ID 从站地址0xFF
Function 功能编码0x03
Quantity 数据数量0x04
数据10x000C
数据20x000A
CRC 低校验位0xA5
CRC 高校验位0xF8

3.4 Modbus TCP 报文说明

Tx:000000-00 03 00 00 00 06 FF 03 00 00 00 0A
Rx:000001-00 03 00 00 00 17 FF 03 14 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

请求报文,使用 Modbus 协议,主站寻址 Slave Id 为 255 的从站,从读保持寄存器起始位置 0 开始读取 10 个数据;
响应报文,Slave ID 为 255 的从站响应请求,从读保持寄存器返回 10 个数据 0、0…、0;
标识发送请求 + 报文编号 + 通信标识符 + 协议标识符 + 数据长度 + 地址 + 功能编码 + 起始地址 + 读取数量
标识响应请求 + 报文编号 + 通信标识符 + 协议标识符 + 数据长度 + 地址 + 功能编码 + 数据数量 + 数据1 + ... + 数据n

  • Modbus TCP 请求报文
请求报文说明
Tx:000000标识发送请求
00 03通信事务处理标识符,应答报文要求与请求报文保持一致
00 00协议标识符,应答报文要求与请求报文一致,00 00 标识 modbus 协议
00 06数据长度,十六进制 0x0006,十进制数据长度为 6
FF从站 ID 唯一标识,十六进制 0xFF,十进制从站 ID 为 255
03功能编码,0x03 读保持寄存器
00 00读取寄存器起始位置,十六进制 0x00,十进制从下标 0 位置开始读取
00 0A读取寄存器长度,十六进制 0x000A,十进制读取寄存器长度 10
  • Modbus TCP 响应报文
响应报文说明
Rx:000001标识响应请求
00 03通信事务处理标识符,应答报文要求与请求报文保持一致
00 00协议标识符,应答报文要求与请求报文一致,00 00 标识 modbus 协议
00 17数据长度,十六进制 0x0017,十进制数据长度为 23
FF从站 ID 唯一标识,十六进制 0xFF,十进制从站 ID 为 255
03功能编码,0x03 读保持寄存器
00 00读取寄存器起始位置,十六进制 0x00,十进制从下标 0 位置开始读取
00 0A读取寄存器长度,十六进制 0x000A,十进制读取寄存器长度 10

4. Modbus 主站 Poll 端

    工业中通常 PLC 作为主站,比如西门子 PLC 产品。以西门子 S7-200 产品为例

4.1 编写 Modbus 主站初始化程序

    初始化 Modbus 通信始终接通

    MBUS_CTRL 指令用于初始化、监视或禁用 Modbus 通信。
    ON 设置为始终接通
    Mode 指通信模式,输入的数值选择通信协议;1 标识启用 Modbus 协议,0 标识启用 PPI 系统协议;
    Baud 指波特率,此处设置为 9600;
    Parity 指奇偶校验位;0 不校验,1 奇校验,2 偶校验;
    Timeout 指等待从站应答的毫秒时间数;超时数值可设置为 1~32767,常设置为 1000;

4.2 编写实现 Modbus 主站读写 Slave 从站的通信程序

    从地址为 3 的 Slave 从站读取 DI 通道从 I0.0 开始的 16 位的值,存放到 VB0 开始的存储区中。

地址 00001 是 Q0.0,地址 10001 是 I0.0,地址 30001 是 AIWO,地址 40001 是 V 存储器;
V 寄存器支持位、字节、字、双字访问,
VB 表示存储区的一个字节 Byte,存放短整形数据
VW 表示存储区的一个字 Word,存放整形
VD 表示存储器的两个字 Double Word,存放双整形、浮点型数据

    MBUS_MSG 指令用于启动对 Slave 从站的请求并处理应答;
    EN 和 First 输入打开时, MBUS_MSG 指令启动对 Slave 从站的请求;
    Slave 从站地址
    RW 指定读取或写入动作;读为 0 写为 1
    Addr 指起始的 Modbus 地址;
    Count 指在该请求中读取或写入的数据元素的数目;对于读写线圈是读取或写入的位数;对于读写寄存器是字数;
    DataPtr 指 S7-200 CPU 的 V 存储器中与读取或写入请求相关的数据的间接地址指针;对于读取请求应该指向用于存储从 Slave 从站读取的数据的第一个 CPU 存储器位置;对于写入请求,指向要发送到 Slave 从站的数据的第一个 CPU 存储器位置;

    向地址为 3 的 Slave 从站写入 5 个保持寄存器数据,从 CPU 的 VB10-VB19 获取 5 个写数据后,写入 Slave 从站中的地址 40001-40005。

    程序运行后,就一直在寻址 SlaveID 为 3 的从站服务,对从站进行请求,相应的从站接收到请求后进行响应。

5. Modbus 从站 Slave 端

    此处通过 Java 实现 Modbus TCP 从站端服务。

5.1 编写 Slave 从站 Java 程序

    从站设置 TCP 连接,初始化一个从站 ModbusSlave,规定主站从站 host、port,规定功能编码为 0x03,初始化都保持寄存器,从偏移位 0 开始,存放 2 个数值型数据,启动 ModbusSlave 监听服务。

import com.intelligt.modbus.jlibmodbus.Modbus;
import com.intelligt.modbus.jlibmodbus.data.DataHolder;
import com.intelligt.modbus.jlibmodbus.data.ModbusHoldingRegisters;
import com.intelligt.modbus.jlibmodbus.slave.ModbusSlave;
import com.intelligt.modbus.jlibmodbus.slave.ModbusSlaveFactory;
import com.intelligt.modbus.jlibmodbus.tcp.TcpParameters;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.net.InetAddress;

/**
 * @author niaonao
 * @version 1.0.0
 * @since 2022/5/11
 */
public class ModbusSlaveLocal 
    private static final Log LOG = LogFactory.getLog(ModbusSlaveLocal.class);
    /**
     * 从站地址
     */
    private static final int SLAVE_ADDRESS = 0xFF;
    private static final int ONE_SECOND = 1000;
    private static final int SIZE = 2;

    /**
     * 从站IP、端口
     */
    private static final String SLAVE_HOST = "127.0.0.1";
    private static final int SLAVE_PORT = 501;

    public static void main(String[] args) 
        try 
            // 设置控制台输出主站和从站命令交互日志
            Modbus.setLogLevel(Modbus.LogLevel.LEVEL_DEBUG);

            // 创建读保持寄存器,从第 0 个位置开始写入 2 个数值数据;即写入数据到地址 40001-40002
            ModbusHoldingRegisters holding = new ModbusHoldingRegisters(SIZE);
            for (int i = 0; i < SIZE; i++) 
                holding.set(i, i);
            
            DataHolder dataHolder = new DataHolder();
            dataHolder.setHoldingRegisters(holding);

            // 创建从站
            TcpParameters tcpParameters = new TcpParameters();
            InetAddress address= InetAddress.getByName(SLAVE_HOST);
            tcpParameters.setKeepAlive(true);
            tcpParameters.setHost(address);
            tcpParameters.setPort(SLAVE_PORT);
            ModbusSlave slave = ModbusSlaveFactory.createModbusSlaveTCP(tcpParameters);
            slave.setServerAddress(SLAVE_ADDRESS);
            slave.setReadTimeout(ONE_SECOND);
            slave.setDataHolder(dataHolder);
            slave.listen();

            // 这部分代码主要是设置Java虚拟机关闭的时候需要做的事情,即本程序关闭的时候需要做的事情,直接使用即可
            if (slave.isListening()) 
                Runtime.getRuntime().addShutdownHook(new Thread() 
                    @Override
                    public void run() 
                        synchronized (slave) 
                            slave.notifyAll();
                        
                    
                );

                synchronized (slave) 
                    slave.wait();
                

                /*
                 * using master-branch it should be #slave.close();
                 */
                slave.shutdown();
            
         catch (Exception e) 
            LOG.warn("从站程序执行异常信息:" + e.getMessage(), e);
        
    

5.2 主站测试工具 Poll 通信从站 Java 程序

    测试工具 Modbus Poll 模拟请求 Slave ID 为 255 的从站服务。
    Poll 端使用测试工具测试,通过 SlaveId 地址寻址请求 Slave 从站,从地址 0 开始读取 2 个数据,即地址 40001、40002。
    响应报文可以看到,主站请求得到响应,响应报文包含了 Slave 端放入读保持寄存器的两个数据,数值 0 和数值 1。


    启动 Slave 端 Java 程序,Poll 配置后连接上 Slave 从站,请求正常响应,请求响应报文如下:

Tx:000453-05 AD 00 00 00 06 FF 03 00 00 00 02
Rx:000454-05 AD 00 00 00 07 FF 03 04 00 00 00 01

参考文章
ModBus协议报文格式解析说明
我是Modbus-RTU协议,我有两个兄弟
西门子 S7-200 Modbus RTU 主站编程

以上是关于Modbus的报文格式的主要内容,如果未能解决你的问题,请参考以下文章

modbus tcp报文如何监听

Modbus TCP 示例报文

Modbus TCP 示例报文

modbus 报文不知道协议时怎么破译 ,有大神指点下吗

modbus报文识别中主设备请求报文:06+01+00+16+00+21+1C+61表示的意思?

Modbus 协议从站开发通信西门子 PLC