https://blog.csdn.net/tiandiren111/article/details/118347661

简介
- Modbus 是由 Modicon(现为施耐德电气公司的一个品牌)在 1979 年发明的,是全球第一个真正用于工业现场的总线协议。
- 具有免费+简单+方便修改的优点。
- Modbus的工作方式是请求/应答,每次通讯都是主站先发送指令,可以是广播,或是向特定从站的单播;从站响应指令,并按要求应答,或者报告异常。当主站不发送请求时,从站不会自己发出数据,从站和从站之间不能直接通讯。
- 主要有 RTU 和 ASCII 两种串行模式。设备必须要有RTU模式!这是Modbus协议上规定的,且默认模式必须是RTU,ASCII作为备选。所以,学习Modbus只需要学习RTU,稍微了解ASCII即可。
Modbus-RTU
帧结构
帧结构 = 地址 + 功能码+ 数据 + CRC校验
-
地址: 占用一个字节,范围0-255,其中有效范围是1-247,其他有特殊用途,比如255是广播地址(广播地址就是应答所有地址,正常的需要两个设备的地址一样才能进行查询和回复)。
-
功能码:占用一个字节,功能码的意义就是,知道这个指令是干啥的,比如你可以查询从机的数据,也可以修改数据,所以不同功能码对应不同功能。
-
数据:根据功能码不同,有不同的数据内容。
-
CRC校验:校验数据,判断数据是否在传输过程中被干扰导致被修改。
实战
看到这里你就已经学会Modbus了,下面来实战。
Modbus-RTU协议用的最多功能码就是03和06,03用来查询传感器上的信息,06用来修改传感器寄存器的值。
查询功能码0x03
现在我是主机,我要查询从机地址为01的传感器的数据。于是我和从机之间的数据交互就是:
主机发送: 01 03 00 00 00 01 84 0A
从机回复: 01 03 02 19 98 B2 7E
发送数据解析:

回复数据解析

修改功能码0x06
如果要修改从机的数据就用0x06
主机发送: 01 06 00 00 00 01 48 0A
从机回复: 01 06 00 00 00 01 48 0A
发送数据解析

回复数据解析

如果回复的一样,说明这个数据是修改成功的。
Modbus-ACSII(简单了解)
Modbus-ACSII发送的数据全是字符能直接显示出来,方便调试,但是效率比较低。
比如发送数据0x12,RTU直接发送一个字节:0x12;
ASCII则需要发送2个字节:一个字节代表ASCII码"1",一个代表ASCII码"2",即0x31和0x32;
所以,ASCII效率比较低。但是ASCII能直接打印出来,方便调试观看。直接打印RTU的数据会乱码。

从上面的图中,看出ASCII:
- 比RTU多了起始段:,多个结束符CR,LF
- 地址和功能都变成了2个字节;
- 数据部分更加繁琐,但是更符合人们的查看;
Modbus-RTU进阶
传输时序
两个数据帧帧之间必须间隔3.5个字符时间,避免粘包。


数据帧内两个字符之间的间隔时间必须小于1.5个字符时间。整个报文帧必须以连续的字符流发送。

状态图

上面状态图的一些解释:
- 从 "初始" 态到 "空闲" 态转换需要 t3.5 定时超时: 这保证帧间延迟
- "空闲" 态是没有发送和接收报文要处理的正常状态。
- 在 RTU 模式,当没有活动的传输的时间间隔达 3.5 个字符长时,通信链路被认为在 "空闲" 态。
- 当链路空闲时, 在链路上检测到的任何传输的字符被识别为帧起始。 链路变为 "活动" 状态。 然后,当链路上没有字符传输的时间间个达到 t3.5 后,被识别为帧结束。
- 检测到帧结束后,完成 CRC 计算和检验。然后,分析地址域以确定帧是否发往此设备,如果不是,则丢弃此帧。 为了减少接收处理时间,地址域可以在一接到就分析,而不需要等到整个帧结束。这样, CRC 计算只需要在帧寻址到该节点 (包括广播帧) 时进行。
数据类型
Modbus中使用的有4中数据类型:

通信响应
当主机向设备发送命令后,可能会出现以4下种情况:
- 请求正确的到达服务器,并且请求的内容服务器可以处理,那么服务器返回一个正常响应
- 请求正确的到达服务器,但是请求服务器无法处理(例如请求读一个不存在的寄存器),此时服务器将返回一个异常响应,通知主机错误和错误的类型。
- 请求到达服务器,但是不正确,检测到了通信错误(奇偶校验、LRC、CRC等等),那么不返回响应,主机将最终成为超时状态
- 请求就没到达服务器,服务器没收到也就更不会响应,主机也会成为超时状态
综上,根据服务器处理结果,可以建立两种类型的响应:
-
一个正常MODBUS应答帧:
功能码域:响应功能码 = 请求功能码
数据域:请求中要求的任何数据
校验码:响应帧自身计算

-
一个异常MODBUS应答帧:
用来为客户机提供处理过程中与被发现的差错相关的信息
功能码域:响应功能码 = 请求功能码 + 0x80
数据域:提供一个异常码来指示差错原因
校验码:响应帧自身计算

异常码表

异常码判断流程

功能码
除了前面使用的03、06功能码,Modbus还有很多其他功能码,共分3类:公共功能码、 用户定义功能码、 保留功能码。

- 公共功能码
- 是较好地被定义的功能码,
- 保证是唯一的,
- MODBUS 组织可改变的,
- 公开证明的,
- 具有可用的一致性测试,
- MB IETF RFC 中证明的,
- 包含已被定义的公共指配功能码和未来使用的未指配保留供功能码。
- 用户定义功能码
- 有两个用户定义功能码的定义范围,即 65 至 72 和十进制 100 至 110。
- 用户没有 MODBUS 组织的任何批准就可以选择和实现一个功能码
- 不能保证被选功能码的使用是唯一的。
- 如果用户要重新设置功能作为一个公共功能码,那么用户必须启动 RFC,以便将改变引入公共分类中,并且指配一个新的公共功能码。
- 保留功能码
- 一些公司对传统产品通常使用的功能码,并且对公共使用是无效的功能码。
如果我们需要实现自定义的一些功能码,必须在 65-72 或 100-110 中进行选择。
常用的公共功能码:

