Modbus通信协议从入门到精通

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:

  1. 比RTU多了起始段:,多个结束符CR,LF
  2. 地址和功能都变成了2个字节;
  3. 数据部分更加繁琐,但是更符合人们的查看;

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

布网

开源库

相关推荐
仰科网关2 天前
化工厂SCADA系统OPC DA数据转Modbus TCP接入全厂监控平台项目案例
网络·网络协议·modbus·snmp·opc da·协议转换
仰科网关7 天前
实现华为UPS的SNMP转Modbus协议接入监控平台项目案例
网关·modbus·snmp·vfbox·协议转换
疆鸿智能研发小助手9 天前
造纸厂车间联网改造记:疆鸿智能MODBUS TCP与PROFIBUS的桥梁搭建
modbus·modbus tcp·工业自动化·工业通讯·协议转换网关·profibus
疆鸿智能研发小助手11 天前
疆鸿智能MODBUS TCP与PROFIBUS在核电厂的异构集成解决方案
modbus·modbus tcp·工业自动化·工业通讯·协议转换网关·profibus dp
qq_1728055915 天前
Modbus Server数据采集Web之Server端模拟功能
前端·后端·golang·modbus
水煎包V:YEDIYYDS88815 天前
QT modbus 通信教程,把modbus封装到线程单例中,在线程内完成数据收发,解析。把重要数据以信号方式通知到qml层展示,解决UI卡顿
qt·modbus·线程服务
叶帆16 天前
【睿擎派】云端一体,多种通信协议构建机械臂运动控制系统
物联网·mqtt·rt-thread·modbus·工业通信·ethercat·睿擎派
军训猫猫头17 天前
3.NModbus4 长距离多设备超时 C# + WPF 完整示例
c#·.net·wpf·modbus
程序员-King.19 天前
【Qt开源项目】— ModbusScope-day 1
qt·开源项目·modbus·modbusscope