MODBUS应用协议Spec导读intro

MODBUS应用协议Spec导读intro

文章目录

  • MODBUS应用协议Spec导读intro
    • 引言
    • MODBUS简介
      • MODBUS RTU 协议
    • MODBUS协议
      • MODBUS协议综述
      • MODBUS的主机和从机
      • MODBUS数值编码
      • MODBUS数据类型
      • MODBUS地址映射模型
      • MODBUS传输的实现
      • MODBUS功能码
        • 以功能码`0x01`为例
    • 参考文献

引言

在设计一些小型的多微控制器联动系统时,希望通过一种简单的方式组网,暂不考虑ENET或者CAN总线,虽然这两个外设用于组网确实不错,但对微控制器有比较高的要求,使用这些外设有一定的门槛,协议栈相对复杂,外围电路的成本也比较高。UART是最简单的通信外设,能搭配UART的外设组网协议栈,最常用的就是MODBUS。

笔者阅读MODBUS官网(modbus.org)的《ModBus Over Serial Line》和《ModBus Application Protocol》两篇Spec文档,了解了官方对MODBUS阐释的内容,形成一个导读的材料,作为自己系统梳理MODBUS这个知识点的记录,也供后续具体应用时快速查阅相关资料建立了一个索引。《ModBus Over Serial Line》是面向数据连路层的,更接近物理层,开发者如果需要在自定义的传输系统中适配MODBUS,是值得详读的,可领悟设计MODBUS总线协议的原理和方法。《ModBus Application Protocol》是面向应用层的,对于仅使用MODBUS的开发者,可以更关注这篇文档。

MODBUS简介

MODBUS是由Modicon公司(已被施耐德收购)于1979年针对PLC开发的一种通信协议。MODBUS协议最早被用在PLC控制器中,准确的说是Modicon公司的PLC控制器,这也是Mod-Bus名称的由来。后来Modicon被施耐德(Schneider)收购。MODBUS协议广泛应用在工业控制器、HMI和传感器上,逐渐被其他厂商所接受,成为了一种主流的通讯协议,用于和外围设备进行通讯。

在这里插入图片描述

MODBUS协议作为当今工业控制领域的通用通讯协议,在无数物联网产品中得到应用,工业、农业等物联网解决方案中都有其身影。MODBUS网络是一个工业通信系统,由智能终端的可编程序控制器和计算机,通过公用线路或局部专用线路连接而成。其系统结构既包括硬件、亦包括软件,应用于各种数据采集和过程监控。通过MODBUS协议,控制器相互之间、或控制器经由网络(如以太网)可以和其它设备之间进行通信。MODBUS协议使用的是主从通讯技术,即由主设备主动查询和操作从设备。一般将主控设备方所使用的协议称为MODBUS Master,从设备方使用的协议称为MODBUS Slave。典型的主设备包括工控机和工业控制器等;典型的从设备如PLC可编程控制器等。MODBUS通讯物理接口可以选用串口(包括RS232和RS485),也可以选择以太网口。

MODBUS网络只有一个主机,发出通讯信号,多个从机,网络可支持247个之多的远程从属控制器,但实际所支持的从机数要由所用通信设备决定。采用这个系统,各PC可以和中心主机交换信息而不影响各PC执行本身的控制任务。

目前MODBUS规约主要使用的是ASCII、RTU、TCP等,并没有规定物理层。目前MODBUS常用的接口形式主要有RS232C,RS485,RS422,也有使用RJ45接口的,大多数MODBUS设备通信通过串口EIA-485物理层进行。MODBUS的ASCII、RTU协议则在此基础上规定了消息、数据的结构、命令和应答的方式。MODBUS数据通信采用Master/Slave方式(主/从),即Master端发出数据请求消息,Slave端接收到正确消息后就可以发送数据到Master端以响应请求;Master端也可以直接发消息修改Slave端的数据,实现双向读写。

