Modbus是应用层上的协议,还是一种主从的通信协议,通信过程按照一定的协议规则进行,数据的交互也是有固定的格式的。
总的来说,Modbus是有着明确且固定的数据模型的,并且通信过程中的数据交互识别是要按照功能码进行的。接下来会介绍Modbus的数据模型、寄存器和功能码。
1.Modbus的数据模型
数据模型简单而言就是数据在协议传输数据过程中的表达形式。数据模型还是协议中约定的对从站设备的可访问数据的一种抽象,Modbus中的数据模型有以下四种:
从上图中可以看到,线圈和离散输入都是布尔型的量,所以对这个两个数据类型的访问只能以bit的方式进行。而输入寄存器和保持寄存器都是无符号的的2字节整型量,支持以字节的方式进行访问。
同时需要特别的一点:线圈和保持寄存器都是可读可写的,离散输入和输入寄存器都只读,意味着只能访问该数据类型的内容,而不支持主动去修改他们。
看到这里估计会有感觉疑惑:这线圈、离散量、寄存器啥的到底都是些什么啊?看着还挺让人奇怪的。问到这里就需要简单的说一下Modbus的背景了。
Modbus协议最早的应用领域是工业控制中的,那个时候PLC中的使用很多,而且涉及的控制对象又很多是开关、指示灯、信号灯等等的,所以为了控制和表示这一系列的对象,就需要抽象一些数据类型出来专门进行表示。
线圈可读可写,还是布尔类型的,它可以表示控制现场的开关,1表示开关的打开,0表示开关的关闭。控制开关的开闭可以这么表示,同样的读取回来的值也可以表示开关的开闭状态。
离散量输入也是布尔型的,但是只能读取,不支持写入。所以它可以表示控制现场中的信号灯的状态,主设备通过查询这些bit的值从而获知信号灯的状态。
输入寄存器是只读的,占有两个字节的数据量。所以可以用于存储一些系统的信息,方便主设备随时查询,从而获知从设备的状态。
保持寄存器可读可写,也是两个字节的数据量。所以可以接收来自主设备的控制数据,也可以向主设备返回从设备的控制数据。
2.Modbus的寄存器与地址模型
对Modbus有所了解的朋友应该会经常遇到像30005、10002之类的地址,这一串的数字初一看真的让人挺迷糊的,这些数据到底表示的啥啊?
其实一串数据表示的是Modbus的地址模型。Modbus的数据模型如下表:
上面的表格第一眼并不能直观的看明白是怎么一回事,需要加以解释。
Modbus中的数据元素都定义了地址,范围从0~65535,即最多65536个元素,也就决定了最多有65536个数据元素。
但是呢,65536是协议允许的最大元素范围,实际使用中并不是要求必须全部都实现。Modbus协议是允许设备自行根据使用情况实现需要的部分元素的。这怎么理解?意思就是Modbus并不要求全部实现全部的数据模型,比如你可以选择只要保持寄存器,而不要线圈、离散输入、输入寄存器,都是可以的。
说到这里还有一个问题需要思考:为什么说Modbus协议的数据访问地址范围是65536个呢?要弄清楚这个问题的答案其实也不难,只要仔细看看Modbus的通信协议帧便可以知道了。
比如Modbus RTU读取一定数据保存寄存器内容的协议帧如下:
从协议帧中可以看到,地址是两个字节的,那么地址范围就是0~65535,即65536个。也就是说Modbus可以访问到的寄存器地址多达65536个。
3.Modbus的功能码
Modbus的功能码分为三类:公共功能码、用户定义功能码、保留功能码。如下图:
公共功能码:公共功能码是已经被定义好的功能码。
用户定义功能码:用户定义功能码有两个范围,65~72和100~110。
保留功能码:可以用于某些公司或者应用使用的功能码,这部分功能码对公共使用是无效的。
公共功能码如下表:
知道了功能码之后又怎么使用Modubs协议去进行通信呢?
比如:读取离散量输出20-38的实例如下:
将输出 27-20 的状态表示为十六进制字节值 CD,或二进制 1100 1101。输出 27 是这个字节的MSB,输出 20 是 LSB。
通常,将一个字节内的比特表示为 MSB 位于左侧,LSB 位于右侧。第一字节的输出从左至右为 27 至 20。下一个字节的输出从左到右为 35 至 28。当串行发射比特时,从 LSB 向 MSB 传输:20 . . .27、28 . . . 35 等等。
在最后的数据字节中,将输出状态 38-36 表示为十六进制字节值 05,或二进制 0000 0101。输出38 是左侧第六个比特位置,输出 36 是这个字节的 LSB。用零填充五个剩余高位比特。