本文正在参加「金石计划」
前言
最近两天看了相关 Modbus 的资料,对此有了初步了解,对于该协议的学习应用,也是方便我们软件开发人员对物联网相关体系的进一步了解,本着输入到输出的原则,就将学习的内容总结并输出文档,也避免后续初学人员的踩坑。
一、概念介绍
1.1 物联网 RTU
首先来了解下物联网 RTU 的概念,全称 Remote Terminal Unit ,即远程终端控制单元的意思,RTU 它的作用就是对现场信号、工业设备的监测和控制,也就是通过该装置可以将安装在远程的传感器和设备进行监测和控制,也就是构成我们很多物联网平台数据的来源方式。
RTU 它会将测得的状态或信号转换成可在通信媒体上发送的数据格式,而传输的协议通常是采用 Modbus 协议,Modbus 协议因此应用广泛的特点,成为我们接触物联网必学的一种协议。
1.2 Modbus 协议
Modbus 是应用于电子控制器上的一种通用语言,是由 Modicon 公司(现施耐德电气)在 1979 年发表的,如今已成为工业领域通信协议的业界标准,主要是它具备几个特点:
那为什么会诞生 Modbus 协议呢?
拿我们人与人的交流举例子。
人与人的交流通过语言,不管是中文、英文、阿拉伯文等,都属于语言;
设备与设备之间的交流是通过协议,常用协议有 Modbus RTU、PPI、MPI 等;
而不同的协议就是就对应不同的语言,其中的 Modbus 协议就属于一个应用非常广泛的语言。
再回过头来理解下 RTU 和 Modbus 协议的相关关系。
Modbus 协议定义了一个控制器(RTU)能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一个控制器请求访问其它设备的过程,如何回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。
协议就是互相约定好的一种模板消息,确定好协议后,不管你是通过串口的方式、蓝牙的方式、以太网的方式进行传输数据,只要按照这个协议规范发送消息即可。
一句话:Modbus 是一种应用层报文的传输协议,协议本身未定义物理层,能够适应多种电气接口,因此应用广泛。
因此,下面我们来学习下这个协议规范到底长啥样。
二、Modbus 协议详解
2.1 存储区类型
存储区是用来存储数据的。
由前面我们了解到,我们向对方设备发送消息,我们要遵守一个协议规定,那如果是我们可以怎么制定这个协议呢?
- 首先,协议的目的是为了方便数据传输,而设备数据类型常见的有遥测数据和遥信数据,即遥测数据就是具体的数值数据,例如温度、电流大小等,遥信数据则是开关状态数据,属于布尔类型的。因此,从数据类型的角度可以分为布尔类型和非布尔类型。(下面含义请记住)
-
- 寄存器:理解为非布尔类型
- 线圈:理解为布尔类型
- 从数据的角度,可以从设备中读数据,也可以向设备中写数据(只写数据没有意义),因此分为:
-
- 只读数据:对应“输入”的概念,
- 读写数据:对应“输出”的概念
因此,从我们数学的角度,可以划分成 2 x 2 种存储区。
序号 | 读写 | 存储类型 | 存储区名称 |
---|---|---|---|
1 | 只读 | 线圈 | 输入线圈 |
2 | 读写 | 线圈 | 输出线圈 |
3 | 只读 | 寄存器 | 输入寄存器 |
4 | 读写 | 寄存器 | 保持寄存器 |
上面的是全称,但在代码里面还是不够简洁,因此,Modbus 又觉得直接给他们取个别名吧,就用数字来代替他们的全程,规定如下:
存储区名称 | 存储区代号 |
---|---|
输入线圈 | 1 区 |
输出线圈 | 0 区 |
输入寄存器 | 3 区 |
保持寄存器 | 4 区 |
别问为什么没有 2 区,问就是我也不知道。
2.2 存储区范围
无论是什么存储区,都会有个范围的限制。
Modbus 的存储区大致可分为 5 位数和 6 位数,根据自己情况来判断,因为实际使用中,不一定能用到10000以上,因此,在此场合下 5 位数就够用了。
- 5位和6位
-
- 标准地址(5位):YXXXX ,这里的Y就对应存储区的代号(0143),因此:
-
-
- 输出线圈范围:00001-09999
- 输入线圈范围:10001-19999
- 输出寄存器范围:40001-49999
- 输入寄存器范围:30001-39999
-
-
- 扩展地址(6位):YXXXXX ,
-
-
- 输出线圈范围:000001-065536
- 输入线圈范围:100001-165536
- 输出寄存器范围:400001-465536
- 输入寄存器范围:300001-365536
-
2.3 功能码
功能码就是可以理解为行为类型,我们前面定义了 4 个存储区,而我们再将读写粒度拆分开的话就有六种行为:
- 1、读取输入线圈
- 2、读取输出线圈
- 3、读取输入寄存器
- 4、读取保持寄存器
- 5、写入输出线圈
- 6、写入保持寄存器
理论上,是要分成这六种,但是 Modbus 做了步细分,包括写入单个和写入多个。
因此,写入又可以分为两项,总共就变成八种行为。
这八种行为就是我们的核心功能码,见下:
功能码(16进制) | 功能说明 | 功能码(10进制) |
---|---|---|
0x01 | 读取输出线圈 | 01 |
0x02 | 读取输入线圈 | 02 |
0x03 | 读取保持寄存器 | 03 |
0x04 | 读取输入寄存器 | 04 |
0x05 | 写入单个线圈 | 05 |
0x06 | 写入单个寄存器 | 06 |
0x0F | 写入多个线圈 | 15 |
0x10 | 写入多个寄存器 | 16 |
读和写的功能,可分为八种,因此,功能码就来了,以后想干什么事情,直接看代码就行了,核心就是简化。
2.4 Modbus 通讯过程
了解了核心功能码后,我们就可以来看看 Modbus 具体通信过程。
Modbus 是一主多从的通信协议,以 RS485 总线为例,大概长下面这样(先不管RS485 是啥)。
问题1:何为主站,为何从站?
答:主站就是索要数据的家伙,从站就是被动提供数据的设备。典型的主设备就是现场仪表和显示面板,典型的从设备为可编程逻辑控制器(PLC)。
Modbus 协议有如下几个规定:
-
- 只有一个主机,其他都是从机,一旦上电,就把自己置于监听状态;
-
- 从机无法主动向主机发送数据,只有主机发送数据后,从机接收到再发送给主机;
-
- modbus 协议 RS485 是半双工传输的,意思是主机发送数据的时候,是不能接收数据的;
-
- 任何一次通信都由主机发起,主机发送数据请求之后就转为接收数据状态,同一时刻只能有一个从机与主机通信;
-
- 主机发送数据的方式有两种:
-
- 1对1:只需要发送数据给特定地址的从机即可;
- 1对多:即广播模式,设为0,发给所有从机;
2.5 Modbus 传输模式
Modbus 传输模式有三种:
- RTU 传输模式 : 消息由16 进制组成,数据密度高,吞吐率高;
- ASCll 传输:消息由 ASCLL 字符组成,发送效率不及 RTU 模式,无法使用 RTU 模式的定时管理时,使用 ASCll 模式
- TCP 传输 :是在 TCP\IP 网络上运行的 Modbus 的实现;
2.5.1 ASCll 传输模式
当设备设置为使用 ASCLL 模式在 Modbus 串行总线上进行通信时,消息帧以英文冒号(“:”,ASCII3A Hex)开始,以回车和换号(CRLF,ASCII 0D and 0A Hex)符号结束,允许的传输的字符集为十六进制的 09 和 AF ;网络中的从设备监视传输通路上是否有英文冒号(“:”),如果有的话,就对消息帧进行解码,查看消息中的地址是否与自己的地址相同,如果相同的话,就接收其中的数据,如果不同的话,则不予理会。
开始 | 地址 | 功能码 | 数据 | LRC | 结束 |
---|---|---|---|---|---|
1字符 : | 2字符 | 2字符 | 0-2*252字符 | 2字符 | 2字符CR或LF |
在 ASCll 模式下,每个8位的字节被拆分成两个 ASCll 字符进行发送。
比如十六进制 0x12,会被分解成 ASCll 字符 1(发送0x31) 和 2(0x32) 进行发送,发送的字符量比 RTU 增加一倍。
2.5.2 RTU 传输模式
每个字节可以传输两个十六进制字符。
比如十六进制数 0xAF ,直接以十六进制 0xAF(二进制:10101111)进行发送。因此,它的发送密度比 ASCll 模式高一倍;
RTU 模式采用循环冗余校验(CRC),下面是对 RTU 模式的总结:
当控制器在 Modbus 网络上以 RTU 模式通信时,消息中的每8个 Bit 字节都包含 4 Bit 的十六进制字符,这种模式没有开始和结束标记。
优点:在同样的波特率下,可传输更多数据。它采用二进制表示数据的方式,适用于工业应用。
从站地址 | 功能码 | 数据 | CRC |
---|---|---|---|
1字符 | 1字符 | 0-252 字符 | 2字符 |
Modbus RTU 通常有三种:
- RS-232 :通讯 <15m
- RS-485: 通讯 >15m ,只能接32个从机,半双工
- RS-422:全双工
2.5.3 TCP 传输模式
Modbus TCP 是在 TCP\IP 网络上运行的 Modbus 的实现。 在 Modbus RTU 协议上加了一个 MBAP 报文头,且因为 TCP 是基于可靠连接的服务,RTU 协议中的 CRC 校验码就不再需要,所以 TCP 中没有 CRC 校验码。
其次,在 TCP 中,从机地址变得不再重要,可以被 IP 地址取代。其报文格式见下图
2.6 帧格式
把字节当作最基本的数据单元,然后由字节组成句子,也就是通信帧。
在前面的传输模式中,不管哪种传输模式,都有一个类似这样的结构:从站地址+功能码+数据+校验。而这种就是 Modbus 约定好的报文通信格式。
ADU(Application Data Unit)应用数据单元,分四个部分:地址域、功能码、数据、差错校验(CRC、LRC)。基本上进行传输的数据都要满足这个格式,作为一个完整的帧。
- 地址域:理解为具体和谁说话,一般占用一个字节,所以一般来说寻址范围是0-255,0是广播地址。
- 功能码:理解为具体动作,比如去做、来拿、去吃等
- 数据域:具体内容,配合上下文理解。对功能码细节的补充
- 差错校验:CRC 或 LRC 等方式保证传输的数据没有错误
PDU(protocal data unit):基础通信层的简单协议数据单元;整个 PDU(功能代码和数据)大小不能超过253个字节。
每个功能代码都有一个特定的行为,从设备可以根据所需的应用程序行为灵活的实现这些行为。
三、Modbus 报文模拟仿真
以常用的 RTU 通信模式为例。下面进行案例分析。
首先安装两个软件:Modbus slave(模拟从机)、Modbus Poll(模拟主机)。
- ModbusSlave 是一个从站设备仿真软件,它用于接收主设备的命令包,并回送数据包;可用于测试和调试Modbus主站设备,便于观察Modbus通信过程中的各种报文。
- Modbus Poll(Master):模拟主机发送数据
软件下载地址:www.modbustools.com/modbus_slav…
主机模拟器有了,还需要下载一个工具, Virtual Serial Port Driver 虚拟 com 端口工具,不下载后面会爆出端口没有被定义的。它有个虚拟 com 端口,然后添加好端口后,去设备管理器的端口中查看是否打开
vspd 汉化软件可以到我云盘下载:www.aliyundrive.com/s/SJR7d9NwU…
前面讲过,Modbus 的报文分为四部分,分别为1、1、N、2 字节。看看下面的报文案例能否看懂
通过这两个软件模拟一个物联网传感器设备。
- 打开 slave,定义一个 ID 为1的设备,这个 ID 就是这个从设备的地址了。
- 此功能码为03,另外,设置连接参数,这里的 com 端口要选择自己刚用 vspd 软件开放的,否则会出现 timeout。
- 最终,打开 Modbus poll ,监听1号设备,创建连接。
TX 代表请求报文,RX 代表回应。
举例,逐一分析下面的报文:
- 发送:01 03 00 00 00 02 C4 0B
-
- 01 站地址
- 03 读输出寄存器
- 00 00 起始寄存器
- 00 02 寄存器长度
- C4 0B CRC校验
- 响应:01 03 04 01 46 01 3B 5A 59
-
- 01 站地址
- 03 读输出寄存器
- 04 字节计数 (数据安全,先告诉总数,后面4个字节)
- 01 46 01 3B :具体 4 个字节 0146 32.6 ;013B 转换成10进制 31.5
- 5A 59 :CRC 校验
协议你发的对才能回。
一个端口只能被一个程序连接
再来分析一次,模拟软件发送的是 10 ,下面分析过程如下
Tx:000022-01 03 00 00 00 0A C5 CD
- 01 : 从地址
- 03 :读输出寄存器
- 00 00 :起始寄存器
- 00 0A :寄存器长度
- C5 CD :CRC 校验
Rx:000023-01 03 14 00 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 38 BE
- 01 :从地址
- 03 :读输出寄存器
- 14:字节个数,后面20个字节
- 00 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 :具体内容,可以看到 000A 翻译成10进制就是10
- 38 BE 值
参考链接: