这里分享一下在嵌入式设备与PLC通讯中的一种很常见的通讯协议:Modbus通讯
一、基本概念
Modbus协议 是一个请求/应答协议,发起请求的为Master(client),响应请求的为Slave(server);Modbus协议包括ASCII、RTU、TCP三种报文类型,并没有规定物理层。
标准的Modbus协议物理层接口有RS232、RS422、RS485和以太网接口,采用master/slave方式通信。
- Master端发出读数据请求消息,Slave端接收到正确消息后,就发送对应数据到Master端以响应请求;
- Master端发出写数据请求消息,Slave端接收到正确消息后,就修改Slave端的数据;
先发请求,再接收响应,从而实现 主机 对 从机 读/写操作。
二、报文格式_通用部分
- (ADU)报文,指的是一串完整的指令数据;一个报文就是一帧数据,一个数据帧就一个报文
- (MBAP)报文头,即报文的一部分,用于识别。当然也有些是部分数据在报文尾部,例如CRC数据校验。
- (PDU)协议数据单元,这部分就是通信中的数据部分了。
举例如下:
由于报文类型的不同,报文之间也存在一些差异。先讲解通用的 功能码 & 错误代码 部分。
2.1 Modbus部分功能码
功能码(十六进制) | 中文名称 | 位操作/字节操作 | 操作数量 | 错误功能码(&0x80) |
---|---|---|---|---|
01 | 读线圈状态 | 位操作 | 单个或多个 | 0x81 |
02 | 读离散状态 | 位操作 | 单个或多个 | 0x82 |
03 | 读保持寄存器 | 字节操作 | 单个或多个 | 0x83 |
04 | 读输入寄存器 | 字节操作 | 单个或多个 | 0x84 |
05 | 写单个线圈 | 位操作 | 单个 | 0x85 |
06 | 写单个保持寄存器 | 字节操作 | 单个 | 0x86 |
0F | 写多个线圈 | 位操作 | 多个 | 0x8F |
10 | 写多个保持寄存器 | 字节操作 | 多个 | 0x90 |
Modbus协议规定,从机当执行对应功能码处理时发生错误,响应主机时需要将 功能码 & 0x80
将其返回。
2.2 错误代码表
代码 | 名称 | 含义 |
---|---|---|
01 | 非法功能 | 对于服务器(或从站)来说,询问中接收到的功能码是不可允许的操作,可能是因为功能码仅适用于新设备而被选单元中不可实现同时,还指出服务器(或从站)在错误状态中处理这种请求,例如:它是未配置的,且要求返回寄存器值。 |
02 | 非法数据地址 | 对于服务器(或从站)来说,询问中接收的数据地址是不可允许的地址,特别是参考号和传输长度的组合是无效的。对于带有100个寄存器的控制器来说,偏移量96和长度4的请求会成功,而偏移量96和长度5的请求将产生异常码02。 |
03 | 非法数据值 | 对于服务器(或从站)来说,询问中包括的值是不可允许的值。该值指示了组合请求剩余结构中的故障。例如:隐含长度是不正确的。modbus协议不知道任何特殊寄存器的任何特殊值的重要意义,寄存器中被提交存储的数据项有一个应用程序期望之外的值。 |
04 | 从站设备故障 | 当服务器(或从站)正在设法执行请求的操作时,产生不可重新获得的差错。 |
05 | 确认 | 与编程命令一起使用,服务器(或从站)已经接受请求,并且正在处理这个请求,但是需要长持续时间进行这些操作,返回这个响应防止在客户机(或主站)中发生超时错误,客户机(或主机)可以继续发送轮询程序完成报文来确认是否完成处理。 |
07 | 从属设备忙 | 与编程命令一起使用,服务器(或从站)正在处理长持续时间的程序命令,当服务器(或从站)空闲时,客户机(或主站)应该稍后重新传输报文。 |
08 | 存储奇偶性差错 | 与功能码20和21以及参考类型6一起使用,指示扩展文件区不能通过一致性校验。服务器(或从站)设备读取记录文件,但在存储器中发现一个奇偶校验错误。客户机(或主机)可重新发送请求,但可以在服务器(或从站)设备上要求服务。 |
0A | 不可用网关路径 | 与网关一起使用,指示网关不能为处理请求分配输入端口值输出端口的内部通信路径,通常意味着网关是错误配置的或过载的。 |
0B | 网关目标设备响应失败 | 与网关一起使用,指示没有从目标设备中获得响应,通常意味着设备未在网络中。 |
## 2.3 Modbus 寄存器地址分配 | ||
寄存器信息地址(PLC 地址) | 适用功能码(十六进制) | 寄存器种类 |
—- | — | —- |
00001-09999 | 01 05 15 | 线圈状态 |
10001-19999 | 02 | (开关)输入状态 |
30001-39999 | 04 | 输入寄存器 |
40001-49999 | 03 06 16 | 保持寄存器 |
## 2.4 小总结(心得) | ||
一般情况下,只需要看一下返回的功能码就行了,错误代码可以不用看。Modbus通讯发生错误,往往出现的情况如下: | ||
1. Modbus主机(PLC)读取有问题,例如读的地址写错,读的数据长度写错 | ||
2. Modbus从机压根就没写该 功能码 0r 地址 对应的处理,当主机对其操作自然报错。 | ||
3. 并不是符合Modbus协议规范的报文就一定通信正确,只能说是通讯成功,因为它返回给你一条报错指令。通讯无响应,说明是主机本身发的数据就有问题;通信有响应(可能返回错误报文),说明该地址不可用,主机读歪了或者从机压根没写该功能处理。 |
三、各报文格式_详细解析
每个报文都与其他报文格式有一定区分。在Modbus从机的角度看,讲解一下他们之间的类似之处。
- 三者功能码是通用的
- RTU 和 TCP的报文十分类似。TCP由于是可靠的协议,且通过IP连接,相比RTU就少了 设备ID & CRC数据校验。数据单元部分是完全一样的。
- RTU & ASCII 都是通过串口通讯的,因此都是需要 定时器。但是定时器具体用法不相同。
Ps:
ASCII模式,国内基本没用到。常用的是 RTU & TCP 模式。
3.1 RTU模式
Modbus RTU协议中没有明显的开始符和结束符,而是通过帧与帧之间的间隔时间来判断的。如果在指定的时间内,没有接收到新的字符数据,那么就认为新的帧接收完毕。接下来就是处理数据。Modbus通过时间来判断帧接收完成,自然需要 MCU 的定时器配合(3.5T)。
| 设备地址 | 功能代码 | 数据 | CRC校验 | 结束符(实际报文可没有这个!)
| — | —- | — | —- | —
| 1个字节 | 1个字节 | n个字节 | 2个字节 | T1-T2-T3-T4
- 地址码:每个从机都必须有唯一的地址码ID(从1到247,0是广播地址),并且只有符合地址码的从机才能响应回送。当从机回送信息时,相应的地址码表明该信息来自于何处。
- 功能码:主机发送的功能码告诉从机执行什么任务。ModBus通讯规约定义功能号为1到127。表2-1列出部分常用功能码,以备查询。
- 数据区:数据区包含需要从机执行什么动作或由从机采集的返送信息。应答包中,数据包括了数据字节长度+数据值,请求包中数据只包含数据值。
- 校验码:主机或从机可用校验码进行判别接收信息是否出错。
- 从Modbus主机角度上看
- 使用RTU模式,消息发送至少要以3.5个字符时间的停顿间隔开始(如上图的T1-T2-T3-T4所示)。传输的第一个域是设备地址。可以使用的传输字符是十六进制的0…9,A…F。网络设备不断侦测网络总线,包括停顿间隔时间内。当第一个域(地址域)接收到,每个设备都进行解码以判断是否发往自己的。在最后一个传输字符之后,一个至少3.5个字符时间的停顿标定了消息的结束。一个新的消息可在此停顿后开始。
- 一旦连续发送间隔 小于3.5T,就会对从机数据接收造成 数据黏合。
- 从Modbus从机角度上看
- 整个消息帧必须作为一连续的流传输,如果在帧完成之前有超过1.5个字符时间的停顿时间则为非法帧;如果一个新消息在小于3.5个字符时间内接着前个消息开始,接收的设备将认为它是前一消息的延续,这将导致一个错误,因为在最后的CRC域的值不可能是正确的。即帧之间的间隔必须大于3.5T,帧内字符的间隔必须小于1.5T。实际应用中1.5T一般不处理,只采用3.5T进行处理(FreeModBus开源代码就是这样)。
- FreeModbus库,采用的是3.5T作为判断。只要是超过3.5T,就视为两个数据帧处理。当然,如果主机发送数据异常,让 某条报文中间字符发送相隔时间超过3.5T,那么就会造成 1条正确报文被分割成2条报文,造成 数据裂开。
- 数据裂开一般不会出现。采用FreeModbus库时,正常情况下,高波特率会对3.5T的值进行限制。如果解开该限制,导致3.5T实际值太小(高波特率转换计算出来),这时候主机的字符发送间隔慢一点,从机将无法识别到正确的报文(数据被分裂)。
3.2 ASCII模式
除了数据域为ASCII码,其它域可以使用的传输字符是十六进制的0…9,A…F。网络上的设备不断侦测“:”字符,当有一个冒号接收到时,每个设备都解码下个域(地址域)来判断是否发给自己的。消息中字符间发送的时间间隔(MCU 的定时器)最长不能超过1秒,否则接收的设备将认为传输错误。
起始位 | 设备地址 | 功能代码 | 数据 | LRC校验 | 结束符 |
---|---|---|---|---|---|
: | 2个字符 | 2个字符 | n个字符 | 2个字符 | 2个字符 |
使用ASCII模式,消息以冒号(:)字符(ASCII码 3AH)开始,以回车换行符结束(ASCII码 0DH,0AH)
3.3 TCP/IP模式
与MODBUS RTU相比,少了校验域和地址码,其中地址码被放到MBAP报文头里面了(即 00 00),没有校验域是因为TCP本身就有校验所以省略了。
报文头MBAP,长度为7字节,组成如下:
- 事务处理标识 :可以理解为报文的序列号,一般每次通信之后就要加1以区别不同的通信数据报文(主机要注意的点,从机不对该数据进行识别处理)。
- 协议标识符 :00 00表示ModbusTCP协议。
- 长度 :表示接下来的数据长度,单位为字节。
- 单元标识符 :可以理解为设备地址。
事务处理标识 | 协议标识 | 长度 | 单元标识符 | 功能代码 | 数据 |
---|---|---|---|---|---|
2字节 | 2字节 | 2字节 | 1字节 | 1字节 | n字节 |
四、调试工具
- 如果你做的是Modbus Master,可以使用modbus slave工具模拟从设备来调试,该工具下载地址:Modbus Slave
- 如果你做的是Modbus Slave,可以使用modbus poll工具模拟主设备来调试,该工具下载地址:Modbus Poll
以上两个工具的使用方法,可以参考此博客:Modbus测试工具ModbusPoll与Modbus Slave使用方法