记录基于 MODBUS
协议采集设备数据时遇到的各种坑。
MODBUS
协议是工业领域常用的通信协议,master 通过请求-响应的方式获取 slave 的数据。数据中心使用了大量基于 MODBUS
协议进行通信的设备,包括温湿度、交直流电表、电池仪、HVDC、逆变器、UPS 等。在采集数据中心的物理环境数据时,相当一部分工作量在调试使用 MODBUS
协议的设备。还有一些设备使用基于 UPD
的 SNMP
通信,这些设备调试起来会比较快。
常用的 MODBUS
协议还分为 RTU
及 TCP
,前者基于串口通信,后者基于 TCP
协议通信,MODBUS TCP
通信只需要网络正常即可,MODBUS RTU
通信则涉及到硬件线缆、读写参数等问题,设备无响应数据的问题主要存在于 MODBUS RTU
中,数据异常的问题在两种模式下均可遇到。
硬件
硬件上的问题,单从软件上看不出来,大部分情况下只能观察到 master
已经发送请求,但收不到任何响应。遇到过的问题如下:
线序
采集器通过双绞线与设备连接起来,如果设备端引脚使用的线序与采集器引脚线序一致,那么一切都顺利,调试时不用考虑线序的问题,只需要关注数据是否正确。然而,现实却并非如此。
现象
当线序存在问题时,采集器能成功发出请求,但设备无任何响应,某些情况下,设备——比如温湿度传感器——需要采集器通过双绞线供电,使用线序错误的双绞线连接设备后,设备本身便会停止工作。
解决方法
使用 USB
转 RS485
的转换器,双绞线一端连接设备,另一端剥开,将双绞线里的数据线与电源线连接至转换器,比如蓝
接485+
,蓝白
接485-
等,尝试不同的排列(注意安全),观察向设备发送数据后是否有数据返回。
不同设备使用的线序也不一定相同,有的使用蓝
和蓝白
收发数据,有的使用绿
和绿白
收发数据,也不能排除有的设备使用蓝
和绿白
收发数据。有的需要接入电源线,有的不能接入电源线。
线序的问题取决于厂商的实现,只能在现场调试确认。
某机房的所有串口设备共使用了 8 种线序。
电压不足
采集器可能因质量缺陷或设计本身导致了引脚电压带不动连接的设备
现象
设备无法正常上报测点数据,例子:漏水模块接到电压不够的 DI
口,当发生漏水时,采集器 DI
口的数据没有变化。
解决方法
想办法增加给设备的电压。
串口未供电
采集器的某些串口在设计时未加入供电功能。
现象
需要供电的设备在连接到未供电的串口后,无法工作。
解决方法
将设备连接到可以供电的串口。
设备关机
现象
同一串口下接了多个设备,其中某几个设备一直没有响应。
解决方法
调试时需要和现场人员确认设备是否开机。
数据异常
现象
单个测点数据异常,其他测点数据正常。
原因
可能是设备传感器等故障。
解决方法
更换设备元器件。
设备性能
某些设备出于性能等原因,限制了向它请求的 master
个数,当多个 master
同时向它请求数据时,可能只处理第一个 master
的请求,不响应后续 master
请求。或者所有 master
发出的请求均间断失去响应。
现象
- 设备无任何数据返回,但另一个
master
可以正常采集到数据 - 设备间断无响应,其他
master
也间断地请求不到数据
解决方法
重启设备或考虑减少 master
数量,避免多采。
软件
除硬件问题外,软件层面的设置也会影响数据的读取,大部分情况下是数据异常,也存在设备无数据返回的情况。
slave
地址
现象
已成功发出请求,设备无任何响应。
解决方法
确认 slave
地址填写无误。
串口参数
波特、数据位、停止位、校验位 都会影响数据的传输。
现象
从设备接收到的数据明显是乱码或者根本接收不到数据。
解决方法
首先考虑调整波特,最常用的是 9600
,其次是 19200
。其次尝试修改其他参数,大部分情况下,数据位为 8
,停止位为 1
,校验位为 N
。
请求频率
某些设备性能不够,请求频率过高时无响应。
现象
- 挂在同一串口下的多个设备,有些正常返回数据,有些无任何数据返回
- 某个地址(串口或者IP+Port)下的单个设备,间断出现无响应的情况
解决方法
降低请求频率。
数据异常
现象
能接收到数据,但解析后的测点值明显错误。
解决方法
可能是设备本身的 bug
,原本请求地址为 1
的数据,响应报文中的地址却是 2
,也就是数据错乱。这种情况下,最好关闭串口并重新打开,同时,在收到响应后,对返回的 slave
地址、功能码、CRC
校验码进行验证。
协议文档
厂商提供的文档质量千奇百怪参差不齐,这也是调试过程中遇到的主要问题。
现象
数据错误。
解决方法
只能尝试。
极端情况下,文档中只会指出某个测点的寄存器号为 3xxxx
,请求该测点的功能码可能是 03
,也可能是04
,据说有条潜规则是 3xxxx
的功能码是 04
,4xxxx
的功能码是 03
,很奇怪,想不通。
说完功能码,再说寄存器地址,文档中的 3xxxx
,它实际的地址可能是 xxxx
,也可能是 xxxx-1
,也可能就只是 3xxxx
,还有可能是 3xxxx - 1
,还有可能要除以 2
。可能是十进制下的数值,也可能是十六进制下的数值。
再就是字节序,MODBUS
协议规范中指明使用高尾端,但规范是规范,厂家的实现相对随意,高尾端、低尾端、高尾端字序+字交换、低尾端字序+字交换,4 种字节序都是可能的。
然后是数据类型,MODBUS
存储的单位是寄存器,2个字节,一般是 int16
,也可能是 uint16
,占据 2 个寄存器的测点可能用 float
存储。
还有的设备有隐含规则,比如需要使用的测点的寄存器地址范围是 [1, N]
,但是如果只请求 [1, N]
范围的寄存器数据,那么设备响应的数据会发生错乱,厂商给的反馈是,一定要请求 [0, N]
范围的寄存器,即使 0
号寄存器不需要,也要请求。再比如有的设备使用功能码 01
请求数据,根据 MODBUS
协议规范,请求 N
个线圈,返回的数据部分是 ceil(N/8)
个字节,但设备实际上返回了 2N
个字节。遇到这些违背规范的情况,也只能去兼容设备。
一般通信地址是 IP
的设备,使用的是 MODBUS TCP
协议,但也不能排除某些使用了串口服务器的设备,实际使用的是 MODBUS RTU on TCP
,也就是基于 TCP
的 MODBUS RTU
协议,这种情况只能抓包排查。
一份好的协议文档,应该清楚地说明各个测点所在的寄存器地址、使用的功能码、测点存储的数据类型、字节序,但很多厂商提供的文档,或多或少都缺少一些内容,给实际调试设备时增加了一定的工作量。