admin管理员组

文章数量:1536125

2024年7月17日发(作者:)

Modbus是一种比较简单且易组网安全,性价比高的协议!Modbus仅仅是协议!具体的物理层没有规定!

可以是232也可以是485,Modbus只关心接收到的数据的格式和校验。Modbus的格式很简单,主要有单

字读,单字写,多字读,还有广播等。注意,所有的操作都是以字为单位。Modbus是一种主从式协议,即

一个系统中只有一个主设备,所有的操作都是主设备发起。通过查询和回应的机制进行通信。

(1)查询 查询消息中的功能代码告之被选中的从设备要执行何种功能。数据段包含了从设备要执行功

能的任何附加信息。例如功能代码03是要求从设备读保持寄存器并返回它们的内容。数据段必须包含要告

之从设备的信息:从何寄存器开始读及要读的寄存器数量。错误检测域为从设备提供了一种验证消息内容

是否正确的方法。

(2)回应 如果从设备产生一正常的回应,在回应消息中的功能代码是在查询消息中的功能代码的回应。

数据段包括了从设备收集的数据:象寄存器值或状态。如果有错误发生,功能代码将被修改以用于指出回

应消息是错误的,同时数据段包含了描述此错误信息的代码。错误检测域允许主设备确认消息内容是否可

用。

地址域

消息帧的地址域包含两个字符(ASCII)或8Bit(RTU)。可能的从设备地址是0...247 (十进制)。单个

设备的地址范围是1...247。主设备通过将要联络的从设备的地址放入消息中的地址域来选通从设备。当从

设备发送回应消息时,它把自己的地址放入回应的地址域中,以便主设备知道是哪一个设备作出回应。

地址0是用作广播地址,以使所有的从设备都能认识。当Modbus协议用于更高水准的网络,广播可能不

允许或以其它方式代替。

功能域

消息帧中的功能代码域包含了两个字符(ASCII)或8Bits(RTU)。可能的代码范围是十进制的1...255。

当然,有些代码是适用于所有控制器,有此是应用于某种控制器,还有些保留以备后用。

当消息从主设备发往从设备时,功能代码域将告之从设备需要执行哪些行为。例如去读取输入的开关状态,

读一组寄存器的数据内容,读从设备的诊断状态,允许调入、记录、校验在从设备中的程序等。

当从设备回应时,它使用功能代码域来指示是正常回应(无误)还是有某种错误发生(称作异议回应)。对正

常回应,从设备仅回应相应的功能代码。对异议回应,从设备返回一等同于正常代码的代码,但最重要的

位置为逻辑1。

例如:一从主设备发往从设备的消息要求读一组保持寄存器,将产生如下功能代码:0 0 0 0 0 0 1 1 (十六

进制03H)对正常回应,从设备仅回应同样的功能代码。对异议回应,它返回: 1 0 0 0 0 0 1 1 (十六进

制83H)除功能代码因异议错误作了修改外,从设备将一独特的代码放到回应消息的数据域中,这能告诉

主设备发生了什么错误。主设备应用程序得到异议的回应后,典型的处理过程是重发消息,或者诊断发给

从设备的消息并报告给操作员。

数据域

数据域是由两个十六进制数集合构成的,范围00...FF。根据网络传输模式,这可以是由一对ASCII

字符组成或由一RTU字符组成。

从主设备发给从设备消息的数据域包含附加的信息:从设备必须用于进行执行由功能代码所定义的所为。

这包括了象不连续的寄存器地址,要处理项的数目,域中实际数据字节数。

例如,如果主设备需要从设备读取一组保持寄存器(功能代码03),数据域指定了起始寄存器以及要读的

寄存器数量。如果主设备写一组从设备的寄存器(功能代码10十六进制),数据域则指明了要写的起始寄

存器以及要写的寄存器数量,数据域的数据字节数,要写入寄存器的数据。

如果没有错误发生,从从设备返回的数据域包含请求的数据。如果有错误发生,此域包含一异议代码,主

设备应用程序可以用来判断采取下一步行动。

在某种消息中数据域可以是不存在的(0长度)。例如,主设备要求从设备回应通信事件记录(功能代码0B

十六进制),从设备不需任何附加的信息。

错误检测域

1

标准的Modbus网络有两种错误检测方法。错误检测域的内容视所选的检测方法而定。

