Modbus既然是一种通信协议,那它就应该有规定的通信格式用于在设备之间的指令接收与识别。
本文就着重讲讲Modbus协议的RTU帧和ASCII帧。
Modbus帧在串行链路上的格式如下:
![数据帧格式 – RTU帧 & ASCII帧的区别-Modbus通讯协议要点第4部分插图1 数据帧格式 – RTU帧 & ASCII帧的区别-Modbus通讯协议要点第4部分插图1](https://www.modbus.cn/wp-content/themes/module2/themer/assets/images/lazy.png)
在上图的格式中:
1)地址域:指代的是子节点地址。合法的子节点地址为 0 – 247。 每个子设备被赋予 1 – 247 范围中的地址。主节点通过将子节点的地址放到报文的地址域对子节点寻址。当子节点返回应答时, 它将自己的地址放到应答报文的地址域以让主节点知道哪个子节点在回答。
2)功能码:指明服务器要执行的动作。
3)数据域:功能码后面的有表示含有请求和响应参数的数据。
4)错误检验:是对报文内容执行 “冗余校验” 的计算结果。根据不同的传输模式 (RTU or ASCII)使用两种不同的计算方法。
上面说明了Modbus的帧格式,是一种规定的数据打包的规约。
Modbus中有两种串行传输模式: RTU 模式 和 ASCII 模式。它定义了报文域的内容在线路上串行的传送。它确定了信息如何打包为报文和解码。
所有设备必须实现 RTU 模式,ASCII 模式是备选项。
1、Modbus RTU帧模式
RTU帧指的是什么呢?简单而言就是报文中的每个字节都是用十六进制表示的。
RTU帧中的每个字节数据的格式定义如下:
每个字节为8bit
报文中每个 8 位字节含有两个 4 位十六进制字符(0–9, A–F)
Bits per Byte:
1 起始位
8 数据位,首先发送最低有效位
1 位作为奇偶校验
1 停止位
注 : 使用无校验要求 2 个停止位。
每个字节为8bit
报文中每个 8 位字节含有两个 4 位十六进制字符(0–9, A–F)
Bits per Byte:
1 起始位
8 数据位,首先发送最低有效位
1 位作为奇偶校验
1 停止位
注 : 使用无校验要求 2 个停止位。
字符的传送流是LSB先发送,最后才是MSB,如下:
有奇偶校验的:
无奇偶校验的:
重点来了,RTU的报文帧格式:
Modbus RTU帧的最大长度为256个字节。
2、Modbus ASCII帧模式
Modbus ASCII帧中规定报文的每个字节数据以两个ASCII字符进行发送。
怎么理解呢?
例 : 有一个数据字节为 0X5B,它会被编码为两个字符 : 0x35 和 0x42 (ASCII 编码 0x35 =”5″, 0x42 =”B” )。
ASCII 模式节每个字节 (10 位 ) 为的格式为 :
报文中每个 ASCII 字符含有 1 个十六进制字符
Bits per Byte:
1 起始位
7 数据位, 首先发送最低有效位
1 位作为奇偶校验
1 停止位
注 : 使用无校验要求 2 个停止位。
报文中每个 ASCII 字符含有 1 个十六进制字符
Bits per Byte:
1 起始位
7 数据位, 首先发送最低有效位
1 位作为奇偶校验
1 停止位
注 : 使用无校验要求 2 个停止位。
字符是如何串行传送的:
有奇偶校验的:
无奇偶校验的:
Modbus ASCII的报文帧格式:
![数据帧格式 – RTU帧 & ASCII帧的区别-Modbus通讯协议要点第4部分插图9 数据帧格式 – RTU帧 & ASCII帧的区别-Modbus通讯协议要点第4部分插图9](https://www.modbus.cn/wp-content/themes/module2/themer/assets/images/lazy.png)
ASCII报文帧与RTU报文帧有很大的不同,ASCII报文帧中是带有开头和结束标识符的,这对设备接收报文帧很方便。设备可以很方便的知道一个新报文帧的开头,并且知道报文什么时候结束了。
RTU报文帧中并没有这样的标识符,所以在接收报文帧的时候就需要做些处理,方能判断报文是否完成了一帧数据的接收。
ASCII报文帧中用冒号(:)(ASCII的十六进制为0x3A)作为起始,用回车换行(CR LF)(ASCII的十六进制为0x0D 0x0A)作为结束。
由于ASCII模式下每个字符字节需要用两个字符编码,所以为了确保 ASCII 模式 和 RTU 模式在 Modbus 应用级兼容,ASCII数据域最大数据长度为 (2×252) 是 RTU 数据域 (252) 的两倍。因此,ModbusASCII 帧的最大尺寸为 513 个字符。
3、RTU帧与ASCII帧的传输区别
前面已经分析了RTU报文帧和ASCII报文帧的区别,RTU报文帧是不带开始和结束标识符的,而ASCII报文帧中带有开始和结束标识符。所以在设备接收RTU帧和ASCII帧的时候处理方式就会有所不同。
(1)RTU帧的报文传输
现在思考一个问题:RTU帧中因为没有开始和结束的标识符,设备要怎么知道已经接收完成了一帧报文了呢?
为了能够确认报文被完整接收,不至于接收到不完整的报文就进行报文解析和处理,所以必须要想办法去确认一帧报文已经完成接收,然后再去处理。
在RTU模式中,为了标识不同的报文帧,在报文帧之间插入一个空闲时间间隔,在两帧报文之间用至少3.5个字符的空闲时间来区分不同的帧,同时标识一帧是否已经完成接收。这个时间也称为t3.5时间间隔。
这样的操作方式看下图进行理解:
![数据帧格式 – RTU帧 & ASCII帧的区别-Modbus通讯协议要点第4部分插图11 数据帧格式 – RTU帧 & ASCII帧的区别-Modbus通讯协议要点第4部分插图11](https://www.modbus.cn/wp-content/themes/module2/themer/assets/images/lazy.png)
如果前面开始了一次报文帧的传输,接收设备从空闲状态中被唤起,就需要多接收进行一个超时计时机制,用以确认报文帧是否已经接收完成。就如上图中的帧1和帧2之间如果间隔的时间等于或者超过了t3.5所设定的空闲等待时间,就可以认为前面的帧1已经接收完成,后面再过来的数据就属于帧2的数据。
在RTU帧中还有一个讲究的地方:因为报文帧本质是用字符流进行发送的,所谓为了区分不同的报文帧就需要用到t3.5的字符间隔。但是报文帧中的每个字符要怎么确认是连续的呢?
所以为了确认字符流的发送连续,就要使用到t1.5字符时间。看下图:
从上图中可以清晰看到:如果两个字符之间的空闲间隔大于 1.5 个字符时间,则报文帧被认为不完整应该被接收节点丢弃。小于或者等于1.5个字符的时间则认为正常。
上面说的t1.5和t3.5这两个时间,其实并不是一定应用的。为什么呢?
因为时间项目应用中,很多时候多报文帧的接收都会涉及到中断,特别是在通信速率很高的情况下,会频繁的快速中断,对cpu的负担是很重的,这个时候这t1.5和t3.5的时间就会变得很短暂,并不是很好处理。
所以,t1.5和t3.5这两个时间一般是在通信速率在19200Bps或以下的时候才需要去严格约定。
(2)ASCII帧的报文传输
由于ASCII报文帧与RTU报文帧有着很大的不同,ASCII报文帧是有起始和结束标识符的,而RTU帧没有这样的标识。所以ASCII报文帧的接收就简单方便多了,也不需要什么t3.5的帧间隔时间。
但是呢,为了保证接收的报文帧连续,还是可以约定字符间的传输时间的。一般认为,报文中的字符时间间隔可以达到一秒,如果超过了这个时间间隔,就认为发生了错误,要废弃掉这一帧报文数据,重新开始接收。
4、RTU帧和ASCII帧的传输状态分析
(1)RTU帧的传输状态:
![数据帧格式 – RTU帧 & ASCII帧的区别-Modbus通讯协议要点第4部分插图15 数据帧格式 – RTU帧 & ASCII帧的区别-Modbus通讯协议要点第4部分插图15](https://www.modbus.cn/wp-content/themes/module2/themer/assets/images/lazy.png)
上面状态图可以获取的信息:
1)从 “初始” 态到 “空闲” 态转换需要 t 3.5 定时超时,用以保证帧间延迟。
2)“空闲” 态是没有发送和接收报文要处理的正常状态。
3)在 RTU 模式, 当没有活动的传输的时间间隔达 3.5 个字符长时,通信链路被认为在 “空闲”态。
4)当链路空闲时, 在链路上检测到的任何传输的字符被识别为 帧起始。 链路变为 “活动” 状态。然后, 当链路上没有字符传输的时间间个达到 t3.5 后,被识别为 帧结束。
5)检测到帧结束后,完成 CRC 计算和检验。然后,分析地址域以确定帧是否发往此设备,如果不是,则丢弃此帧。 为了减少接收处理时间,地址域可以在一接到就分析,而不需要等到整个帧结束。这样,CRC 计算只需要在帧寻址到该节点 (包括广播帧) 时进行。
(2)ASCII帧的传输状态
![数据帧格式 – RTU帧 & ASCII帧的区别-Modbus通讯协议要点第4部分插图17 数据帧格式 – RTU帧 & ASCII帧的区别-Modbus通讯协议要点第4部分插图17](https://www.modbus.cn/wp-content/themes/module2/themer/assets/images/lazy.png)
上面状态图可以得到的信息:
1)“空闲” 态是没有发送和接收报文要处理的正常状态。
2)每次接收到 “:” 字符表示新的报文的开始。如果在一个报文的接收过程中收到该字符,则当前地报文被认为不完整并被丢弃。而一个新的接收缓冲区被重新分配。
3)检测到帧结束后,完成 LRC 计算和检验。然后,分析地址域以确定帧是否发往此设备,如果不是,则丢弃此帧。 为了减少接收处理时间,地址域可以在一接到就分析,而不需要等到整个帧结束。