操作实例
2.3 读线圈寄存器01H
描述:
读MODBUS从机线圈寄存器当前状态。
查询
例如从机地址为11H,线圈寄存器的起始地址为0013H,结束地址为0037H。该次查询总共访问37个线圈寄存器。
| 字段 | Hex |
|---|---|
| 从机地址 | 11 |
| 功能码 | 01 |
| 寄存器起始地址高字节 | 00 |
| 寄存器起始地址低字节 | 13 |
| 寄存器数量高字节 | 00 |
| 寄存器数量低字节 | 25 |
| CRC校验高字节 | 0E |
| CRC校验低字节 | 84 |
响应
响应负载中的各线圈状态与数据内容每位相对应。1代表ON,0代表OFF。若返回的线圈数不为8的倍数,则在最后数据字节末尾使用0代替。
| 字段 | Hex |
|---|---|
| 从机地址 | 11 |
| 功能码 | 01 |
| 返回字节数 | 05 |
| 数据1(线圈0013H-线圈001AH) | CD |
| 数据2(线圈001BH-线圈0022H) | 6B |
| 数据3(线圈0023H-线圈002AH) | B2 |
| 数据4(线圈002BH-线圈0032H) | 0E |
| 数据5(线圈0033H-线圈0037H) | 1B |
| CRC校验高字节 | 45 |
| CRC校验低字节 | E6 |
线圈0013H到线圈001AH的状态为CDH,二进制值为11001101,该字节的最高位对应线圈001AH,最低位对应线圈0013H。线圈001AH到线圈0013H的状态分别为:ON-ON-OFF-OFF-ON-ON-OFF-ON。
| 001AH | 0019H | 0018H | 0017H | 0016H | 0015H | 0014H | 0013H |
|---|---|---|---|---|---|---|---|
| ON | ON | OFF | OFF | ON | ON | OFF | ON |
最后一个数据字节中,线圈0033H到线圈0037H的状态为1BH(二进制00011011),线圈0037H是左数第4位,线圈0033H为该字节的最低位,线圈0037H至线圈0033H的状态分别为ON-ON-OFF-ON-ON,剩余3位使用0填充。
| 003AH | 0039H | 0038H | 0037H | 0036H | 0035H | 0034H | 0033H |
|---|---|---|---|---|---|---|---|
| 填充 | 填充 | 填充 | ON | ON | OFF | ON | ON |
2.4 读离散输入寄存器02H
说明:
读离散输入寄存器状态。
查询
从机地址为11H。离散输入寄存器的起始地址为00C4H,结束寄存器地址为00D9H。总共访问32个离散输入寄存器。
| 字段 | Hex |
|---|---|
| 从机地址 | 11 |
| 功能码 | 02 |
| 寄存器地址高字节 | 00 |
| 寄存器地址低字节 | C4 |
| 寄存器数量高字节 | 00 |
| 寄存器数量低字节 | 16 |
| CRC校验高字节 | BA |
| CRC校验低字节 | A9 |
响应
响应各离散输入寄存器状态,分别对应数据区中的每位值,1代表ON;0代表OFF。第一个数据字节的LSB(最低位)为查询的寻址地址,其他输入口按顺序在该字节中由低字节向高字节排列,直到填充满8位。下一个字节中的8个输入位也是从低字节到高字节排列。若返回的输入位数不是8的倍数,则在最后的数据字节中的剩余位至该字节的最高位使用0填充。
| 字段 | Hex |
|---|---|
| 从机地址 | 11 |
| 功能码 | 02 |
| 返回字节数 | 03 |
| 数据1(00C4H-00CBH) | AC |
| 数据2(00CCH-00D3H) | DB |
| 数据3(00D4H-00D9H) | 35 |
| CRC校验高字节 | 20 |
| CRC校验低字节 | 18 |
离散输入寄存器00D4H到00D9H的状态为35H(二进制00110101)。输入寄存器00D9H为左数第3位,输入寄存器00D4为最低位,输入寄存器00D9H到00D4H的状态分别为ON-ON-OFF-ON-OFF-ON。00DBH寄存器和00DAH寄存器被0填充。
| 00CBH | 00CAH | 00C9H | 00C8H | 00C7H | 00C6H | 00C5H | 00C4H |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 |
| 00D3H | 00D2H | 00D1H | 00D0H | 00CFH | 00CEH | 00CDH | 00CCH |
| 1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 |
| 00DBH | 00DAH | 00D9H | 00D8H | 00D7H | 00D6H | 00D5H | 00D4H |
| 填充 | 填充 | 1 | 1 | 0 | 1 | 0 | 1 |
2.5 读保持寄存器03H
说明:
读保持寄存器。可读取单个或多个保持寄存器。
查询
从机地址为11H。保持寄存器的起始地址为006BH,结束地址为006DH。该次查询总共访问多个保持寄存器。
| 字段 | Hex |
|---|---|
| 从机地址 | 11 |
| 功能码 | 03 |
| 寄存器地址高字节 | 00 |
| 寄存器地址低字节 | 6B |
| 寄存器数量高字节 | 00 |
| 寄存器数量低字节 | 03 |
| CRC高字节 | 76 |
| CRC低字节 | 87 |
响应
保持寄存器的长度为2个字节。对于单个保持寄存器而言,寄存器高字节数据先被传输,低字节数据后被传输。保持寄存器之间,低地址寄存器先被传输,高地址寄存器后被传输。
| 字段 | Hex |
|---|---|
| 从机地址 | 11 |
| 功能码 | 03 |
| 字节数 | 06 |
| 数据1高字节(006BH) | 00 |
| 数据1低字节(006BH) | 6B |
| 数据2高字节(006CH) | 00 |
| 数据2低字节(006CH) | 13 |
| 数据3高字节(006DH) | 00 |
| 数据3低字节(006DH) | 00 |
| CRC高字节 | 38 |
| CRC低字节 | B9 |
| 006BH高字节 | 006BH低字节 | 006CH高字节 | 006CH低字节 | 006DH高字节 | 006DH低字节 |
|---|---|---|---|---|---|
| 00 | 6B | 00 | 13 | 00 | 00 |
2.6 输入寄存器04H
说明:
读输入寄存器命令。该命令支持单个寄存器访问也支持多个寄存器访问。
查询
从机地址为11H。输入寄存器的起始地址为0008H,寄存器的结束地址为0009H。本次访问2个输入寄存器。
| 字段 | Hex格式 |
|---|---|
| 从机地址 | 11 |
| 功能码 | 04 |
| 寄存器起始地址高字节 | 00 |
| 寄存器起始地址低字节 | 08 |
| 寄存器个数高字节 | 00 |
| 寄存器个数低字节 | 02 |
| CRC高字节 | F2 |
| CRC低字节 | 99 |
响应
输入寄存器长度为2个字节。对于单个输入寄存器而言,寄存器高字节数据先被传输,低字节数据被传输。输入寄存器之间,低地址寄存器先被传输,高地址寄存器后被传输。
| 字段 | Hex格式 |
|---|---|
| 从机地址 | 11 |
| 功能码 | 04 |
| 字节数 | 04 |
| 数据1高字节(0008H) | 00 |
| 数据1低字节(0008H) | 0A |
| 数据2高字节(0009H) | 00 |
| 数据2低字节(0009H) | 0B |
| CRC高字节 | 8B |
| CRC低字节 | 80 |
| 0008H高字节 | 0008H低字节 | 0009H高字节 | 0009H低字节 |
|---|---|---|---|
| 00 | 0A | 00 | 0B |
2.7 写单个线圈寄存器05H
说明:
写单个线圈寄存器。FF00H值请求线圈处于ON状态,0000H值请求线圈处于OFF状态。05H指令设置单个线圈的状态,15H指令可以设置多个线圈的状态,两个指令虽然都设定线圈的ON/OFF状态,但是ON/OFF的表达方式却不同。
查询
从机地址为11H,线圈寄存器的地址为00ACH。使00ACH线圈处于ON状态,即数据内容为FF00H。
| 字段 | Hex |
|---|---|
| 从机地址 | 11 |
| 功能码 | 05 |
| 寄存器地址高字节 | 00 |
| 寄存器地址低字节 | AC |
| 数据1高字节 | FF |
| 数据2低字节 | 00 |
| CRC校验高字节 | 4E |
| CRC校验低字节 | 8B |
响应
| 字段 | Hex |
|---|---|
| 从机地址 | 11 |
| 功能码 | 05 |
| 寄存器地址高字节 | 00 |
| 寄存器地址低字节 | AC |
| 寄存器1高字节 | FF |
| 寄存器1低字节 | 00 |
| CRC校验高字节 | 4E |
| CRC校验低字节 | 8B |
2.8 写单个保持寄存器06H
说明:
写保持寄存器。注意06指令只能操作单个保持寄存器,16指令可以设置单个或多个保持寄存器。
查询
从机地址为11H。保持寄存器地址为0001H。寄存器内容为0003H。
| 字段 | Hex |
|---|---|
| 从机地址 | 11 |
| 功能码 | 06 |
| 寄存器地址高字节 | 00 |
| 寄存器地址低字节 | 01 |
| 数据1高字节 | 00 |
| 数据1低字节 | 01 |
| CRC校验高字节 | 9A |
| CRC校验低字节 | 9B |
响应
| 字段 | Hex |
|---|---|
| 从机地址 | 11 |
| 功能码 | 06 |
| 寄存器地址高字节 | 00 |
| 寄存器地址低字节 | 01 |
| 寄存器数量高字节 | 00 |
| 寄存器数量低字节 | 01 |
| CRC校验高字节 | 1B |
| CRC校验低字节 | 5A |
2.9 写多个保持寄存器10H
说明:
写多个保持寄存器。
查询
从机地址为11H。保持寄存器的起始地址为0001H,寄存器的结束地址为0002H。总共访问2个寄存器。保持寄存器0001H的内容为000AH,保持寄存器0002H的内容为0102H。
| 字段 | Hex |
|---|---|
| 从机地址 | 11 |
| 功能码 | 10 |
| 寄存器起始地址高字节 | 00 |
| 寄存器起始地址低字节 | 01 |
| 寄存器数量高字节 | 00 |
| 寄存器数量低字节 | 02 |
| 字节数 | 04 |
| 数据1高字节 | 00 |
| 数据1低字节 | 0A |
| 数据2高字节 | 01 |
| 数据2低字节 | 02 |
| CRC校验高字节 | C6 |
| CRC校验低字节 | F0 |
| 地址 | 0001H高字节 | 0001H低字节 | 0002H高字节 | 0002H低字节 |
|---|---|---|---|---|
| 数值 | 00 | 0A | 01 | 02 |
响应
| 字段 | Hex |
|---|---|
| 从机地址 | 11 |
| 功能码 | 10 |
| 寄存器起始地址高字节 | 00 |
| 寄存器起始地址低字节 | 01 |
| 寄存器数量高字节 | 00 |
| 寄存器数量低字节 | 02 |
| CRC校验高字节 | 12 |
| CRC校验低字节 | 98 |
2.10 写多个线圈寄存器0FH
说明:
写多个线圈寄存器。若数据区的某位值为"1"表示被请求的相应线圈状态为ON,若某位值为"0",则为状态为OFF。
查询
从机地址为11H,线圈寄存器的起始地址为0013H,线圈寄存器的结束地址为001CH。总共访问10个寄存器。寄存器内容如下表所示。
| 001AH | 0019H | 0018H | 0017H | 0016H | 0015H | 0014H | 0013H |
|---|---|---|---|---|---|---|---|
| 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 |
| 0022H | 0021H | 0020H | 001FH | 001EH | 001DH | 001CH | 001BH |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
传输的第一个字节CDH对应线圈为0013H到001AH,LSB(最低位)对应线圈0013H,传输第二个字节为01H,对应的线圈为001BH到001CH,LSB对应线圈001CH,其余未使用位使用0填充。
| 字段 | Hex |
|---|---|
| 从机地址 | 11 |
| 功能码 | 0F |
| 寄存器地址高字节 | 00 |
| 寄存器地址低字节 | 13 |
| 寄存器数量高字节 | 00 |
| 寄存器数量低字节 | 0A |
| 字节数 | 02 |
| 数据1(0013H-001AH) | CD |
| 数据2(001BH-001CH) | 01 |
| CRC校验高字节 | BF |
| CRC校验低字节 | 0B |
响应
| 字段 | Hex |
|---|---|
| 从机地址 | 11 |
| 功能码 | 0F |
| 寄存器地址高字节 | 00 |
| 寄存器地址低字节 | 13 |
| 寄存器数量高字节 | 00 |
| 寄存器数量低字节 | 0A |
| 字节数 | 02 |
| CRC校验高字节 | 99 |
| CRC校验低字节 | 1B |
布网
