大多数调试会集中在*2层,数据方面的层次.还有一些调试会发生在连接层,但是连接层是可见的物理元件,要容易一些.
*2层的详细和举例—Modbus RTU的报文和功能号
Modbus常用的功能号(*2层报文的FC字节)对应了常用的四种数据.
功能号 功能
1 从”从”设备读线圈Coil,即读0xxxxx.
2 读离散输入,即读1xxxxx
3 读保持寄存器,即读4xxxxx
4 读输入寄存器,即读3xxxxx 注意和3不要混淆
5 向”从”设备写单个线圈
6 写单个保持寄存器
15 写多个(连续的)线圈
16 写多个(连续的)保持寄存器
我们一个一个来看,在modbus通讯里,数据交换是怎么进行的,发生了什么?
1. 读保持寄存器(hold register),即读4xxxxx数据. 为什么先说它,因为4xxxxx数据类型是16位的,可以表达整数,正负和浮点,用得比较多.
上面说过,Modbus是一主多从的链路.从设备有识别号,可以叫从站地址,就是*2报文里面的SA字节.
例子:假设主站需要取得2号从站,40019到40025的7个字寄存器数据,*1层次的语言.
主设备解释,执行过程,*2层次语言,会话过程是这样的:
Q主设备发出读功能(全部数据用16进制表示,在主发出功能命令之前,线路是静默的,即电线上没有信号可能有电):
SA FC SRHI SRLO NRHI NRLO CRCHI CRCLO
02 03 00 12 00 07 A4 3E
其中第一个02是向其请求数据的从设备号;
第二个字节03, 是告诉对方主站需要4xxxxx的保持寄存器数据;
后面第三第四的00 12,是告诉对方,我从40019开始.大家一定要注意,40019在报文里是用18表示的(00 12是2字节十六进制).也就是说,虽然modbus规定寄存器从?????1开始,比如40001,但是私底下,它自己是从0开始的.就是因为这个,很多情况数据会错位,导致不正确.如果你的数据主从对不上,试下错位,屡试不爽,经常经常,尤其浮点(后面再说)不直观不容易发觉.
第五第六字节,表示请求数据(寄存器)的个数.0007就是7个.
第七第八A43E,是CRC校验,暂时不管.
R从设备都处在接收(听主命令)状态,不管是不是呼叫它的.这时2号设备也接到了,除了2号设备,其它听到不关它事,只有2号回应.
02 03 0E 00 00 00 01 00 02 00 0A 00 64 03 E8 27 10 43 FD
40019 40020 40021 40022 40023 40024 40025
第一字节02的意思是,我02回复;
第二字节03的意思是,我回答的是你要的03功能,即4xxxxx数据;
第三字节0E的意思是,我回答的有效数据有14个字节(0E是十六进制的),就是你要的7个字(一个字16位,一个字节8位,2个字节byte组成1个字word).
第四字节开始到第17字节,后面每2个字节数据对应那7个寄存器,就是从名字叫40019到40025寄存器的数据是:
寄存器 数据十六进制 数据十进制
40019 00 00 0
40020 00 01 1
40021 00 02 2
40022 00 0A 10
40023 00 64 100
40024 03 E8 1000
40025 27 10 10000
这样,从*2回到了*1层,展现给工程人员.
以上,两个帧的报文,完成对话,一问一答,读到数据. 要是自己编程(比如VB)或者用串口调试(不是modbus层),你完全可以模仿主,发出那段简单的读取报文,看看从设备是不是乖乖(主仆颠倒的事情多呢)呈上数据.
顺带说一下,这里涉及到了*3层次,即时序的问题.刚开始,线路是静默的,一次对话启动,主先占用线路主动发出申请,然后放弃线路使用权;然后有关的从占用线路,发回应答,再放弃线路.小的衔接不说.因为从站是跟着主站走,所以时序中,定好主站时机,就确定了通讯时序.一般主站启动,有定时方式和事件方式.要求不高的,定时发命令即可(比如间隔1秒),要求的是时间足够长,能让从站完全发回数据被主站接收.这样可能保守和浪费,所以也有采用事件方式的.事件就是捕捉或者监控上次启动的通讯结束,然后立即启动下一个对话,这样时间利用比较紧凑,获得的数据更新比较快.
16-07-06 16:55