简介
Modbus通信协议由Modicon公司(现已经为施耐德公司并购,成为其旗下的子品牌)于1979年发明的,是全球最早用于工业现场的总线规约。Modbus通信协议采用的是主从通信模式(Master/Slave通信模式),其在分散控制方面应用极其广泛,从而使得Modbus协议在全球得到了广泛的应用。
Modbus是一项应用层报文传输协议, 用于在通过不同类型的总线或网络连接的设备之间的客
户机/服务器通信。其具有支持串口(主要是RS232,RS422,RS-485总线),以太网多个版本,其中最著名的是Modbus RTU,Modbus ASCII和Modbus TCP三种。其中Modbus RTU与Modbus ASCII均为支持RS-485总线的通信协议,其中Modbus RTU由于其采用二进制表现形式以及紧凑数据结构,通信效率较高,应用比较广泛。而Modbus ASCII由于采用ASCII码传输,并且利用特殊字符作为其字节的开始与结束标识,其传输效率要远远低于Modbus RTU协议,一般只有在通信数据量较小的情况下才考虑使用Modbus ASCII通信协议,在工业现场一般都是采用Modbus RTU协议,一般而言,大家说的基于串口通信的Modbus通信协议都是指Modbus RTU通信协议。
通用Modbus协议描述
Modbus是一个请求/应答协议,并且提供功能码规定的服务。Modbus功能码是Modbus请求/应答PDU 的元素。
Modbus协议定义了一个与基础通信层无关的简单协议数据单元(PDU),特定总线或网络上的Modbus协议映射能够在应用数据单元(ADU)上引入一些附加域
既然Modbus是通过PDU完成相关操作的,那么看看PDU的种类,他们是:
1. Modbus请求PDU,mb_req_pdu
2. Modbus响应PDU,mb_rsp_pdu
3. Modbus异常响应PDU,mb_excep_rsp_pdu
Modbus使用最高有效字节在低地址存储的方式表示地址和数据项,这意味着当发送多个字节时,首先发送最高有效字节,例如:
0x1234,发送的第一个字节为0x12,然后是0x34
Modbus数据模型
数据模型是对从站设备可访问的数据进行抽象,Modbus协议的数据模型定义了四种可访问的数据:
其中,离散量输入和线圈数据类型是布尔量,因此只支持以位(bit)的方式进行访问,输入寄存器和保持寄存器数据类型是无符号2字节整型,因此支持以字的方式进行访问。当主设备访问从设备的这些数据模型时,离散量输入和输入寄存器只支持以只读的方式进行访问,而线圈和保持寄存器既可以读也可以写。
数据模型中的每一种数据区块都最多允许有65536(2^16)个元素,Modbus定义了每个数据元素的地址,范围从0到65,535。但是每个数据元素的编号从1开始,范围从1到65,536。
需要说明的是:65536只是协议允许的最大元素范围,并不要求全部实现。Modbus协议允许设备根据自己的实际情况实现部分元素,甚至不要求实现模型中全部四种数据模型。譬如设备可能会选择不执行线圈、离散输入或输入寄存器,而只使用保持寄存器150至175和200至225。这是完全可以接受的,并且通过异常来处理无效的访问。
Modbus协议的地址模型
为了简化数据模型与设备存储区的对应关系,又引入了地址模型的概念,通过编号的方式对不同类型数据进行区分,也就是通过特定的编号作为前缀加到所讨论的数据地址中。如表中所示,通过0,1,3,4分别表示线圈,离散量输入,输入寄存器,和保持寄存器。
因此理论上,
线圈地址范围:000001~065536
离散量输入地址范围:100001~165536
输入寄存器地址范围:300001~365536
保持寄存器地址范围:400001~465536
由于65536是比较大的数值,实际应用一般不需要这么大的存储区,因此设备厂家普遍采用的是10000以内的地址范围,即:
线圈地址范围:00001~09999
离散量输入地址范围:10001~19999
输入寄存器地址范围:30001~39999
保持寄存器地址范围:40001~49999
有了该地址模型,我们就可以从Modbus寄存器的地址判断要访问的区块的类型。譬如常见到的寄存器地址40001/400001,最前面的4表明它是一个保持寄存器,后面的0001或者00001都是指第一个保持存储器,并且它的地址是0。寄存器30004表明它是输入寄存器,地址是3。寄存器10008表明它是离散量输入,地址是7。
要注意的是,保持寄存器和输入寄存器中的数值是2个字节,而线圈和离散量输入中数值大小仅为1bit (位)
地址模型解决了协议操作地址与硬件内部实际地址的对应关系,下面来看看功能码,也就是要执行的操作。
功能码
功能码使用示例
读寄存器(0x03)
写寄存器(0x10)
理解了功能码的请求帧,以及正常响应帧,异常响应帧的格式,那么Modbus的程序开发应该就水到渠成了。