DolphinDB Modbus协议接入:PLC数据采集
目录摘要一、Modbus协议概述1.1 什么是Modbus1.2 Modbus特点1.3 Modbus寄存器类型二、DolphinDB Modbus插件2.1 插件安装2.2 连接配置三、数据读取3.1 读取线圈3.2 读取离散输入3.3 读取输入寄存器3.4 读取保持寄存器四、数据写入4.1 写入线圈4.2 写入保持寄存器五、数据解析5.1 整数解析5.2 浮点数解析5.3 字符串解析六、轮询采集6.1 定时轮询6.2 多设备轮询七、实战案例7.1 PLC数据采集系统八、总结参考资料摘要本文深入讲解DolphinDB Modbus协议接入技术。从Modbus协议原理到插件配置从寄存器读取到数据解析从轮询采集到实时写入全面介绍Modbus数据采集的核心方法。通过丰富的代码示例帮助读者掌握PLC数据采集的核心技能。一、Modbus协议概述1.1 什么是ModbusModbus是工业领域广泛使用的通信协议Modbus架构主站DolphinDB从站1PLC从站2传感器从站3仪表通信方式Modbus TCPModbus RTU1.2 Modbus特点特点说明简单可靠协议简单稳定可靠广泛应用工业标准协议多种传输TCP/RTU/ASCII开放免费无授权费用1.3 Modbus寄存器类型类型地址范围访问说明线圈00001-09999读写开关量输出离散输入10001-19999只读开关量输入输入寄存器30001-39999只读模拟量输入保持寄存器40001-49999读写模拟量输出二、DolphinDB Modbus插件2.1 插件安装//检查插件 getLoadedPlugins()//加载Modbus插件 loadPlugin(modbus)//查看插件函数 modbus::getPluginFunctions()2.2 连接配置//Modbus TCP连接 connmodbus::connectTcp(192.168.1.100,502)//Modbus RTU连接串口 connmodbus::connectRtu(/dev/ttyUSB0,9600,N,8,1)//参数串口、波特率、校验位、数据位、停止位三、数据读取3.1 读取线圈//连接Modbus设备 connmodbus::connectTcp(192.168.1.100,502)//设置从站ID modbus::setSlaveId(conn,1)//读取单个线圈地址0 coilmodbus::readCoil(conn,0,1)print(线圈状态: string(coil[0]))//读取多个线圈地址0-9 coilsmodbus::readCoil(conn,0,10)print(线圈状态: string(coils))3.2 读取离散输入//读取离散输入地址10001对应地址0 inputsmodbus::readDiscreteInput(conn,0,8)print(离散输入: string(inputs))3.3 读取输入寄存器//读取单个输入寄存器 valuemodbus::readInputRegister(conn,0,1)print(输入寄存器值: string(value[0]))//读取多个输入寄存器 valuesmodbus::readInputRegister(conn,0,10)print(输入寄存器值: string(values))3.4 读取保持寄存器//读取保持寄存器 valuesmodbus::readHoldingRegister(conn,0,10)print(保持寄存器值: string(values))四、数据写入4.1 写入线圈//写入单个线圈 modbus::writeSingleCoil(conn,0,true)//打开 modbus::writeSingleCoil(conn,0,false)//关闭//写入多个线圈 modbus::writeMultipleCoils(conn,0,[true,false,true,false])4.2 写入保持寄存器//写入单个保持寄存器 modbus::writeSingleRegister(conn,0,100)//写入多个保持寄存器 modbus::writeMultipleRegisters(conn,0,[100,200,300])五、数据解析5.1 整数解析//16位整数解析defparseInt16(values,offset0){returnvalues[offset]}//32位整数解析两个寄存器defparseInt32(values,offset0){returnvalues[offset]*65536values[offset1]}//有符号整数defparseSignedInt16(values,offset0){vvalues[offset]returniif(v32768,v-65536,v)}5.2 浮点数解析//32位浮点数解析IEEE754defparseFloat32(values,offset0){//需要将两个16位寄存器转换为32位浮点数//使用位操作 highvalues[offset]lowvalues[offset1]//转换逻辑returnfloat32fromBits(high*65536low)}5.3 字符串解析//字符串解析defparseString(values,length){charsarray(CHAR,length)for(iin0..length){chars[i]char(values[i/2](8*(i%2)))}returnconcat(chars)}六、轮询采集6.1 定时轮询//创建流表 share streamTable(100000:0,device_idtimestamptemperaturepressureflow,[SYMBOL,TIMESTAMP,DOUBLE,DOUBLE,DOUBLE])asmodbus_stream//轮询函数defpollModbus(conn,slaveId,interval1000){modbus::setSlaveId(conn,slaveId)while(true){try{//读取寄存器 valuesmodbus::readInputRegister(conn,0,6)//解析数据 temperaturevalues[0]/10.0pressurevalues[1]/10.0flowvalues[2]/10.0//写入流表 insert into modbus_stream values(device_string(slaveId),now(),temperature,pressure,flow)}catch(ex){print(读取失败: ex)}sleep(interval)}}//启动轮询 submitJob(modbus_poll,Modbus轮询,def(){pollModbus(conn,1,1000)})6.2 多设备轮询//多设备轮询defpollMultipleDevices(conn,slaveIds,interval1000){while(true){for(slaveIdinslaveIds){try{modbus::setSlaveId(conn,slaveId)valuesmodbus::readInputRegister(conn,0,3)temperaturevalues[0]/10.0pressurevalues[1]/10.0flowvalues[2]/10.0insert into modbus_stream values(device_string(slaveId),now(),temperature,pressure,flow)}catch(ex){print(设备 string(slaveId) 读取失败)}}sleep(interval)}}//启动多设备轮询 submitJob(modbus_multi_poll,多设备轮询,def(){pollMultipleDevices(conn,[1,2,3,4,5],1000)})七、实战案例7.1 PLC数据采集系统//PLC数据采集系统//1.创建分布式表 dbdatabase(dfs://modbus_db,VALUE,1..100)schematable(1:0,device_idtimestamptemperaturepressureflow_ratelevel,[SYMBOL,TIMESTAMP,DOUBLE,DOUBLE,DOUBLE,DOUBLE])db.createPartitionedTable(schema,plc_data,device_id)//2.创建流表 share streamTable(100000:0,device_idtimestamptemperaturepressureflow_ratelevel,[SYMBOL,TIMESTAMP,DOUBLE,DOUBLE,DOUBLE,DOUBLE])asmodbus_stream//3.启用持久化 enableTablePersistence(modbus_stream,true,true,1000000)//4.订阅流表写入分布式表 subscribeTable(,modbus_stream,persist,-1,def(msg){loadTable(dfs://modbus_db,plc_data).append!(msg)},10000,5000)//5.连接Modbus设备 connmodbus::connectTcp(192.168.1.100,502)//6.启动轮询 submitJob(plc_poll,PLC轮询,def(){modbus::setSlaveId(conn,1)while(true){try{valuesmodbus::readInputRegister(conn,0,8)insert into modbus_stream values(PLC_001,now(),values[0]/10.0,//温度 values[1]/10.0,//压力 values[2]/10.0,//流量 values[3]/10.0//液位)}catch(ex){print(读取失败: ex)}sleep(1000)}})//7.监控defmonitorModbus(){print( Modbus监控 )print(流表行数: string(execcount(*)frommodbus_stream))print(最新数据: )select top5*frommodbus_stream}monitorModbus()print(PLC数据采集系统启动完成)八、总结本文详细介绍了DolphinDB Modbus协议接入Modbus协议寄存器类型、通信方式插件配置TCP连接、RTU连接数据读取线圈、离散输入、寄存器数据写入线圈写入、寄存器写入数据解析整数、浮点数、字符串轮询采集定时轮询、多设备轮询思考题Modbus TCP和RTU有什么区别如何设计高效的Modbus轮询策略如何处理Modbus通信异常参考资料DolphinDB Modbus插件Modbus协议规范