MODBUS支持两种模式,RTU模式和ASCII码模式。
RTU模式采用16进制发送和接受数据,校验方式采用CRC循环冗余校验。
ASCII码模式采用字符的方式发送数据,校验方式采用LRC校验。
CRC校验码运算包含整个数据帧,
LRC校验码运算报头(:)不参与运算,LRC在数据之后,在\CR\LF之前
当使用MODBUS
以EMERSON EC20PLC为例,分别说明两种模式的报文
A:读取EC20的M0的状态(01功能码的例子,读单个线圈)
根据EC20的MODBUS地址映射关系,EC20的M0线圈的MODBUS地址为2000,由于RTU采用16进制数据,ASCII模式采用16进制的字符,所以,需要知道2000的16进制值为07D0。
1:RTU模式
1. 1
请求帧为:
01H 01H 07 D0H 00 01H FDH 47H
站号 功能码 MODBUS首地址 数据个数 CRC校验码
当M0=OFF时的响应帧为:
01H 01H 01H 00H 51H 88H
站号 功能码 数据个数 数据值 CRC校验码
当M0=ON时的响应帧为:
01H 01H 01H 01H 90H 48H
站号 功能码 数据个数 数据值 CRC校验码
2:ASCII码模式(字符模式)
采用ASCII码模式,需要加上报头(:),16进制值为3A,报尾为CRLF(转意字符\CR\LF),其他的部分和RTU模式一样,例如地址2000,仍然要转化为16进制,并以字符的形式表现,这是特别需要注意的,很多人一开始都会犯错误。
请求帧为:(以下表示ASCII码帧时,都以这种格式表示,有效帧在双引号内,表示是一个字符串,以便符合高级语言的表示形式,帧之间也并不存在空格,本文只是为了描述的方便性)
“: 01 01 07 D0 00 01 26 \CR\LF”
报头 站号 功能码 MODBUS首址 数据个数 LRC校验码 规定的报尾
响应帧为(M0=OFF时):
“: 01 01 01 00 FD \CR\LF”
报头 站号 功能码 数据个数 数据值 LRC校验码 规定的报尾
响应帧为(M0=ON时):
“: 01 01 01 01 FD \CR\LF”
报头 站号 功能码 数据个数 数据值 LRC校验码 规定的报尾
B:读取EC20的D0----D3寄存器的值(03功能码)
1:RTU模式
B1。1
请求帧
01H 03H 0000H 0001H 84H 0AH
站号 功能码 MODBUS首址 数据个数 CRC校验码
响应帧(D0=0,WORD型16BIT时)
01H 03H 02H 0000H B8H 44H
站号 功能码 数据个数 数据值 CRC校验码
响应帧(D0=12H,WORD型16BIT时)
01H 03H 02H 0012H 38H 49H
站号 功能码 数据个数 数据值 CRC校验码
可想而知的是,如果D0被定义为一个双字(32BIT,那么,请求帧如果只定义读取一个数据,则数据是读不到的,当然,这取决于各种控制器数据的内存结构,要么取到高半字,要么取到低半字)
例如请求帧01H 03H 0000H 0002H C4H 0BH这个时候才可能读到一个完整的双字。
其响应帧为(D0=16#FFFF时):01H 03H 04H 0000H FFFFH FBH 83H
这个时候才可以读到一个32BIT双字
又如D0=12H,D2=34H,D4=56H,D6=100H,都是双字时,发出请求帧为:
01H 03H 0000H 0008H 44H 0CH
响应帧为:
01H 03H 10H 00H 00H 00H 12H 00H 00H 00H 34H 00H 00H 00H 56H 00H 00H 01H 00H F2H D6H
2:ASCII码模式(读D0)
B2.1
请求帧(1个数据)
“: 01 03 0000 0001 FB \CR\LF”
报头 站号 功能码 MODBUS首址 数据个数 LRC码 报尾
响应帧(D0=12H,16BIT WORD时):
“: 01 03 02 000C EE \CR\LF”
报头 站号 功能码 数据个数 数据值 LRC码 报尾
B2.2
请求帧(2个32BIT数据,即D0,D2为双字时)
“: 01 03 0000 0004 F8 \CR\LF”
报头 站号 功能码 MODBUS首址 数据个数 LRC码 报尾
响应帧(PLC内D0=12H,D2=34H,32BIT DWORD时)
“ : 01 03 08 000C 0000 0022 0000 C6 \CR\LF”
报头 站号 功能码 数据个数 数据值 LRC码 报尾
B2.3
请求帧(4个16BIT数据)
“: 01 03 0000 0004 F8 \CR\LF”
报头 站号 功能码 MODBUS首址 数据个数 LRC码 报尾
响应帧为(PLC内D0=12,D1=34,D2=56,D3=78,为16BIT WORD十进制时)
“: 01 03 08 000C 0022 0038 004E 40 \CR\LF”
报头 站号 功能码 数据个数 数据值1,2,3,4 LRC码 报尾
C:05功能码(写单个线圈)
1:置0003(Y3)线圈ON(RTU)
01 05 00 03 FF 00 7C 3A而不是01 05 00 03 00 01 CRC
2:置0003(Y3)线圈OFF(RTU)
01 05 00 03 00 00 3D CA
3:置2000(M0)线圈ON(RTU)
01 05 07 D0 FF 00 8C B7而不是01 05 07 D0 00 01 CRC
4:置2000(M0)线圈OFF(RTU)
01 05 07 D0 00 00 CD 47
以上数据通过COMMIX串口调试工具获得。尚有LRC,CRC的算法有待研究。
至于MODBUS TCP的方式,和这两种方式的异同之处,尚待研究
LRC校验码的生成方法:
去掉报头和报尾,逐数据相加,在取和结果取补码,得到LRC码,需要注意的是,是每字节以16进制相加
CRC循环冗余码的算法:
查过了相关的资料,也不太麻烦,网络上的例子多得是,可以参考
01功能码虽然说只能读取单个线圈,但实践中发现可以读去多个线圈,以下是一些例子
注意:当 :010107D000081F\CR\LF发出时,得到的是从2000开始的8BIT(1BYTE)的数据,
响应为::010101FFFE\CR\LF(8BIT为全ON)
|