Modbus协议栈模型

1:Modbus协议简介

     Modbus协议主要描述的是应用层的信息封装格式,处于OSI模式的第七层(应用层)。Modbus的物理层可以是RS-485、Ethernet II /802.3。Modbus协议栈的层次图:
            

        本文主要介绍Modbus使用物理层是EIA/TIA-485的情况。Modbus主要内容为应用层协议,所以在现实使用中可以将EIA/TIA-485(485)和Ethernet II /802.3(以太网)不同的物理连接网络通过Modbus协议组成统一的系统。
使用EIA/TIA-485这种串行通讯方式的Modbus协议框图:


物理层的EIA/TIA-485大家比较熟悉,现场总线通讯很多设备都使用485通讯。下面重点介绍一下Figure 2 中的 Data Link 层和Application层。
Application层主要目的是定义应用层的功能和参数。应用层帧格式见图:

Modbus应用层的Function Code 就是我们熟悉的功能码,常见的有04(read input register) 03(Read Holding Registers)等。这些内容大家比较熟悉,就不一一说明了。
具体功能码含义可参见文章最后的相关资料及工具。

Data Link 层主要目的是确定总线上的具体从机以及检验数据帧传输是否正确。Data Link层的数据帧格式见图:

其中Address field域是地址域,现场使用485总线,总线上可能存在很多设备,这个地址主要用于从总线上选择一个具体的设备。CRC (or LRC是检验位)用于检验数据,确保传输正确。
在485总线上使用Modbus协议,有两种主要方式:RTU ASCII。RTU传输方式传输的数据帧为二进制数据,ASCII传输方式传输的是ASCII码。举例来说要发送 0x31(十进制数)使用RTU直接发送0x31就可以(占用一个byte),而ASCII码传输方式则需要发送0x33和0x31这两个字节(即十六进制数0x31的 高低位分别占用一个byte)。
两种传输方式各有利弊,使用RTU传输效率高,使用ACSII可读性好。
Modbus协议是一种主从式协议,即主站发起通讯,从站响应这种模式。
 最后,给大家一个看一个完整的Modbus协议帧格式:

关于Modbus的具体协议规定和Modbus在串行传输(485)中的使用,请大家查看4:相关资料及工具 里的

Modbus_Application_Protocol_V1_1b3.pdf
Modbus_over_serial_line_V1_02.pdf

其他Modbus相关资料请参考网站:http://www.modbus.org/

2:FreeMODBUS移植

     FreeMODBUS是一个开源的MODBUS协议栈,使用ANSI C语言编写,可在常见的处理器上移植(不需要嵌入式操作系统的支持,当然可以通过很简单的修改可以在嵌入式操作系统上运行)。FreeMODBUS支持从机,若想使用FreeMODBUS实现主机MODBUS,则需要根据实际需求进行二次开发MODBUS协议栈。
关于Modbus的软件结构,移植,配置,使用网上有很多资料和移植经验。我就不详细探讨移植和FreeMODBUS的软件结构。这里只是简单说一下软件的大致结构以及移植过程中需要注意的地方。我会根据MODBUS协议栈的协议规定,以FreeMODBUS为原型,说明从协议栈的规定到具体实现之间的关系。另外,也谈一下自己对通讯协议的一些个人想法。
前面说过,MODUBS串行口传输方式中存在RTU、ASCII 两种方式。这里只针对RTU方式进行分析,ASCII方式自行分析。
 FreeMODBUS的整体软件结构是:前后台系统。利用串行口接收、发送中断完成数据帧在物理层的传输:接收时,接到一帧完整无误的数据帧就通过事件的方式通知前台程序,前台程序根据收到的数据帧做相应的处理。发送时,先封装应用层数据内容,然后再封装链路层数据,最后通过串口中断的方式发送出去。
通过分析FreeMODBUS的整体软件结构我们很容易就知道,FreeMODBUS需要使用到串口(RS485),我们移植FreeMODBUS要实现初始化串口、读写串口、初始化并控制串口中断。
接下来一个重要的问题是RTU方式的MODBUS如何判别一帧数据包哪?有的协议里有开始标示、结束标示,通过判别开头标示和结束标示来表示一帧完整的数据帧。但根据前面的介绍,我们发现MODBUS RTU方式的数据帧并没有开始标示和结束标示,那MODBUS RTU怎么判别一帧数据帧的哪?我们还要看MDBUS协议栈的具体规定。先给大家看一个图:

MODBUS协议里面说一帧数据和下一帧数据之间的间隔至少是3.5个字符。按照9600的波特率来算的话(9600 N 1,一帧数据为10bit),1S大约能传输960字节,一个字符(1 Byte)的传输时间大约为1ms多点。那这个T3.5应该在4ms左右。也就是说一帧完整的数据帧和下一个数据帧之间的间隔应>=4ms。也就是图示中的 Start >= 3.5Char 、End >= 3.5 Char。
MODBUS RTU方式 还有一个时间要求:

根据图示,很明显MIDBUS协议要求一帧数据里,byte和byte之间的时间间隔应<= 1.5个字符,如果还是按照9600的波特率来计算的话,大约是1.56ms。一帧数据内超出这个数值认为数据包错误。

我们知道了这个,似乎明白了MODBUS协议栈是使用两个时间来确定一帧完整的数据包的。记住哦,T3.5 T1.5 很重要的MODBUS协议参数。然后我们也很容易想到FreeMODBUS要实现精确延时,有可能会使用到定时器,对了,你没猜错,FreeMODBUS除了占用一个串口硬件资源外,它还占用了一个定时器硬件资源。所以移植的时候也要处理定时器有关的初始化、启动定时、关闭定时、开关定时器中断等操作。
下面,我们来说一下FreeMODBUS是如何实现上述时间要求的。根据我看FreeMODBUS的源代码,它只利用了一个T3.5,并没有实现T1.5这个时间要求。我的理解是这样的:
FreeMODBUS一般作为从机,从机作为接收时,若主发送的数据不满足T1.5的要求,FreeMODBUS并没有检测,FreeMODBUS只检测是否满足T3.5这个时间,若byte和byte之间的间隔>=T3.5 这个时间,则认为一帧数据包接收完毕。它的设计可能是假定了主机发送的数据帧格式完全符合MODBUS协议。
而从机发送数据时,是使用串口中断发送,肯定满足T1.5的要求,因为MODBUS是主从模式,主机发送完命令,从机接收到后才给主机响应,这种通讯业肯定能满足T3.5这个要求。
好了,我们现在看看FreeMODBUS是怎么实现接收数据帧时根据这个T3.5来实现判断接收完一帧完整的数据帧的。大致流程是这样,初始化一个4ms的定时器,并打开定时器中断,在每次接收到1个byte时,都重置定时器计数值并启动定时器,然后若时间都过去4ms了都没有收到新的byte,那么就认为一帧数据接收完毕。这个也很好理解吧,可以好好琢磨一下这个实现方案。

最后,还有一个事件处理需要在移植FreeMODBUS的时候考虑,这个简单,其实就是在接受完一帧数据或者出错后,通知前台的查询程序,让它做相应的处理。

FreeMODBUS大致分了3层,底层的接收、发送策略(符合MODBUS协议规定)。中间MODBUS协议。然后就是上层应用层,每层的接口设计的不错,方便移植,应用层也方便扩展。

猜你喜欢

转载自blog.csdn.net/lushoumin/article/details/80842424