ASCII 当选用ASCII模式作字符帧,错误检测域包含两个ASCII字符。这是使用LRC(纵向冗长检测)

方法对消息内容计算得出的,不包括开始的冒号符及回车换行符。LRC字符附加在回车换行符前面。

RTU 当选用RTU模式作字符帧,错误检测域包含一16Bits值(用两个8位的字符来实现)。错误检测域

的内容是通过对消息内容进行循环冗长检测方法得出的。CRC域附加在消息的最后,添加时先是低字节然

后是高字节。故CRC的高位字节是发送消息的最后一个字节。

ModBus 可分为两种传输模式: ASCII 模式和 RTU 模式。使用何种模式由用户自行选择,包括串口通信

参数(波特率、校验方式等)。在配置每个控制器的时候,同一个 Mod B us 网络上的所有设备都必须选择

相同的传输模式和串口参数。

ASCII 模式,消息以冒号(:)字符( ASCII 码 3AH )作为起始位 , 以回车换行符( ASCII 码 0DH,

0AH )作为结束符。传输过程中,网络上的设备不断侦测 “ : ” 字符,当有一个冒号接收到时,每个

设备就解码下个位的地址域,来判断是否发给自己的。 与地址域一致的设备继续接受其它域,直至接受到

回车换行符。除起始位和结束符外,其 他 域可以使用的传输字符是十六进制的 0 … 9 , A … F ,当

然也要用 ASCII 码表示字符。当选用 A SCII 模式时,消息帧使用 LRC (纵向冗长检测)进行错误检测,

这种方式的主要优点是字符发送的时间间隔可达到 1 秒而不产生错误。

ASCII每个字节的位

• 1个起始位

• 7个数据位,最小的有效位先发送

• 1个奇偶校验位,无校验则无

• 1个停止位(有校验时),2个Bit(无校验时)

错误检测域 LRC(纵向冗长检测)

ASCII模式帧结构:

:

地功能代数据数

设备地址

2个字符

数据1 ...

功能代码

2个字符

数据LRC高字LRC低字

n 节

LRC校验

2个字符

回车 换行

址 码

起始位

1个字符

高有效位

启始位

数据 结束符

2个字符 n个字符

使用ASCII字符帧时,传输位的序列是:每个字符或字节以如下方式发送(从左到右): 最低有效位...最

1 2 3 4 5 6 7 奇偶位 停止位

无奇偶校验位用个停止位代替。

RTU消息发送至少要以 3.5 个字符时间的停顿间隔开始。传输过程中,网络设备 不 断侦测网络总线,包

括停顿间隔时间内。当第一个域(地址域)接收到,相应的设备就对 接 下来的传输字符进行解码,一旦

有至少 3. 5 个字符时间的停顿就表示该消息的结束。

RTU每个字节的位

• 1个起始位

• 8个数据位,最小的有效位先发送

• 1个奇偶校验位,无校验则无

• 1个停止位(有校验时),2个Bit(无校验时)

错误检测域 CRC(循环冗长检测)

RTU 模式中整个消息帧必须作为一连续的流转输,如果在帧完成之前有超过 1.5 个 字符时间的停顿

时间,接收设备将刷新不完整的消息并假定下一字节是一个新消息的地址 域。同样地,如果一个新消息在

小于 3. 5 个字符时间内接着前个消息开始,接收的设备将 认为它是前一消息的延续。如果在传输过程中

2

有以上两种情况发生的话,必然会导致 CRC 校验产生一个错误消息,反馈给发送方设备。 当控制器设为

RTU (远程终端单元)模式通信时,消息中的每个 8Bit 字节包含两个 4 B it 的十六进制字符。这种模式

与 ASCII 模式相比在同样的波特率下,可比 ASCII 模式传送 更多的数据。

3.5個字符的時間間隔,只是用在RTU模式下面,因為RTU模式沒有開始符和結束符,兩個數據包

之間只能靠時間間隔來區分,Modbus定義在不同的波特率下,間隔時間是不一樣的,所以就是3.5個字符

的時間,波特率高,這個時間間隔就小,波特率低,這個時間間隔相應就大,你在處理的時候,當使用RTU

模式時,就要有一個定時器來計時,計時時間為3.5個字符的時間,如果正在接收的過程中,發現定時器