所以当我们提及MODBUS协议时,要确定是哪种模式:RTU、ASCII或TCP,3种模式区别还是很大的:

  • 基于串口的MODBUS-RTU 数据按照标准串口协议进行编码,是使用最广泛的一种MODBUS协议,采用CRC-16_MODBUS校验算法。
  • 基于串口的MODBUS-ASCII 所有数据都是ASCII格式,一个字节的原始数据需要两个字符来表示,效率低,采用LRC校验算法。
  • 基于网口的MODBUS-TCP 基于TCP/IP协议,占用502端口,数据帧主要包括两部分:MBAP(报文头)+PDU(帧结构),数据块与串行链路是一致的。

MODBUS的ASCII、RTU协议规定了消息、数据的结构、命令和就答的方式,数据通讯采用Maser/Slave方式,Master端发出数据请求消息,Slave端接收到正确消息后就可以发送数据到Master端以响应请求;Master端也可以直接发消息修改Slave端的数据,实现双向读写。

MODBUS协议需要对数据进行校验,串行协议中除有奇偶校验外,ASCII模式采用LRC校验,RTU模式采用16位CRC校验,但TCP模式没有额外规定校验,因为TCP协议本身就是一个面向连接的可靠协议。对于MODBUS的ASCII、RTU和TCP协议来说,其中TCP和RTU协议非常类似,只要把RTU协议的两个字节的校验码去掉,然后在RTU协议的开始加上5个0和一个6并通过TCP/IP网络协议发送出去即可。

另外,在具体的工业监控环境中,MODBUS采用主从方式定时收发数据,在实际使用中如果某Slave站点断开后(如故障或关机),Master端可以诊断出来,而当故障修复后,网络又可自动接通,MODBUS协议的可靠性较好。

MODBUS RTU 协议

MODBUS在7层OSI参考模型中属于第七层应用层,数据链路层有两种:基于标准串口协议和TCP协议,物理层可使用3线232、2线485、4线422,或光纤、网线、无线等多种传输介质。

MODBUS RTU 协议是一种开放的串行协议,广泛应用于当今的工业监控设备中。该协议使用 RS-232 或 RS-485 串行接口进行通信,并得到市场上几乎所有商业 SCADA、HMI、OPC 服务器和数据采集软件程序的支持。

MODBUS RTU 协议使用主/从技术在设备之间进行通信。这意味着,任何使用MODBUS RTU 协议的应用程序都将有一个MODBUS主站和至少一个MODBUS从站:MODBUS Master 通常是一台运行软件的主机监控计算机,它将与一个或多个MODBUS Slave 设备进行通信。MODBUS 从设备是执行系统参数测量和控制系统中的开/关设备的设备。为了执行这些任务,主站向MODBUS 从站发送消息,请求执行特定任务。

MODBUS RTU 协议使用格式化的消息在主机和从机之间进行通信。消息由系统 Master 发起并发送到 Slave 设备。然后,从站以请求的数据进行响应,或者确认它执行了请求的功能。所有进出主站的消息都包含一个两字节(16 位)CRC(循环冗余校验)校验和值,用于错误检查。如果将无效请求传输到MODBUS 从站,则会返回一个字节(8 位)错误代码值,说明请求错误的原因。

MODBUS 主站消息包含几个重要的信息。每条消息都以接收消息的设备的从地址开始。接下来是要执行的功能编码(或命令)。后面是指定函数正确执行所需的任何数据。从地址是一个单字节(8 位)值,可用值范围在 0-247 之间。MODBUS 功能码也是一个字节值,并且在协议中定义了许多标准化功能码。支持所请求功能所需的任何数据值的长度将是一个或多个字节。MODBUS 从站响应消息将包含响应的从站地址、功能编码和主站请求的任何必要数据。

MODBUS协议

MODBUS协议综述

MODBUS协议定义了独立于物理层上的一个简单的协议数据单元(PDU,Protocol Data Unit),在一些具体的总线或者网络上实现的MODBUS还可以引入一些额外的数据段到应用数据单元(ADU,Application Data Unit)。如图x所示。
MODBUS应用协议Spec导读intro_第1张图片

图x 通用的MODBUS通信帧

