Modbus RTU踩坑全记录:C#串口通信到工业设备数据采集
上个月帮一个汽车零部件厂改造数据采集系统现场有30多台台达PLC和温度传感器全是Modbus RTU协议。一开始踩了不少坑串口经常断开、CRC校验通不过、设备响应超时。折腾了一周终于搞定现在系统稳定运行采集周期100ms数据准确率99.9%。今天把整个流程和踩坑经验分享给大家。一、整体采集流程先给大家看一下整个系统的核心流程从串口初始化到多设备轮询每一步都有细节要注意。是是否否否是串口初始化构建Modbus请求帧CRC16校验计算发送请求帧等待设备响应响应超时?重发请求计数1重发次数3?标记设备离线解析响应帧CRC校验通过?提取数据并转换存储/上传数据轮询下一个设备二、核心实现细节串口初始化Modbus RTU是基于串口的通信协议C#里用SerialPort类就能实现。关键参数要记牢波特率通常是9600或19200数据位8停止位1校验位None这是工业设备最常用的配置。初始化时要注意两点一是打开串口后要判断IsOpen属性确认串口真的打开了再继续二是程序退出时一定要释放串口资源否则下次启动可能会提示“串口被占用”。Modbus RTU帧结构Modbus RTU的帧结构很简单主站请求帧包括1字节设备地址、1字节功能码、2字节起始地址、2字节寄存器数量、2字节CRC校验。从站响应帧类似把起始地址和数量换成了字节数和实际数据。最常用的功能码是03读保持寄存器几乎所有PLC和传感器都支持。比如要读取地址为1的PLC从寄存器100开始的5个寄存器按照帧结构组装好数据就行。CRC16校验这是最容易踩坑的地方。Modbus RTU用的是CRC-16-IBM多项式计算出来的校验码是2字节发送时要注意字节序——低字节在前高字节在后。很多人一开始会把高字节放前面导致设备根本不响应或者响应后校验通不过。多设备轮询机制Modbus RTU是单主多从结构总线上只能有一个主站所以主站要依次轮询每个从站设备。每个设备之间要留20-50ms的间隔避免前一个设备的响应和后一个设备的请求冲突。还要设置合理的超时时间一般300-500ms比较合适。如果设备没响应就重发请求重发3次还不行就标记设备离线继续轮询下一个不要让一个设备影响整个采集流程。三、踩坑经验总结串口资源释放问题有一次程序异常退出重启后串口一直打不开后来发现是之前的进程没释放串口资源。最好用using语句包裹SerialPort或者在程序退出时显式调用Dispose。设备地址冲突现场有两个温度传感器地址设成了1导致采集到的数据一会儿正常一会儿乱码。提前用串口调试工具逐个测试设备地址能避免很多麻烦。电磁干扰工厂里电机多干扰大经常出现CRC校验错误。后来换成了屏蔽双绞线并且在程序里加了重传机制问题就解决了。数据类型转换Modbus寄存器是16位的而实际数据可能是32位整数、浮点数或者字符串。要根据设备手册里的定义正确转换数据类型比如两个寄存器拼成一个32位整数时要注意高低字的顺序。四、实际运行效果系统上线后对接了32台设备采集周期设为100msCPU使用率稳定在3%左右内存占用不到100MB。连续运行1个月没有出现过串口断开或数据丢失的情况设备在线率99.8%完全满足生产现场的需求。Modbus RTU虽然是个老协议但在工业现场应用非常广泛。只要注意这些细节就能用C#快速实现稳定可靠的数据采集。