超時,就表示一個數據包接收完成,可以進行處理了。假如通信波特率为 19200,那么:

1.5 个字符间隔 = 1/19200 *11*1.5*1000=0.86ms

3.5 个字符间隔 = 1/19200 *11*3.5*1000=2ms

静止时间和波特率有关

例如:波特率=9600,则:一位停止位+1位校验位+8位数据位+1位起始位=11位

也就是说1秒钟传输9600位,则1秒钟传输9600/11=872字节

显然3.5字符静止时间

1000ms x

-------- = ----- ===> x=4ms

872 3.5 即:静止时间=4ms

可定义一个1ms的定时中断,当接收到一个字符后,开启定时器,并且清除计时值,当中断中“读

数值”累计>=4时,表示已经接收到一帧完整的MODBUS数据。

Modbus RTU报文基本格式

Modbus命令简介

起始应有

目标站号 功能码

1字节 1字节

数据 CRC校验码

N字节 2字节 》》3.5个字符的报文间隔

注:下面对于各请求命令的“应答格式”的描述是指命令被正确执行时的应答格式。若CPU接收到错误的命

令或者命令被执行错误,则返回的应答帧中“功能码”部分变为如下数据:功能码的最高位置1后得到的数

据。比如功能码为01,若响应错误,则返回的功能码为0x81。

MODBUS功能码介绍

01 命令读可读写数字量寄存器(取得一组逻辑线圈的当前状态(ON/OFF)) MODBUS地址 00001~

MODBUS 请求

功能码 1 BYTE 0X01

起始地址 2 BYTE 0X0000 TO 0XFFFF

读取数量 2 BYTE 1 TO 2000(0X7D0)

MODBUS 响应

功能码 1 BYTE 0X01

字节计数 1 BYTE N

线圈状态 n BYTE n =N or N+1

N =读取数量/8 如果余数不为0 则N=N+1

错误 响应

功能码 1 BYTE 0X01+ 0X80

错误代码 1 BYTE 0x1 or 0x2 or 0x3 or 0x4

举例

请求 响应

域名称 数据(hex) 域名称 数据(hex)

功能码 01 功能码 01

3

起始地址高(字节) 00 字节计数 03

起始地址低(字节) 13 27(h)~20状态 CD

读取数量高(字节) 00 35(h)~28状态 6B

读取数量低(字节) 13 38(h)~36状态 05

【01功能码分析】

01功能码:读可读写数字量寄存器(取得一组逻辑线圈的当前状态(ON/OFF)):

计算机发送命令:[设备地址] [命令号01] [起始寄存器地址高8位] [低8位] [读取的寄存器数高8位] [低8

位] [CRC校验的低8位] [CRC校验的 高8位]

例:[11][01][00][13][00][25][CRC低][CRC高]

意义如下:

<1>设备地址:在一个485总线上可以挂接多个设备,此处的设备地址表示想和哪一个设备通讯。例子中为

想和17号(十进制的17是十六进制的11)通讯。

<2>命令号01:读取数字量的命令号固定为01。

<3>起始地址高8位、低8位:表示想读取的开关量的起始地址(起始地址为0)。比如例子中的起始地址为

19。

<4>寄存器数高8位、低8位:表示从起始地址开始读多少个开关量。例子中为37个开关量。

<5>CRC校验:是从开头一直校验到此之前。在此协议的最后再作介绍。此处需要注意,CRC校验在命令

中的高低字节的顺序和其他的相反。

设备响应:[设备地址] [命令号01] [返回的字节个数][数据1][数据2]...[数据n][CRC校验的低8位] [CRC校

验的高8位]

例:[11][01][05][CD][6B][B2][0E][1B][CRC低][CRC高]

意义如下:

<1>设备地址和命令号和上面的相同。

<2>返回的字节个数:表示数据的字节个数,也就是数据1,2...n中的n的值。

<3>数据1...n:由于每一个数据是一个8位的数,所以每一个数据表示8个开关量的值,每一位为0表示对

应的开关断开,为1表示闭合。比如例子中,表示20号(索引号为19)开关闭合,21号断开,22闭合,23

闭合,24断开,25断开,26闭合,27闭合...如果询问的开关量不是8的整倍数,那么最后一个字节的高

位部分无意义,置为0。

<4>CRC校验同上。