由Client发起MODBUS传输请求,创建MODBUS的APU,告诉Server要执行什么命令。MODBUS的应用协议定义了由Client发起的请求的格式。

MODBUS数据单元的功能码(Function Code)为1字节,其值的有效范围是1-255,其中128-255是为使用异常响应预留的)。当Client发送一条消息到Server:其中的功能码将告知Server执行什么功能。有时候,还会在基本的功能码后面(占用数据区的空间)定义子功能码(Sub-function code),以表示更细分的命令;数据段包含了功能码的参数信息,例如,可以指定离散的寄存器地址,将要处理的元素的数量,以及本数据字段的长度(命令码会定义数据部分的长度和含义)等等。如果传输过程中没有出现错误,Server顺利接收到消息帧之后,将会在数据段中装好Client请求的数据,然后再回消息给Client。如果传输或者执行功能码的过程中出现了错误,Server将会在数据段中填入一个异常码(Exception Code),告知Client自己将要采取的措施。

例如,一个Client将要从一组离散的输入输出信息中读取一个开关量信息,或者向一组寄存器写数,Server将会回复给Client一个应答,其中,使用功能码段来指示操作正常(error-free),或者某个特定的错误(exception)。如果是一个正常的应答,Server将只是回复(echo)给Client之前相同功能码的消息帧。如图x所示。
MODBUS应用协议Spec导读intro_第2张图片

图x MODBUS传输应答正常

当Server执行命令的过程中出现异常,Server将会回复一个对应于原功能码,但最高位置1的“功能码”。

MODBUS应用协议Spec导读intro_第3张图片

图x MODBUS传输应答异常

MODBUS PDU的长度受限于最早期基于串行线路 网络实现的MODBUS中定义的帧长度(最长的RS485 ADU长度为256字节)。因此:

  • 串行线路上的MODBUS PDU长度 = 256字节 - Server地址(1字节)- CRC(2字节)= 253字节

对应地:

  • RS232 / RS485 ADU = 253字节 + Server 地址(1字节)+CRC(2字节) = 256字节
  • TCP MODBUS ADU = 253字节 + MBAP (7字节) = 260字节

在MODBUS传输的过程中,定义了3种PDU:

  • MODBUS请求数据包,MODBUS Request PDU,mb_req_pdu
  • MODBUS应答数据包,MODBUS Response PDU,mb_rsp_pdu
  • MODBUS异常应答数据包,MODBUS Exception Response PDU,mb_excep_rsp_pdu

其中,MODBUS请求数据包和应答数据包的数据格式如下:

功能码 请求数据
1字节: MODBUS功能码 N字节:对应于具体的功能码,通常包含变量的引用、变量的数量、数据偏移地址、子功能码等等。

MODBUS异常应答数据包的数据格式如下:

异常功能码 请求数据
1字节:MODBUS功能码+0x80 1字节:在异常功能码表中定义的编码,见后表。

MODBUS的主机和从机

MODBUS是一主多从系统:

  • 整个系统中只有一个主机,主机可以向系统中的其它从机发送命令并处理应答消息。通信系统中的通信均由主机发起。
  • 从机也不会主动发起通信,仅能在主机的请求下传输数据,从机之间不会进行通信

