modbus协议整理(一)

546 阅读16分钟

一、modbus-RTU协议整理

1.1 RS-485串口通信

modbus-RTU一般运行于RS-485串口通信中。所以先简单提下这部分内容。

串口的设计是传输数据是通过高低电平,高电平0,低电平1。一般高电平5伏左右,低电平0v左右。在传输中受到电磁干扰,电压不稳定,就会出现偏差,所以通信距离一般都在1米之内。两根线一根接收数据,一根发送数据,支持全双工通信,但限于点对点。

RS-232则是把高低电平做了转换,并加入0v地线,高电平是正电压,且高达12v左右,低电压是负电压,-12v左右。电压差加大后,提高了抗干扰能力。通信距离可以达到15米。除地线外,两根线一根接收数据,一根发送数据,支持全双工通信,但限于点对点。

RS-485是RS-232的升级版,使用差分信号传输,只需要两根线。A线电平比B线高是0,B线电平比A线高是1,AB线绕成双绞线,即使同时受到电磁干扰时电压产生偏差,也不会对差值产生影响,所以RS-485 最大的通信距离能达到1200米。一对差分信号线,同一时刻,要么在发送数据,要么在接收数据,所以标准RS-485一般是半双工的,一般使用主从模式。使用标准485芯片一个主机最多可以挂32个从机,高负载芯片可以挂载更多从机。传输中,要采用双绞线保持信号稳定。

主从接线(注意红蓝线在现实中不是独立的,是双绞线): image.png

具体介绍可以参见【物联网】看这篇就够了!串口通信、RS232、RS485最本质的区别!

1.2 modbus-RTU通信模式

Modbus-RTU使用单主站的主/从通信模式,从站的地址范围为1-247。 在Modbus-RTU通信中,主机向总线发送指令帧后,地址匹配的从机将执行以下流程:

  1. 校验与解析:验证帧的CRC校验码,若正确则解析功能码及数据;
  2. 任务执行:根据功能码要求执行操作(如读取寄存器或控制设备);
  3. 响应反馈:将执行结果封装为响应帧(含自身地址码、功能码、结果数据及CRC校验码)发回主机;
  4. 错误处理:若CRC校验失败,从机丢弃该帧且不响应,保持静默。

Modbus-RTU 采用严格的主从式半双工通信

  1. 主站轮询控制:仅主站可发起请求,从站无权主动发送数据;
  2. 单帧传输原则:总线上任一时刻仅允许一帧数据传输(主站请求  从站响应);
  3. 请求-响应机制
    • 主站向指定从站发送指令帧 → 对应从站处理并返回响应帧;
    • 其他从站处于监听静默状态,不占用总线;
  4. 总线空闲规则:无主站请求时,总线无通信流量,直至主站发起下一轮询。

Modbus-RTU 帧间隔规则

  1. 帧起始界定:消息必须以 ≥3.5个字符时间(Tchar)的静默间隔 开始,标识新帧起始。
  2. 帧结束界定:帧内连续字符间隔 ≤1.5个Tchar ;若帧间静默间隔 <3.5个Tchar ,接收端会将其合并为同一帧,导致CRC校验失败或指令解析错误。

Tchar=1个字符的位数/波特率(bps)= 11 bit / Baud Rate

字符位构成

  • 1起始位 + 8数据位 + 1校验位(偶/奇校验) + 1停止位 = 11位
  • 注:若使用2停止位,则按12位计算(较少见)
波特率(bps)1个Tchar(ms)3.5个Tchar(ms)
9600119600≈1.146960011​≈1.1463.5×1.146≈4.013.5×1.146≈4.01
192001119200≈0.5731920011​≈0.5733.5×0.573≈2.003.5×0.573≈2.00
11520011115200≈0.09511520011​≈0.0953.5×0.095≈0.333.5×0.095≈0.33

1.3 Modbus-RTU 报文格式

从机地址功能码数据区CRC校验
1字节(8位)
0x01-0xF7:从机唯一地址
1字节(8位)
最高位=1表示异常响应(如 0x81=读线圈异常)
n字节(8*n位)
内容由功能码决定:读操作:含起始地址+数据长度 写操作:含地址+写入值 响应:含执行结果数据
2字节(16位)
循环冗余校验码,覆盖地址域+功能码+数据区 接收方校验失败时丢弃报文且不响应

Modbus-RTU协议功能码表

