Modbus RTU简介(上)
Posted zacch66
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Modbus RTU简介(上)相关的知识,希望对你有一定的参考价值。
1 前言
1.1 什麽是Modbus
-
Modbus是一种用于工业控制的标准通信协议,它定义了装置之间在应用层的消息封装模式、沟通方法、沟通顺序。
-
Modbus的优势 :
- Modbus协议是开源免费的
- Modbus支援多种常见工控接口(RS232, RS485, TCP/IP etc.),且可以各种物理层装置上传输(双绞线、光纤、无线等)
- Modbus格式简单易于开发
-
Modbus能够将众多设备连接到DCS, PLC系统上,再利用服务器(云、中央计算机)进行监控与下达指令,以便于集中式控制。
1.2 Modbus的通讯
- Modbus通信协议是一个(master/slave)架构,或者(client/server)架构,在整个通讯网路中能够同时拥有多个slaves但是只允许拥有一个专门发送request的master。
- Modbus是一个一主多从协议(最多可连接247台slave,所以slave地址范围在1~247之间),只有在master发出request时slave才会做出回应,slaves之间不能沟通。
- 每条master所发出的request,都包含一个slave地址,每台slave都会收到该request,都只有符合该地址的slave才会回应该请求,如图1-1(地址0是广播模式,每台slave都会运行指令但不会回应master)。
- ADU(Application Data Unit)是完整的协议传输封包而PDU(Protocol Data Unit)则是资料传输的基础单元,与通信无关,如图1-2所示。
1.3 Modbus的错误通讯
当master传送的request不符合格式、slave不支援此功能等问题时,代表slave不能正确解码request内容,这时slave就会response一个error response,其组成为[slave ID][error code][exception code]
- slave ID=original
- error code=function code + 0x80
- exception code=01, 02, 03, 04, etc(依照发生错误的原因)
- CRC校正码
2 Modbus重点内容
2.1 Modbus暂存器
2.1.1 暂存器种类
Modbus其中一重要的概念是暂存器,不同地址的暂存器存放着不同数据类型型与读写特性得资料,而这裡所说的暂存器地址不一定是固定的内存地址,也可以是开发者自行定义的连续或不连续的一块储存区域。我们可以把Modbus暂存器分为如图2-1所示的4大主要部分。
2.1.2 暂存器地址分配
- 这裡有关地址的概念容易混淆,我的理解是暂存器PLC地址是给"人"看的,想当然尔从1开始(使用10进位制),前缀的0、1、4、3只是用来代表功能码而已,真正要注意的是后4码地址。
- 暂存器Modbus协议地址是给"机器"看的,所以使用16进位制处理,从0开始,然后再搭配1byte的功能码处理。
2.2 RTU封包格式
- Modbus封包最大长度为256bytes
2.2.1 master request format
[从机地址] [功能码] [暂存器地址] [暂存器数量(word数)] [验证码]
ex : [1F] [04] [00 0A] [00 04] [D2 75]
2.2.2 slave response format
[从机地址] [功能码] [几个bytes] [data] [验证码]
ex : [1F] [04] [08] [00 01 FF FF 00 00 00 00] [54 FE]
2.2.2 封包之间的区隔
Modbus封包之间的区隔是使用3.5个字符时间来判断,在该时间区间内,master与slave不做任何动作,利用字符时间的机制只适用于Modbus RTU。
封包之间的时间间格在计算上其实还取决于鲍率,还有格式问题:
依据Modbus国家规范,一个字符时间为处理11 bits资料所需时间,一般包含一个起始位、8个数据位、1个校验位、一个停止位,而不是所谓一个byte(8 bits)的时间,这裡不要搞混,这是官方规定
所谓封包之间的间隔指的是在serial port上的所有封包,包含request、reaponse,只要有资料流淌,就必须规定他们之间的区分方法
所以我们假设当前鲍率为9600,也就是9600 bits per second,而3.5个字符时间就等于3.5*11=38.5位,那麽我们可以求得该Modbus RTU要求封包之间的时间间格为 : (38.5*1000)/9600 = 4.0104167ms
由于频繁的计算会对CPU造成负担,所以Modbus官方规定,当鲍率超过19200时,封包时间间格会固定为定值1.75ms
另外一种较为简易的设定是不管鲍率为何,统一设定成10ms的时间间格,好处是释放cpu压力、较为简便,对于对时间要求没有那麽即时的系统,坏处是效率较低、不够精准
另外Modbus还有一个字元之间的判断,一样是利用字符时间机制,假设一个数据中相邻两个字元的时间差在1.5个字符时间以上,就会判断该笔资料丢失 (1.5*11*1000)/baud rate ms,当鲍率超过19200时,时间间格设定成定值0.75ms
2.3 地址范围
Modbus的ID号为1bytes(0~255),但是前面有提过,slave最多只能设定成247,这是因为0是广播模式,而剩馀的248~255是Modbus的保留ID,供更高级开发用,所以实际应用上我们能设定的范围在1~247之间。
2.4 功能码
Modbus的功能码主要对应四个大方向—DO, DI, AO, AI,其中的功能码主要也是处理这四大方向(对应连接的slave提供的可能是温度数据、湿度数据、是否上锁等数位类比消息)。功能码占总封包1个byte,不过允许范围在1~127,0在上面有提到分配给广播模式,而128~255之所以不分配主要原因为假如1~127发生错误加上0x80的错误码后会变成让上限变成255,所以若是开放128以后的数会让功能码区段超过1个bytes的范围。
- 另外Modbus也提供使用者65~72, 100~110的自订义功能码区段
2.4.1 读取数位输出状态(DO)
- 功能码代号 : 01(0x)
- 功能 : 该功能码为读取coil线圈数位输出状态资讯,若状态为on则输出1,反之若为off则输出0
- 佔用大小 : 若为n个bits,则佔用N=n/8个bits,若不能整除则N+1
- 读写状态 : R/W
- 线圈地址上限 : 1~2000
- Modbus起始地址 : 0x0000~0xffff
Request
请求部份我们首先填入功能码01,再来需要注意的是起始地址为2个bytes,这裡填的Modbus的地址主要由使用者决定(0x0000~0xffff)分别为HI高位与LO低位,由线圈20~38(Dec)可得需请求19个线圈数据,但是我们实际读取的是Modbus地址19~37(Dec)因此将首地址转换成HEX为0x0013,数量地址也分成高低两位共2个bytes,所以我们可以得到00Hi 13Lo。
请求封包佔8bytes长度。
Response
如果我们要读取线圈20~38的状态,需要先计算总共需要回传38-20+1=19个bits,19/8=2…3,不能整除所以要多分配一个bytes(用来补足的bits都设定成0),可以得出回传的data佔有3个bytes。假设线圈20~27的状态分别为on-on-off-off-on-on-off-on,要注意我们需要从LSB开始存取状态,因此Binary Status为 1100 1101转换成HEX就是CD,以此类推我们可以得到图2-7的资料封包的排序如下所示。
响应封包的资料长度视请求的暂存器数量而定,最长不超过256bytes,data最长2000/8=250bytes。
2.4.2 读取数位输入状态(DI)
- 功能码代号 : 02(1x)
- 功能 : 该功能码为读取coil线圈数位输入状态资讯,若状态为on则输出1,反之若为off则输出0
- 佔用大小 : 若为n个bits,则佔用N=n/8个bits,若不能整除则N+1
- 读写状态 : R
- 线圈地址上限 : 1~2000
- Modbus起始地址 : 0x0000~0xffff
Request
请求部份我们首先填入功能码02,再来需要注意的是起始地址为2个bytes,这裡填的Modbus的地址主要由使用者决定(0x0000~0xffff)分别为HI高位与LO低位,由线圈19~218(Dec)可得需请求22个线圈数据,但是我们实际读取的是Modbus地址196~217(Dec)因此将首地址转换成HEX为0x00C4,数量地址也分成高低两位共2个bytes,所以我们可以得到00Hi C4Lo。
Response
如果我们要读取线圈197~218的状态,需要先计算总共需要回传218-197+1=22个bits,22/8=2…6,不能整除所以要多分配一个bytes(用来补足的bits都设定成0),可以得出回传的data佔有3个bytes。假设线圈197~204的状态分别为off-off-on-on-off-on-off-on,要注意我们需要从LSB开始存取状态,因此Binary Status为 1010 1100转换成HEX就是CD,以此类推我们可以得到图2-8的资料封包的排序如下所示。
2.5.1 读保持暂存器(AO)
- 功能码代号 : 03(4x)
- 功能 : 该功能码为读写暂存器类比输出状态资讯,其输出以Word为基本单位(1Word=2bytes)
- 佔用大小 : 若为n个Word,则佔用2*n个bytes
- 读写状态 : R/W
- 暂存器地址上限 : 1~125
- Modbus起始地址 : 0x0000~0xffff
Request
请求部份我们首先填入功能码03,再来需要注意的是起始地址为2个bytes,这裡填的Modbus的地址主要由使用者决定(0x0000~0xffff)分别为HI高位与LO低位,由暂存器地址108~110(Dec)可得需请求3个暂存器数据,但是我们实际读取的是Modbus地址107~109(Dec)因此将首地址转换成HEX为0x006B,数量地址也分成高低两位共2个bytes,所以我们可以得到00Hi 6BLo。
Response
如果我们要读取暂存器108~110的状态,需要先计算总共需要回传110-108+1=3个Word,2*3=6个bytes,可以得出回传的data佔有6个bytes。假设暂存器108的输出为555(Dec),我们可以经过转换得到0x022B,然后依高低位分别填入02Hi 2BLo,依此类推暂存器109、110输出分别为0以及100,经过转换分别得到00 00与00 64(HEX)。
另外假如回传暂存器状态设定成32bits,那麽暂存器取值就需要佔用到108、109两个暂存器位置共4bytes,下一个暂存器将从110开始。
2.5.2 读输入暂存器(AI)
- 功能码代号 : 04(3x)
- 功能 : 该功能码为读取暂存器类比输入状态资讯,其输出以Word为基本单位(1Word=2bytes)
- 佔用大小 : 若为n个Word,则佔用2*n个bytes
- 读写状态 : R
- 暂存器地址上限 : 1~125
- Modbus起始地址 : 0x0000~0xffff
Request
请求部份我们首先填入功能码04,再来需要注意的是起始地址为2个bytes,这裡填的Modbus的地址主要由使用者决定(0x0000~0xffff)分别为HI高位与LO低位,范例中我们要读取暂存器9的数值,但是我们实际读取的是Modbus地址08因此将首地址转换成HEX为0x0008,数量地址也分成高低两位共2个bytes,所以我们可以得到00Hi 08Lo。
Response
如果我们要读取暂存器9的状态,总计1个Word,共2个bytes,可以得出回传的data佔有2个bytes。假设暂存器9的输出为10(Dec),我们可以经过转换得到0x000A,然后依高低位分别填入00Hi 0ALo。
另外假如回传暂存器状态设定成32bits,那麽暂存器取值就需要佔用4bytes,那麽取直就需要暂用暂存器9与10的位置。
以上是关于Modbus RTU简介(上)的主要内容,如果未能解决你的问题,请参考以下文章