BMS应用软件开发 — 13 Modbus协议详解
目录
13.1 MODBUS协议
13.1.1 物理接口
13.1.2 工作模式
13.1.3 协议版本
13.2 协议描述
13.2.1 报文格式
13.2.2 报文发送接受
13.3 Modbus-TCP/IP
13.3.1 数据帧
13.3.2 端口号
13.3.3 通信流程
13.3.4 Modbus poll和Modbus Slave实验
13.4 Modbus-ASCII
13.4.1 数据帧
13.4.2 ASCII 帧间隔
13.4.3 字符时间
13.5 Modbus-RTU
13.5.1 数据帧
13.5.2 通信过程
13.5.3 错误处理
13.1 MODBUS协议
13.1.1 物理接口
Modbus 协议属于应用层协议,协议本身并没有像 SPI,I2C,TCP/IP 定义物理层,只定义了数据包组织结构和内容的公共格式。所以它没有自己专属的数据链路层和物理层,所以需要依赖其他可用的物理层和数据链路层来传输数据。
例如可以选用串口(例如 RS232,RS485 和 RS422),也可以选择以太网口,但目前大多数应用都是通过串口 RS-485 作为物理层,如下图。
实际上不仅限于以上物理接口,由于 Modbus 属于应用层协议所以协议本身不管数据是经过何种网络进行通信的。所以还能以 USB,蓝牙,WiFi 等其他一切能够串行传输数据的总线作为物理层和数据链路层传输数据。
RS-485、RS-422、RS-232
- RS-485:半双工收发接口,这是最为常用的 Modbus 物理层,信号采用差分电平编码,用一对双绞线现场布线,抗干扰性能也不错
- RS-422:全双工收发接口,这种物理层也有比较多的应用,信号采用差分电平编码,需要两对双绞线现场布线,抗干扰性能也不错。与 RS-485 相比,其优势在于可以实现全双工,通信的效率高些,所需要的代价就是现场布线需要两对双绞线,增加了一定的成本。
- RS-232:全双工收发接口,这个基本用在点对点通信场景下,不适合多点拓扑连接,采用共模电平编码,一般需要 Rxd/Txd/Gnd 三根线连接。
13.1.2 工作模式
Modbus 协议是属于主从(Master/Slave)通信方式的协议。在所有节点中其中一个为 Master 节点,其余为 Slave 节点,在整个通信网络中 Master 节点至少且只有 1 个。
主从通信以 请求/应答 为主,每次通讯都是主站先发送指令(可以是广播指令,或是向特定从站的单播指令),从站响应指令,并按要求应答,或者报告异常。当主站不发送请求时,从站不会自己发出数据,从站和从站之间不能直接通讯(也就是说从站之间不能相互发送指令或访问)。
无论主站发送的是广播指令还是单播指令,实际上所有从设备都会完整接收命令。但单播指令只有指令中指明的 编号/地址 与设备 编号/地址 相同时设备才会执行及回应指令,编号/地址 与指令指明的 编号/地址 不同的从机将接收到的所有内容丢弃,而广播指令所有收到指令的设备都会执行指令,但不会给主机回应指令。
- 半双工通信:Modbus 由于请求/应答机制所以不能同步通信(同步通信需要收发双方以相同的节奏发送和接收数据),总线上每次只有一帧数据进行传输,属于半双工通信。
- Modbus 没有支持忙机制处理:例如主机给从机发送命令, 如果从机正在处理其他任务,此时从机将无法响应主机,所以需要通过软件的方式来判断是否正常接收。
13.1.3 协议版本
Modbus 协议目前分别定义了基于串口和以太网传输数据的规则,其中串口规则两种 Modbus RTU 和 Modbus ASCII,以太网规则一种 Modbus TCP/IP。
- Modbus ASCII 是一种文本协议,使用 ASCII 码表示数据。它使用起始字符(“:”)、从站地址、功能码、数据、结尾字符(换行符 CR/LF)等字段来定义通信内容,并采用的是 LRC 校验算法。数据以 ASCII 码的形式传输,通常是通过 RS-232 或 RS-485 等串行通信接口进行传输。
- Modbus RTU 是一种二进制协议,使用二进制码表示数据。它采用起始字符、从站地址、功能码、数据等字段来定义通信内容,并使用 CRC 校验位来保证数据的完整性。Modbus RTU 通常通过 RS-232、RS-485 或 RS-422 等串行通信接口进行传输。
- Modbus TCP/IP 是一种基于以太网的协议,使用 TCP/IP 协议栈进行通信。它使用以太网帧作为数据传输的封装,通过 IP 地址和端口号来标识设备。其占用的是 502 端口,数据帧主要包括两部分:MBAP(报文头)+PDU(帧结构),数据块与串行链路是一致的。Modbus TCP/IP 可以通过以太网、无线局域网等网络介质实现设备之间的远程通信。
Modbus 还有有一个扩展版本 Modbus PLUS(也叫 Modbus+ 或者 MB+),不过此协议是 Modicon 公司专有的,和 Modbus 不同。它需要一个专门的协处理器来处理类似 HDLC 的高速令牌旋转。我们不使用 MB+ 所以不深入去了解,我们只要了解 Modbus-TCP/IP,Modbus-RTU,Modbus-ASCII 这三种模式即可。
13.2 协议描述
13.2.1 报文格式
无论是三种传输模式中的哪一种,Modbus
帧格式都是一样的。Modbus 消息应用数据单元(ADU)由四部分组成:地址域+功能码+数据+差错校验。报文定义了一个与物理层无关的协议数据单元(简称 PDU),由两部分组成:功能码(Function Code) + 数据域(Data)(功能码 1 Byte,数据域不确定)
- 地址:指定目标设备的地址,在主从式架构中,主站通过地址选择与之通信的从站设备。地址范围通常为 0 - 247,其中 0 为广播地址,用于向所有从站发送消息。
- 功能码:表示要执行的操作类型,常见功能码如下:
-
- 01(读线圈状态):主站读取从站指定地址范围的线圈状态。
- 02(读离散输入状态):读取从站指定地址范围的离散输入状态。
- 03(读保持寄存器):读取从站指定地址范围的保持寄存器内容。
- 04(读输入寄存器):读取从站指定地址范围的输入寄存器内容。
- 05(写单个线圈):向从站指定地址的线圈写入 0 或 1 的状态。
- 06(写单个保持寄存器):向从站指定地址的保持寄存器写入一个 16 位的数据。
- 15(写多个线圈):向从站指定地址范围的多个线圈写入状态。
- 16(写多个保持寄存器):向从站指定地址范围的多个保持寄存器写入数据。
- 数据:包含了执行功能码所需的参数或要传输的数据。例如,在读取寄存器时,数据部分可能包含要读取的寄存器起始地址和数量;在写入寄存器时,数据部分则包含要写入的值。
功能码(Function Code)和数据区(Data)在不同类型的网络都是固定不变的。地址域和校验码(Checksum)则因网络底层的实现方式不同而有所区别。地址域包含了从站的地址,功能码告诉从站要执行何种功能,数据区是具体的数据内容。
存储区类型 | 对象类型 | 访问权限 | 存储区地址范围 | 功能 |
线圈寄存器 | 单个比特 | 只读 | 通常为 0x0000 - 0xFFFF 或 1 - 65536 | 存储布尔值,代表开关量状态,用于控制外部设备状态或获取开关状态反馈 |
离散输入寄存器 | 单个比特 | 读写 | 一般为 1x0001 - 1xFFFF(如 10001 - 165536 等) | 读取外部设备的开关状态,如传感器通断、按钮按下 / 松开等 |
保持寄存器 | 16bit | 只读 | 通常为 4x0001 - 4xFFFF(如 40001 - 465536 等) | 存储和传输数值型数据,用于存放测量值或设置设备参数 |
输入寄存器 | 16bit | 读写 | 一般为 3x0001 - 3xFFFF(如 30001 - 365536 等) | 读取外部设备的模拟量输入值,如传感器的电压、电流转换后的数字值 |
为什么命名为“线圈”和“寄存器?
在Modbus协议中,功能码被命名为“线圈”和“寄存器”,这源于其在工业自动化和控制系统中的应用背景。“线圈”通常指的是继电器或电磁线圈的状态,代表设备的开/关状态或数字输出,例如设备是否开启或关闭。寄存器通常存储的是16位或32位的数值,适用于处理模拟量或复杂的数据类型。
对于不同类型的网络,Modbus 的协议层实现是一样的,区别在于下层的实现方式,常见的有 TCP/IP 和 串行通讯 两种。
如上图所示,Modbus 串行传输的物理层是 RS-485/422 或 RS-232,数据链路层是 Modbus 的串行传输协议。Modbus TCP 传输的 1-4 层和我们日常使用的以太网,因特网一样,分别为物理层,数据链路层,网络层,传输层。同时标准规定 Modbus-TCP 默认采用的 TCP 端口号是 502。
13.2.2 报文发送接受
在 Modbus 通信中,主站通过发送帧向从站发起数据读取请求,具体解析如下:
组成部分 | 具体数值 | 含义 |
站地址 | 01 | 目标从站的地址编号,主站靠此定位通信对象 |
功能码 | 03 | 表示执行读输出寄存器(保持寄存器)操作 |
起始寄存器 | 00 00 | 指定读取数据的起始寄存器位置 |
寄存器长度 | 00 02 | 明确要连续读取的寄存器数量为 2 个 |
CRC 校验 | C4 0B | 用于校验数据传输过程中是否出现错误的循环冗余码 |
从站接收发送帧处理后返回回复帧,内容解析如下:
组成部分 | 具体数值 | 含义 |
站地址 | 01 | 作出响应的从站地址,与发送帧目标地址对应 |
功能码 | 03 | 与发送帧功能码一致,确认执行了读取操作 |
字节计数 | 04 | 表明后续具体数据的字节数,因读 2 个寄存器(每个 2 字节)共 4 字节 |
具体数据 | 01 46 01 3B | 从站返回的从指定寄存器读取到的实际数据 |
CRC 校验 | 5A 59 | 校验回复数据在传输中是否正确的循环冗余码 |
13.3 Modbus-TCP/IP
Modbus TCP是一种基于TCP/IP协议的Modbus通信协议,用于在客户机和服务器之间进行数据通信。它常用于工业自动化控制、电力监控与管理、温湿度监测等领域。Modbus TCP协议使用标准的TCP/IP协议栈,通过以太网进行通信,并支持多个设备同时访问同一个Modbus TCP服务器。
在 Modbus TCP 模式下,主站被称为客户端(Client),从站被称为服务器(Server)因为 Modbus 主站总是向 Modbus 从站查询操作数据,这和客户端与服务器的运作模式是相同的。
13.3.1 数据帧
对于 TCP/IP 通信 Modbus 协议引入一些附加域映射成应用数据单元(ADU)而 ADU 可分为 MBAP 和 PDU 两部分,这两部分如下关系:
- PDU = 功能码(Function Code) + 数据域(Data)(功能码 1 Byte,数据域长度不确定)。
- ADU = MBAP+PDU
数据帧组成如下图:
其中 MBAP(报文头)占 7 Bytes,功能码 1 Byte,数据域长度不确定,由具体功能决定,如下所示:
事务处理标识 | 协议标识 | 长度 | 单元标识符 |
2 Byte | 2 Byte | 2 Byte | 1 Byte |
- 事务处理标识,可以理解为报文的序列号,一般每次通信之后就要加 1 以区别不同的通信数据报文。
- 协议标识符,例如 00 00 表示的是 Modbus-TCP/IP 协议。
- 长度,表示接下来的数据长度,单位为字节。
- 单元标识符,可以理解为设备地址。
将 ADU 报文详细展开后如下图:
(1) 取消了校验位,TCP/IP 协议的数据链路层上就进行了 CRC-32 的校验,同时TCP/IP 是面向连接的可靠性的协议,因此应用层没必要再加上校验位。
(2) Slave 地址变成了单元标识符,当网络中的设备都使用 TCP/IP 协议,该地址是没有意义的,因为使用 IP 地址就能进行路由寻址,如果网络里还有串行通讯的设备,则需要使用网关来实现 Modbus-TCP/IP 到 Modbus-RTU/ASCII 之间的协议转换,这时用 Unit Identifier 来标识网关后面的每个串行通讯设备。
(3) 长度是指后面的字节总数,实际上数据区的长度是能确定的,有的功能码就可以确定数据区的长度(例如读寄存器功能码),有的功能码虽不能确定数据区长度,但是 Modbus 协议数据区包含有字节计数(这后面会说明)。表头增加的长度是为了应对有些情况下TCP/IP 协议会将应用层的数据拆包传输的场景。
(4) 事物处理标识符和协议标识符由 Client 生成,Server 的响应将复制这些参数。
13.3.2 端口号
在计算机网络中,一台计算机可以同时运行多个网络应用程序,当接收到一个网络数据包时,操作系统需要知道将这个数据包交给哪个应用程序处理。端口号就起到了这样的标识作用,它使得不同的应用程序能够在同一台计算机上同时进行网络通信而不会相互干扰。例如,当你在浏览器中访问一个网站时,浏览器会使用特定的端口号(通常是 80 或 443)与服务器上的 Web 服务进行通信。
IANA(Internet Assigned Numbers Authority)互联网编号分配管理机构给Modbus 协议赋予 TCP 端口号为 502,这是目前 Modbus 在仪表与自动化行业中唯一分配到的端口号。
13.3.3 通信流程
(1)连接建立:客户机主动建立TCP连接,与服务器进行通信。
(2)请求发送:客户机向服务器发送请求消息,请求读取或写入数据。请求消息中包含了事务标识符、协议标识符、长度字段、单元标识符、功能码以及相关的数据和操作参数。
(3)响应接收:服务器接收到客户机的请求后,根据请求的功能码执行相应的操作,并生成响应消息。响应消息中包含了事务标识符、协议标识符、长度字段、单元标识符、功能码以及请求的结果数据。
(4)异常处理:如果服务器无法满足客户机的请求,或者执行请求时发生错误,服务器将生成一个异常响应消息。异常响应消息包含了事务标识符、协议标识符、异常功能码和异常代码。
(5)连接关闭:当通信完成后,客户机可以选择关闭TCP连接。
13.3.4 Modbus poll和Modbus Slave实验
(1)打开这两个软件
(2)Modbus Slave连接设置
(3)Modbus Poll连接设置
(4)通讯设置好后,设置值,如下图。如果上面设置没问题,此时两边的号地址内容是同时变化:
13.4 Modbus-ASCII
13.4.1 数据帧
在 Modbus ASCII 模式下,主站是运行 Master 协议程序,从站是运行 Slave 协议程序。
起始位 | 设备地址 | 功能代码 | 数据数量 | 数据 | LRC高字节 | LRC低字节 | 结束符 |
: | 2 Bytes | 2 Bytes | N | N Bytes | 1 Byte | 1 Byte | CR, LF(回车换行) |
Modbus 以 ASCII 模式通信,在消息中的每个 8 Bit 字节都作为两个 ASCII 字符发送,也就是说使用两个字符来表示 1 个字节的十六进制值,可见所见即所得。
例如表示十六进制 35 需要使用 3 和 5 这两个字符,而每个字符都占用 1 个字节,字符 3 实际值为十六进制 33,字符 5 实际值为 35,所以为了表示 30 需要使用 16 Bits 数据,所以实际发送的数据为 00110011, 00110101,但这并不是最终使用的数据,接收端需要将其转换为原始值才能够使用。
13.4.2 ASCII 帧间隔
使用 ASCII 模式,消息以 : 冒号字符(ASCII 码 3A)开始,以回车换行符结束ASCII 码 0D,0A。
其它域可以用于表达十六进制数值的字符是 0-9,A-F。网络上的设备不断侦测 : 冒号字符,当每个节点设备接收到一个 : 冒号时,每个设备都解码设备地址域来判断是否是发给自己的。
消息中字符间发送的时间间隔最长不能超过 1 秒,否则接收的设备将认为传输错误,一个典型 ASCII 消息帧如下所示:
起始位 | 设备地址 | 功能代码 | 数据 | LRC 校验 | 结束符 |
1 个字符 | 2 个字符 | 2 个字符 | n 个字符 | 2 个字符 | 2 个字符 |
13.4.3 字符时间
所谓字符传输时间指的是传输一个 ASCII 字符需要花费的时间,一个 ASCII 字符包含 1 个字节(8 bits),所以传输一个字符需要花费传输 8 个数据位的时间(所以这里字符传输时间并不是真的字面意思传输字符,而是指代传输字节)。
然而实际上传输 1 个字节数据需要花费的时间并不只 8 个位时间,因为除了传输固有的 1 字节数据,还需要传输一些辅助功能位。例如发送 1 个字节需要固定起始位 1 位,数据位 8 位,校验位 1 位(可选的),停止位 1 位,其中 8 位数据位才是真正的有效数据,所以有如下公式来计算字符时间。
例如:固定起始位 1 位,数据位 8 位,奇/偶校验位 1 位,停止位 1 位,波特率为9600 bps,计算单个字符传输时间为:
13.5 Modbus-RTU
Modbus - RTU 是 Modbus 协议的一种实现方式,它采用二进制编码方式来表示数据,相比于 ASCII 模式,RTU 模式的数据传输效率更高,因为它每个字节可以携带更多的有效信息,在相同的波特率下能够传输更多的数据。该协议基于主从架构,主站(通常是控制器或计算机)发起通信请求,从站(如传感器、执行器等设备)根据请求进行响应。Modbus - RTU 采用串行通信方式,常见的物理层接口有 RS - 232、RS - 485 等。
13.5.1 数据帧
在 Modbus RTU 模式下,主站是运行 Master 协议程序,从站是运行 Slave 协议程序。
起始位 | 设备地址 | 功能代码 | 数据数量 | 数据 | CRC高字节 | CRC低字节 | 结束符 |
T1-T2-T3-T4 | 1 Bytes | 1 Bytes | N | N Bytes | 1 Byte | 1 Byte | T1-T2-T3-T4 |
- 从站地址:用于标识通信的目标从站设备,主站通过该地址选择与之通信的从站。地址范围通常是 1 - 247,其中 0 为广播地址,用于向所有从站发送消息,但广播消息不会有响应。
- 功能码:指示主站请求执行的操作类型,与前面介绍相同。常见的功能码有读取线圈状态(01)、读取离散输入状态(02)、读取保持寄存器(03)、读取输入寄存器(04)、写单个线圈(05)、写单个保持寄存器(06)、写多个线圈(15)、写多个保持寄存器(16)等。
- 数据域:包含执行功能码所需的具体参数或要传输的数据。例如,在读取寄存器时,数据域可能包含要读取的寄存器起始地址和数量;在写入寄存器时,数据域则包含要写入的值。数据域的长度根据功能码和具体操作而定。
- CRC 校验:循环冗余校验码,用于检测数据在传输过程中是否发生错误。主站在发送数据时会计算 CRC 校验值并添加到数据帧末尾,从站接收到数据后会重新计算 CRC 值并与接收到的校验值进行比较,如果不一致则认为数据传输有误。
13.5.2 通信过程
- 主站发起请求:主站根据需要向从站发送请求帧,请求帧包含从站地址、功能码和数据域等信息。例如,主站要读取从站地址为 1 的设备的保持寄存器,起始地址为 0,数量为 10 个,请求帧可能如下:
内容 | 从站地址 | 功能码 | 起始地址高字节 | 起始地址低字节 | 寄存器数量高字节 | 寄存器数量低字节 | CRC 校验高字节 | CRC 校验低字节 |
详情 | 01 | 03 | 00 | 00 | 00 | 0A | XX | XX |
- 从站接收并处理请求:从站接收到主站的请求帧后,首先检查从站地址是否与自己的地址匹配,如果匹配则根据功能码执行相应的操作。如果请求合法,从站会根据请求读取或写入相应的数据。
- 从站返回响应:从站处理完请求后,会向主站返回响应帧。响应帧包含从站地址、功能码、数据域和 CRC 校验等信息。对于上述读取保持寄存器的请求,从站的响应帧可能如下:
内容 | 从站地址 | 功能码 | 字节计数 | 数据 1 高字节 | 数据 1 低字节 | ... | 数据 10 高字节 | 数据 10 低字节 | CRC 校验高字节 | CRC 校验低字节 |
详情 | 01 | 03 | 14 | XX | XX | ... | XX | XX | XX | XX |
- 主站接收并处理响应:主站接收到从站的响应帧后,会检查 CRC 校验值是否正确,如果正确则根据功能码和数据域解析响应数据,完成一次通信过程。
13.5.3 错误处理
在 Modbus - RTU 通信中,可能会出现各种错误,如数据传输错误、从站设备故障等。为了处理这些错误,协议定义了异常响应机制。
- 异常响应帧:当从站接收到的请求存在错误或无法执行时,会返回异常响应帧。异常响应帧的功能码与请求帧的功能码相同,但最高位会被置为 1,同时数据域包含一个异常码,用于指示具体的错误类型。常见的异常码有非法功能码(01)、非法数据地址(02)、非法数据值(03)、从站设备故障(04)等。
- 错误检测与处理:主站在接收到异常响应帧后,会根据异常码进行相应的处理。例如,如果接收到非法功能码异常,主站会检查请求帧的功能码是否正确;如果接收到从站设备故障异常,主站可能会尝试重新发送请求或采取其他措施。