02 命令 读取输入状态 取得一组开关输入的当前状态(ON/OFF) MODBUS地址 10001~

MODBUS 请求

功能码 1 BYTE 0X02

起始地址 2 BYTE 0X0000 TO 0XFFFF

读取数量 2 BYTE 1 TO 2000(0X7D0)

MODBUS 响应

功能码 1 BYTE 0X02

字节计数 1 BYTE N

输入状态 n BYTE n =N or N+1

N =读取数量/8 如果余数不为0 则N=N+1

错误 响应

功能码 1 BYTE 0X02+ 0X80

错误代码 1 BYTE 0x1 or 0x2 or 0x3 or 0x4

举例

请求 响应

4

域名称 数据(hex)域名称 数据(hex)

功能码 02 功能码 02

起始地址高(字节) 00 字节计数 03

起始地址低(字节) C4 204(h)~197状态 AC

读取数量高(字节) 00 212(h)~205状态 DB

读取数量低(字节) 16 218(h)~213状态 35

03读取保持寄存器 在一个或多个保持寄存器中取得当前的二进制值 MODBUS地址 40001~

MODBUS 请求

功能码 1 BYTE 0X03

起始地址 2 BYTE 0X0000 TO 0XFFFF

读取数量 2 BYTE 1 TO 125(0X7D)

MODBUS 响应

功能码 1 BYTE 0X03

字节计数 1 BYTE N*2

输入状态 N*2 BYTE

错误 响应

功能码 1 BYTE 0X03+ 0X80

错误代码 1 BYTE 0x1 or 0x2 or 0x3 or 0x4

举例

请求 响应

域名称 数据(hex) 域名称 数据(hex)

功能码 03 功能码 03

起始地址高(字节) 00 字节计数 06

起始地址低(字节) 6B 寄存器高(108) 02

读取数量高(字节) 00 寄存器低(108) 2B

读取数量低(字节) 03 寄存器高(109) 00

寄存器低(109) 00

寄存器高(110) 00

寄存器低(110) 64

04读取输入寄存器 在一个或多个输入寄存器中取得当前的二进制值

MODBUS 请求

功能码 1 BYTE 0X04

起始地址 2 BYTE 0X0000 TO 0XFFFF

读取数量 2 BYTE 1 TO 125(0X7D)

MODBUS 响应

功能码 1 BYTE 0X04

字节计数 1 BYTE N*2

输入状态 N*2 BYTE

错误 响应

功能码 1 BYTE 0X04+ 0X80

错误代码 1 BYTE 0x1 or 0x2 or 0x3 or 0x4

举例

5

MODBUS地址 30001~

请求 响应

域名称 数据(hex) 域名称 数据(hex)

功能码 04 功能码 04

起始地址高(字节) 00 字节计数 02

起始地址低(字节) 08 输入寄存器高(9) 00

读取数量高(字节) 00 输入寄存器低(9) 0A

读取数量低(字节) 01

功能码05:强置单线圈 强置一个逻辑线圈的通断状态写单线圈(开关量输出)

请求格式:

目标站号

1字节

应答格式:

若设置成功,原文返回

06号命令,设置单个保持寄存器预置单寄存器 把具体二进值装入一个保持寄存器

MODBUS 请求

功能码 1 BYTE 0X06

数据地址 2 BYTE 0X0000 TO 0XFFFF

设置数据 2 BYTE

MODBUS 响应

功能码 1 BYTE 0X06

数据地址 2 BYTE 0X0000 TO 0XFFFF

设置数据 2 BYTE

错误 响应

功能码 1 BYTE 0X06+ 0X80

错误代码 1 BYTE 0x1 or 0x2 or 0x3 or 0x4

0000继电器释放,0XFF00继电器吸合

举例 第9个保持寄存器的值为1234

请求 响应

域名称 数据(hex) 域名称 数据(hex)

功能码 05 功能码 05

起始地址高(字节) 00 00

起始地址低(字节) 08 08

读取数量高(字节) 12 12

读取数量低(字节) 34 34

功能码15:写多线圈(开关量输出)强置多线圈 强置一串连续逻辑线圈的通断

请求格式:

目标

站号

1字节

功能码

15

起始地址

高字节

1字节

起始地址低数量

字节

1字节

高字节

1字节

数量

低字节

1字节

强制值字强制值

节数

1字节

第1字节