功能码名称作用
0x01读取线圈状态取得一组逻辑线圈的当前状态(NO/OFF)
0x02读取离散输入状态取得一组开关输入的当前状态(NO/OFF)
0x03读取保持寄存器在一个或多个保持寄存器中取得当前的二进制数值
0x04读取输入寄存器在一个或多个输入寄存器中取得当前的二进制数值
0x05强置(写)单线圈强置一个逻辑线圈的通断状态
0x06预置(写)单寄存器把具体二进制数值装入一个保持寄存器
0x07读取异常状态取得8个内部线圈的通断状态,这8个线圈的地址由控制器决定,用户逻辑可以将这些线圈定义,以说明从机状态,短报文适用于迅速读取状态
0x08回送诊断校验把诊断校验报文报送给从机,以对通信处理进行评鉴
0x09编程(只用于484)使主机模拟编程器作用修改PC从机逻辑
0x0A控询(只用于484)可使主机与一个正在执行长程序任务的从机通信,探询该从机是否已完成其操作任务,仅在含有功能码0x09的报文发送后,本功能码才发送
0x0B读取事件记录可使主机发出单询问,并随即判定操作是否成功,尤其是该命令或其他应当产生通信错误时
0x0C读取通信事件记录可使主机检索每台从机的Modbus事务处理通信事件记录,如果某项事务处理完成,记录会给出有关错误
0x0D编程(184/384/484/584)使主机模拟编程器作用修改PC从机逻辑
0x0E控询(184/384/484/584)可使主机与正在执行任务的从机通信,定期探询该从机是否已完成其操作任务,仅在含有功能码0x0D的报文发送后,本功能码才发送
0x0F强置(写)多线圈强置一串连续逻辑线圈的通断状态
0x10预置(写)多寄存器把具体的二进制数值装入一串连续的保持寄存器
0x11报告从机标识可使主机判断编址从机的类型及该从机运行指示灯的状态
0x12(884和MICRO84)可使主机模拟编程功能,修改PC状态逻辑
0x13重置通信链路发生非可修改错误后,使从机复位于已知状态,可重置顺序字节
0x14读取通用参数(584L)显示扩展存储器文件中的数据信息
0x15写入通用参数(584L)把通用参数写入或修改扩展存储器文件
0x16-0x40保留作扩展功能备用
0x41-0x48保留留作用户功能的扩展编码
0x49-0x77非法功能
0x78-0x7F保留留作内部使用
0x80-0xFF保留用于异常应答

常见协议格式示例:

1.读取线圈状态、读取离散输入状态(功能码:0x01、0x02)

主机发送报文如下(大端):

从站地址功能码寄存器地址(高)寄存器地址(低)线圈状态数量(高)线圈状态数量(低)CRC校验(低)CRC校验(高)
0x110x010x000x130x000x250xF90xC8

0x11:从机的地址

0x01:01功能码,读取从机线圈状态

0x00 0x13:读取的寄存器起始地址。从0x0013开始读取

0x00 0x25:读取的线圈数量为0x0025个 。也就是37个状态量,8位一个字节,需要5个字节的空间。

0xF9 0xC8:循环冗余校验 CRC校验。

从机返回的报文如下:

从站地址功能码字节数量数据数据数据数据数据CRC校验(低)CRC校验(高)
0x110x010x050xCD0x6B0xB20x0E0x1B0x180x8D

0x11:从机的地址

0x01:01功能码,读取从机线圈状态

0x05:返回字节数量为5个。注意指定读取的线圈数量是37个,所以第5个字节的只有从低到高的前5个字节有效,bit6,bit7,bit8是无效值,需要忽略。

0xCD 0x6B 0xB2 0x0E 0x1B:返回的数据,5个字节的具体值。

0x18 0x8D:循环冗余校验 CRC校验

第一个数据0xCD转为二进制数值为11001101,从低位到高位读。说明线圈的状态值如下:

线圈地址 (十进制)线圈地址 (十六进制)位位置状态 (OFF/ON)二进制值
190x0013bit0ON 合1
200x0014bit1OFF 分0
210x0015bit2ON 合1
220x0016bit3ON 合1
230x0017bit4OFF 分0
240x0018bit5OFF 分0
250x0019bit6ON 合1
260x001Abit7ON 合1

其他的字段以此类推。

2.读取保持寄存器、读取输入寄存器(功能码:0x03、0x04)

主机发送报文如下(大端,即数据的高位先发送):

从站地址功能码寄存器地址(高)寄存器地址(低)寄存器数量(高)寄存器数量(低)CRC校验(低)CRC校验(高)
0x010x030x000x010x000x010xD50xCA

0x01:从机的地址

0x03:读取从机保持寄存器的数据

0x00 0x01:读取的寄存器起始地址。从0x0001开始读取。

0x00 0x01: 读取的寄存器数量为1个 。一个寄存器占16位,对应2字节数据。

0xD5 0xCA: 循环冗余校验 CRC校验。

从机返回的报文如下

从站地址功能码字节数量数据(高)数据(低)CRC校验(低)CRC校验(高)
0x010x030x020x000x170xF80x4A

0x01:从机的地址

0x03:读取从机保持寄存器的数据

0x02:返回字节数量为2个(一个寄存器2个字节)

0x00 0x17:寄存器存储的数据是0x0017,十进制23

0xF8 0x4A:循环冗余校验 CRC

3.强置(写)单线圈(功能码:0x05)

主机发送报文如下:

从站地址功能码寄存器地址(高)寄存器地址(低)写入的值(高)写入的值(低)CRC校验(低)CRC校验(高)
0x110x050x000xAC0xFF0x000xF30xF6

0x11:从机的地址

0x05:写单个线圈

0x00 0xAC:写的寄存器地址。

0xFF 0x00:要写入的数据。即对0x11号从机的0x00AC地址,写入数值0xFF00。

0xF3 0xF6:循环冗余校验 CRC校验。

从机返回的报文如下:

从站地址功能码寄存器地址(高)寄存器地址(低)写入的值(高)写入的值(低)CRC校验(低)CRC校验(高)
0x110x050x000xAC0xFF0x000xF30xF6

从机返回的报文和主机下发的报文一样,相当于确认命令已执行。

4.预置(写)单寄存器(功能码:0x06)

主机发送报文如下:

从站地址功能码寄存器地址(高)寄存器地址(低)写入的值(高)写入的值(低)CRC校验(低)CRC校验(高)
0x110x060x000x010x000x320x790xB9

0x11:从机的地址

0x06:写单个寄存器

0x00 0x01:写的寄存器地址。

0x00 0x32:要写入的数据。即对0x11号从机的0x0001地址,写入数值0x0032。

0x79 0xB9:循环冗余校验 CRC校验。

从机返回的报文如下:

从站地址功能码寄存器地址(高)寄存器地址(低)写入的值(高)写入的值(低)CRC校验(低)CRC校验(高)
0x110x060x000x010x000x320x790xB9

从机返回的报文和主机下发的报文一样,相当于确认命令已执行。

5.强置(写)多线圈(功能码:0x0F)

主机对从机发送报文如下:

从站地址功能码寄存器地址(高)寄存器地址(低)线圈状态数量(高)线圈状态数量(低)字节数量数值1数值2CRC校验(高)CRC校验(低)
0x010x0F0x040xA50x000x0D0x020x0C0x020xB90xDE

0x01:从机的地址

0x0F:写多个线圈

0x04 0xA5:写的寄存器起始地址。大端模式,计算后地址十进制为1189。

0x00 0x0D:要写的线圈状态数量。这里是13个。

0x02:要写入的字节的数量。13个线圈比特位,需要两个字节的数据来填充。注意填充的2个字节有16比特,但bit14-bit16的值是不会写入的。

0x0C 0x02:要写入的数据,这里是2个字节的内容。即 0000 1100, 0000 0010,每个字节从低位到高位的顺序写。

0xB9 0xDE:循环冗余校验 CRC校验。

写入之后的线圈状态值:

线圈地址 (十进制)线圈地址 (十六进制)位位置状态 (OFF/ON)二进制值
11890x04A5字节1(0x0C), bit0OFF 分0
11900x04A6字节1(0x0C), bit1OFF 分0
11910x04A7字节1(0x0C), bit2ON 合1
11920x04A8字节1(0x0C), bit3ON 合1
11930x04A9字节1(0x0C), bit4OFF 分0
11940x04AA字节1(0x0C), bit5OFF 分0
11950x04AB字节1(0x0C), bit6OFF 分0
11960x04AC字节1(0x0C), bit7OFF 分0
11970x04AD字节2(0x02), bit0OFF 分0
11980x04AE字节2(0x02), bit1ON 合1
11990x04AF字节2(0x02), bit2OFF 分0
12000x04B0字节2(0x02), bit3OFF 分0
12010x04B1字节2(0x02), bit4OFF 分0
12020x04B2及以上字节2(0x02), bit5(超出13个线圈范围,忽略)-

从机返回的报文如下:

从站地址功能码寄存器地址(高)寄存器地址(低)寄存器数量(高)寄存器数量(低)字节数量CRC校验(低)CRC校验(高)
0x110x0F0x040xA50x000x0D0x020xB90x79

6.预置(写)多寄存器(功能码:0x10)

主机发送报文如下:

从站地址功能码寄存器地址(高)寄存器地址(低)寄存器数量(高)寄存器数量(低)字节数量数值1(高)数值1(低)数值2(高)数值2(低)CRC校验(低)CRC校验(高)
0x010x100x000x340x000x020x040x0C0x020x090x0E0xB90xDE

0x01:从机的地址

0x10:写多个保持寄存器

0x00 0x34:写的寄存器起始地址。

0x00 0x02:要写的寄存器数量。这里是2个。

0x04:要写入的字节的数量。一般是寄存器数量*2,所以是4个字节。

0x0C 0x02 0x09 0x0E:要写入的数据

0xB9 0xDE:循环冗余校验 CRC校验。

从机返回的报文如下:

从站地址功能码寄存器地址(高)寄存器地址(低)寄存器数量(高)寄存器数量(低)CRC校验(低)CRC校验(高)
0x010x100x000x340x000x020xB90x79

部分参考理论基础——Modbus-RTU通讯协议