modbus解读

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

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 十六进制),从设备不需任何附加的信息。

错误检测域
标准的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 模式帧结构:
起始位 设备地址 功能代码 数据
LRC 校验 结束符 1个字符 2个字符
2个字符
n 个字符
2个字符
2个字符
使用ASCII 字符帧时,传输位的序列是:每个字符或字节以如下方式发送(从左到右): 最低有效位...最
高有效位
无奇偶校验位用个停止位代替。

RTU 消息发送至少要以 3.5 个字符时间的停顿间隔开始。

传输过程中,网络设备 不 断侦测网络总线,包括停顿间隔时间内。

当第一个域(地址域)接收到,相应的设备就对 接 下来的传输字符进行解码,一旦有至少 3. 5 个字符时间的停顿就表示该消息的结束。

RTU 每个字节的位 • 1个起始位
• 8个数据位,最小的有效位先发送 • 1个奇偶校验位,无校验则无
• 1
个停止位(有校验时),2个Bit (无校验时) 错误检测域 CRC(循环冗长检测)
RTU 模式中整个消息帧必须作为一连续的流转输,如果在帧完成之前有超过 1.5 个 字符时间的停顿时间,接收设备将刷新不完整的消息并假定下一字节是一个新消息的地址 域。

同样地,如果一个新消息在小于 3. 5 个字符时间内接着前个消息开始,接收的设备将 认为它是前一消息的延续。

如果在传输过程中
有以上两种情况发生的话,必然会导致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命令简介
起始应有目标站号功能码数据 CRC校验码
》》3.5个字符的报文间隔1字节1字节N字节2字节
注:下面对于各请求命令的“应答格式”的描述是指命令被正确执行时的应答格式。

若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
起始地址高(字节) 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
举例
请求响应
域名称数据(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地址30001~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
举例
请求响应
域名称数据(hex)域名称数据(hex)
功能码04 功能码04
起始地址高(字节) 00 字节计数02
起始地址低(字节) 08 输入寄存器高(9)00
读取数量高(字节) 00 输入寄存器低(9)0A
读取数量低(字节) 01
功能码05:强置单线圈强置一个逻辑线圈的通断状态写单线圈(开关量输出)请求格式:
目标站号功能码线圈地址
高字节
线圈地址
低字节
强制值
高字节
强制值
低字节
CRC校验码
1字节05 1字节1字节1字节1字节2字节注:强制值=0xFF00,则置线圈为ON;强制值=0x0000,则置线圈为OFF。

应答格式:
若设置成功,原文返回
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字节
…CRC
1字节15 1字节1字节1字节1字节1字节1字节…2字节正确应答格式:
目标站号功能码起始地址
高字节
起始地址低字节
数量
高字节
数量
低字节
CRC校验码
1字节15 1字节1字节1字节1字节2字节
功能码16:写多保持寄存器(模拟量输出)预置多寄存器把具体的二进制值装入一串连续的保持寄存器请求格式:
目标站号功能码
起始地址
高字节
起始地址低
字节
数量
高字节
数量
低字节
强制值字
节数
强制值1
高字节
强制值1
低字节
…CRC
1字节16 1字节1字节1字节1字节1字节1字节1字节…2字节正确应答格式:
目标站号功能码起始地址
高字节
起始地址低字节
数量
高字节
数量
低字节
CRC
校验码
1字节16 1字节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++ ; /* 累加*/
return ((unsigned char)(-((char_uchLRC))) ;
3、【生成CRC-16校验字节的步骤】
①装如一个16位寄存器,所有数位均为1。

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

运算结果放入这个16位寄存器。

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

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

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

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

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

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

相关文档
最新文档