使用modbus单点读取地址是轮询可能会导致效率很低,频繁发送读取报文会导致plc响应时间拉长,批量读取可大大减少数据通信的过程,每次读取完成后,在内存中异步处理返回来的数据数组。
modbus 功能码简介 :
0x01: 读线圈寄存器
0x02: 读离散输入寄存器
0x03: 读保持寄存器
0x04: 读输入寄存器
0x05: 写单个线圈寄存器
0x06: 写单个保持寄存器
0x0F 写多个线圈寄存器
0x10: 写多个保持寄存器
读取指令多用到 01~04 功能码。在这里用到的包有 NModbus4,Nuget可直接获取。开发语言C#
以 读取保持寄存器 03 为例 看下Nmodbus4里的方法签名
// // 摘要: // Reads contiguous block of holding registers. // // 参数: // slaveAddress: // Address of device to read values from. // // startAddress: // Address to begin reading. // // numberOfPoints: // Number of holding registers to read. // // 返回结果: // Holding registers status ushort[] ReadHoldingRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints);
返回类型为 ushort[] 数组,slaveAddress 从机地址,也就是plc的设备id,startAddress 读取起始地址,numberOfPoints 这个是重点,这个参数决定每次读取的点号数量。写1的话表示每次读取一个点号。
private ushort[] registerBuffer;
registerBuffer = master.ReadHoldingRegisters(1, 1, 100);
定义一个字节数组用来接收返回值
当读取到数据组时 registerBuffer 可根据需要处理,可拼接成json发送至平台消费者,或者开启子线程循环字节数组,将点号值返回消费者。
可以计算下,正常工控一个设备点号可能在 100个左右,如果单点读取,轮询可能需要1分钟时间,如果开启100个子线程同时读取,还可以接受,但是1000个点呢,对计算机资源耗费巨大。综合考虑
批量读取还是经济换算的。
for (int i = 0; i < registerBuffer.Length; i++) { { PublishMessage(registerBuffer[i]); } }
需要注意的是,使用modbus协议批量读取 PLC 数据时需要跟PLC程序开发者做好沟通规划好数据区,将返回数据集中在相邻的寄存器地址里,方便读取。