但在2020年,MODBUS组织专门发文(https://MODBUS.org/docs/Client-ServerPR-07-2020-final.docx.pdf),声明在后续的MODBUS公文中,使用"Client-Server"取代之前的"Master-Slave",描述MODBUS的通信过程。

MODBUS主机发起2种类型的通信过程:

  • 点对点通信(unicast mode),主机向一个从机发出通信请求,通过从机的地址定位特定的从机。主机向从机发送命令,从机回复主机一条消息。
  • 广播通信(broadcast mode),主机向系统中的所有从机发信,但不需要从机应答。通常可以使用广播群发写命令,所有的从机必须接收主机群发的命令。“0”号地址被预留,专用于广播通信的地址。

MODBUS数值编码

MODBUS使用大端编码表示地址和数据内容,这意味着,如果要传输一个多字节的数据,高位部分的字节将被优先传输。例如:当要传送一个16位的值0x1234,则拆成字节流后,先传送0x12,再传送0x34

MODBUS数据类型

MODBUS建立了若干个数据类型,每个数据类型均有其各自的特性,其中4个主要的类型如下表x所示。

表x MODBUS数据类型
数据类型 对象类型 读写属性 说明
分立的输入(Discrete Input) 单个bit位 只读 这个类型的数据可以表示一个IO系统的状态,相当于是状态标志位
线圈???(Coils) 单个bit位 可读可写 这个类型的数据可以被应用程序修改,相当于是变量位。
输入寄存器(Input Registers) 16-bit字 只读 这个类型的数据可以表示一个IO系统的状态,相当于是一组状态值。
保存数据的寄存器(Holding Register) 16-bit字 可读可写 这个类型的数据可以被应用程序修改,相当于是变量字。

NOTE:这里的4种数据类型的名字有点古怪,但从功能上看,分别对应单个bit位只读(状态)或者可读可写(变量),和16b字的只读(状态)或者可读可写(变量),在后续描述的内容中,为了便于读者理解,将使用新的名字进行命名:位状态、位变量、寄存器状态、寄存器变量。

MODBUS规定,每种数据类型均可以有最多65536个数据元素(16位编址)。

很明显,所有通过MODBUS管理的数据(位,寄存器)必须位于设备的内存中。但是内存中的物理地址同MODBUS的数据编址不是一回事,MODBUS的数据地址空间可以基于实际内存的物理地址建立映射(例如在物理内存空间中创建一个数组,以开辟一块内存作为MODBUS的数据地址空间)。MODBUS的数据地址编号是从0开始的无符号整型数。

在实际实现MODBUS时,开发者可以为4种不同的数据类型开辟4块独立的空间,分别用于建立各自的地址映射。如图x所示。

MODBUS应用协议Spec导读intro_第4张图片

图x 独立分布的modbus数据类型

当然,也可以将4种数据类型映射到同一块内存区,只是以不同的方式访问同一块物理内存。如图x所示。
MODBUS应用协议Spec导读intro_第5张图片

图x 映射在同一块物理内存上的modbus数据类型

MODBUS地址映射模型

MODBUS应用协议明确定义了PDU的编址规则:

  • 在PDU中,每个数据的地址范围为0-65535
  • 在数据类型块中,其中的元素编号为1到n。
  • 数据地址空间同具体的物理内存之间的映射,可由设备供应商(系统开发者)自行定义。

前面两条规则的意思是,虽然地址编址是从0开始,但MODBUS通信帧中,要对这些存储单元进行索引,就得使用从1开始的计数。如图x所示。

MODBUS应用协议Spec导读intro_第6张图片

图x MODBUS中错位的地址映射

从图x中可以看出,其实PDU的地址映射还是正常的从0开始索引,不正常的只是MODBUS数据类型内部的编号而已,所幸用户能看到的,也仅是PDU的地址映射,影响不大。开发者在自己的设备上适配MODBUS协议时,需要特别注意一下。

MODBUS传输的实现

MODBUS Client作为请求的发出者,只要按照顺序发出字节流即可。但Server端需要时刻监听传输端口,需要考虑实现一个异步监听的机制。MODBUS的应用Spec文档中,还提供了一个建议的实现方法,通过状态机解析MODBUS的通信帧。如图x所示。

MODBUS应用协议Spec导读intro_第7张图片

图x MODBUS Server实现解析通信帧的状态机

当Server处理掉一个请求,就会回应给Client一个应答数据包。应答数据包分为正常应答数据包和异常应答数据包,前文中有详细介绍,这里不再赘述。

MODBUS功能码

前文中介绍了MODBUS通信数据包中包含功能码。具体来看,MODBUS中的功能码分为三个大类:

  • 公用功能码(Public Function Codes)。这是由MODBUS组织约定,所有的MODBUS统一实现的。
  • 用户自定义功能码(User-Defined Function Codes)。用户自定义功能码的编号有两个区间,65-72,100-110。用户可以在公用功能码之外,自定义实现定制的功能码。不同设备商实现的自定义功能码可能不相同,哪怕是同一个编号的功能码,实现的功能也可能不同。MODBUS组织保留了征用用户自定义功能码的权限,这意味着,用户自定义的功能码在向后兼容时,仍存在一定的风险。
  • 保留功能码(Reserved Function Codes)。一些公司为了维护老产品,但是尚未公开的功能码。这些预留的功能码也被记录在Spec的附录A中。

这三大类功能码在编址空间中的分布,如图x所示。

MODBUS应用协议Spec导读intro_第8张图片

图x MODBUS功能码分布

NOTE:MODBUS数据包PDU中的功能码字段是1字节,值范围是·0-255,这里列写的有效功能码是 0-127(7位有效),128-255对应功能码字节的第8位为1,用于表示对应的功能码执行异常。

在MODBUS的应用协议Spec里,用大量的篇幅介绍了典型的若干个公共功能码的含义和用法,每个功能码对应的参数也不尽相同,开发者在使用时可以具体详查。这里展现Spec文档中介绍的命令。如图x所示。

MODBUS应用协议Spec导读intro_第9张图片

图x MODBUS应用协议Spec中对命令码的具体介绍

以功能码0x01为例

本文以功能码0x01 读1-bit数为例,说明MODBUS数据包的应用。

这个功能码可用于读取位于远程设备(Server)的从1到2000个连续的1位数的状态,请求的PDU数据包中指定了读取位的起始地址和读取的数量。正如前文介绍的,PDU中使用的编址从0开始,因此在Server中编号为1-16的1-bit位数的地址,在PDU中将以0-15表示。

Server回应的包含各个1-bit数的PDU数据包中,见使用数据段的每1位表示读到的数据位的值。例如,可以表示某个开关量的状态:1表示ON0表示OFF。在数据包的数据流中,高地址的字节先传送,低地址的位数据位于LSB,逐次排列。

如果请求读取和应答的1-bit数的数量不是8的整数倍(不能刚好被打包成字节),那么最后1字节的高位表示的空位将被用0填满。Byte Count字段将用于指定读取数据位的数量。

请求PDU:

功能码 1字节 0x01
起始地址 2字节 0x0000 - 0xFFFF
1-bit数的数量 2字节 1 - 2000(0x7D0)

应答PDU:

功能码 1字节 0x01
字节数量(Byte Count) 1字节 N
1-bit数的值 n字节 n = N 或者 N+1

其中,N = (1-bit数的数量) / 8,如果不能整除,则N再加1,容纳多余的零头。

异常应答PDU:

功能码 1字节 原功能码 + 0x80
异常码 1字节 01020304

一个具体的通信实例:

  • 请求PDU的字节流是:01 00 13 00 13
  • 应答PDU的字节流是:01 03 CD 6B 05

发送PDU描述的是,Client要从Server读开始地址为0x00130x0013(19)个位的值。

应答PDU描述的是,返回0x03个字节,这3个字节的二进制码为11001101 01101011 00000101,分别对应18 - 1110 - 32 - 0,最后一个字节的高5位置就被填充为0了。

MODBUS应用协议Spec还很贴心地给出了erver读1-bit数的状态图,检测字节流的有效性后再执行对应的功能。如图x所示。

MODBUS应用协议Spec导读intro_第10张图片

图x MODBUS Server读1-bit数的状态图

每个命令的格式不尽相同,不需要死记硬背。更多的命令,开发者可根据具体需要,逐个查询Spec文档详解即可。

参考文献

  • https://MODBUS.org/specs.php
  • https://MODBUS.org/docs/MODBUS_Application_Protocol_V1_1b3.pdf
  • https://MODBUS.org/docs/MODBUS_over_serial_line_V1_02.pdf
  • 《带你聊透MODBUS通信协议》,https://zhuanlan.zhihu.com/p/556769945
  • 《MODBUS通讯协议完整介绍》,https://zhuanlan.zhihu.com/p/145546574

END

你可能感兴趣的:(嵌入式系统架构设计,嵌入式系统,单片机,modbus)