1字节

CRC

2字节

功能码

05

线圈地址

高字节

1字节

线圈地址

低字节

1字节

强制值

高字节

1字节

强制值

低字节

1字节

CRC校验码

2字节

注:强制值= 0xFF00,则置线圈为ON;强制值=0x0000,则置线圈为OFF。

正确应答格式:

6

起始地址

高字节

1字节

数量

起始地址低字节

高字节

1字节 1字节

数量

低字节

1字节

目标站号

1字节

请求格式:

目标

站号

1字节

功能码

15

CRC校验码

2字节

功能码16:写多保持寄存器(模拟量输出)预置多寄存器 把具体的二进制值装入一串连续的保持寄存器

起始地址

功能码

高字节

16 1字节

起始地址低数量

字节

1字节

高字节

1字节

数量

低字节

1字节

强制值字强制值1

节数

1字节

高字节

1字节

强制值1

低字节

1字节

数量

低字节

1字节

CRC

CRC

2字节

正确应答格式:

目标站号

1字节

功能码

16

起始地址

高字节

1字节

数量

起始地址低字节

高字节

1字节 1字节

校验码

2字节

17 报告从机标识 可使主机判断编址从机的类型及该从机运行指示灯的状态

18 (884和MICRO 84) 可使主机模拟编程功能,修改PC状态逻辑

19 重置通信链路 发生非可修改错误后,是从机复位于已知状态,可重置顺序字节

20 读取通用参数(584L) 显示扩展存储器文件中的数据信息

21 写入通用参数(584L) 把通用参数写入扩展存储文件,或修改之

22~64 保留作扩展功能备用

65~72 保留以备用户功能所用 留作用户功能的扩展编码

73~119 非法功能

120~127 保留 留作内部作用

128~255 保留 用于异常应答

错误检测方法

1、奇偶校验

用户可以配置控制器是奇或偶校验,或无校验。这将决定了每个字符中的奇偶校验位是如何设置的。

如果指定了奇或偶校验,“1”的位数将算到每个字符的位数中(ASCII模式7个数据位,RTU中8个数据

位)。例如RTU字符帧中包含以下8个数据位: 1 1 0 0 0 1 0 1

整个“1”的数目是4个。如果便用了偶校验,帧的奇偶校验位将是0,便得整个“1”的个数仍是4个。

如果便用了奇校验,帧的奇偶校验位将是1,便得整个“1”的个数是5个。

如果没有指定奇偶校验位,传输时就没有校验位,也不进行校验检测。代替一附加的停止位填充至要传输

的字符帧中。

2、LRC检测

使用ASCII模式,消息包括了一基于LRC方法的错误检测域。LRC域检测了消息域中除开始的冒号及结

束的回车换行号外的内容。LRC域是一个包含一个8位二进制值的字节。LRC值由传输设备来计算并放到

消息帧中,接收设备在接收消息的过程中计算LRC,并将它和接收到消息中LRC域中的值比较,如果两值

不等,说明有错误。

LRC方法是将消息中的8Bit的字节连续累加,丢弃了进位。

LRC简单函数如下:

static unsigned char LRC(auchMsg,usDataLen)

unsigned char *auchMsg ; /* 要进行计算的消息 */

unsigned short usDataLen ; /* LRC 要处理的字节的数量*/

{ unsigned char uchLRC = 0 ; /* LRC 字节初始化 */

while (usDataLen--) /* 传送消息 */

uchLRC += *auchMsg++ ; /* 累加*/

7

return ((unsigned char)(-((char_uchLRC))) ;

3、【生成CRC-16校验字节的步骤】

①装如一个16位寄存器,所有数位均为1。

②该16位寄存器的高位字节与开始8位字节进行“异或”运算。运算结果放入这个16位寄存器。

③把这个16寄存器向右移一位。

④若向右(标记位)移出的数位是1,则生成多项式1和这个寄存器进行“异或”

运算;若向右移出的数位是0,则返回③。

⑤重复③和④,直至移出8位。

⑥另外8位与该十六位寄存器进行“异或”运算。

⑦重复③~⑥,直至该报文所有字节均与16位寄存器进行“异或”运算,并移位8次。

⑧这个16位寄存器的内容即2字节CRC错误校验,被加到报文的最高有效位

8

本文标签: 设备消息地址功能寄存器