Modbus協議在應用中一般用來與PLC或者其他硬件設備通訊,Modbus集成到IoTBrowser使用串口插件模式開發,不同的是採用命令函數,具體可以參考前面幾篇文章。目前示例實現了Modbus-Rtu和Modbus-Tcp兩種,通過js可以與Modbus進行通訊控制。
一、開發插件
- 添加引用
- 添加NModbus4,在NuGet搜索NModbus4
- 添加Core,路徑:\IoTBrowser\src\app_x64\Core.dll
- 添加Infrastructure,路徑:\IoTBrowser\src\app_x64\Infrastructure.dll
- 添加Newtonsoft,路徑:\IoTBrowser\src\app_x64\Newtonsoft.Json.dll
- 開發ModbusRtu和ModbusTcp插件
- ModbusRtu
- 添加引用
public class ModbusRtuCom : ComBase { public override string Type => "modbusRtuCom"; public override string Name => "ModbusRtuCom"; private object _locker = new object(); public override bool Init(int port, int baudRate = 9600, string extendData = null) { this.Port = port; var portName = "COM" + port; base.PortName = portName; ModbusRtuService.Init(portName, baudRate); Console.WriteLine("初始化ModbusRtuCom驅動程序成功!"); return true; } public override event PushData OnPushData; public override bool Open() { var b = false; try { ModbusRtuService.Open(); b = true; IsOpen = true; } catch (Exception ex) { string msg = string.Format("ModbusRtuCom串口打開失敗:{0} ", ex.Message); Console.WriteLine(msg); } return b; } public override bool Close() { ModbusRtuService.Close(); IsOpen = false; OnPushData = null; return true; } public override string Command(string name, string data) { var outData = string.Empty; var dataObj = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(data); switch (name) { case "ReadCoils": //01 var readData = ModbusRtuService.ReadCoils(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), ushort.Parse(dataObj.numberOfPoints.ToString())); outData = ModbusHelper.ToString(readData); break; case "ReadInputs": //02 readData = ModbusRtuService.ReadInputs(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), ushort.Parse(dataObj.numberOfPoints.ToString())); outData = ModbusHelper.ToString(readData); break; case "ReadHoldingRegisters": //03 readData = ModbusRtuService.ReadHoldingRegisters(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), ushort.Parse(dataObj.numberOfPoints.ToString())); outData = ModbusHelper.ToString(readData); break; case "ReadInputRegisters": //04 readData = ModbusRtuService.ReadInputRegisters(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), ushort.Parse(dataObj.numberOfPoints.ToString())); outData = ModbusHelper.ToString(readData); break; case "WriteSingleCoil": //05 ModbusRtuService.WriteSingleCoil(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), ModbusHelper.BoolParse(dataObj.value.ToString())); break; case "WriteSingleRegister": //06 ModbusRtuService.WriteSingleRegister(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), ushort.Parse(dataObj.value.ToString())); break; case "WriteMultipleCoils": //0F 寫一組線圈 var values = dataObj.value.ToString().Split(' '); var datas = new bool[values.Length]; for (var i = 0; i < values.Length; i++) { datas[i] = ModbusHelper.BoolParse(values[i]); } ModbusRtuService.WriteMultipleCoils(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), datas); break; case "WriteMultipleRegisters": // 10 寫一組保持寄存器 values = dataObj.value.ToString().Split(' '); var udatas = new ushort[values.Length]; for (var i = 0; i < values.Length; i++) { udatas[i] = ushort.Parse(values[i]); } ModbusRtuService.WriteMultipleRegisters(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), udatas); break; } return outData; } }
b.ModbusTcp
public class ModbusTcpCom : ComBase { public override string Type => "modbusTcpCom"; public override string Name => "ModbusTcpCom"; private object _locker = new object(); public override bool Init(int port, int baudRate = 9600, string extendData = null) { this.Port = port; ModbusTcpService.Init(extendData, port); Console.WriteLine("初始化ModbusTcpCom驅動程序成功!"); return true; } public override event PushData OnPushData; public override bool Open() { var b = false; try { ModbusTcpService.Open(); b = true; IsOpen = true; } catch (Exception ex) { string msg = string.Format("ModbusTcpCom串口打開失敗:{0} ", ex.Message); Console.WriteLine(msg); } return b; } public override bool Close() { ModbusTcpService.Close(); IsOpen = false; OnPushData = null; return true; } public override string Command(string name, string data) { var outData = string.Empty; var dataObj = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(data); switch (name) { case "ReadCoils": //01 var readData = ModbusTcpService.ReadCoils(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), ushort.Parse(dataObj.numberOfPoints.ToString())); outData = ModbusHelper.ToString(readData); break; case "ReadInputs": //02 readData = ModbusTcpService.ReadInputs(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), ushort.Parse(dataObj.numberOfPoints.ToString())); outData = ModbusHelper.ToString(readData); break; case "ReadHoldingRegisters": //03 readData = ModbusTcpService.ReadHoldingRegisters(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), ushort.Parse(dataObj.numberOfPoints.ToString())); outData = ModbusHelper.ToString(readData); break; case "ReadInputRegisters": //04 readData=ModbusTcpService.ReadInputRegisters(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), ushort.Parse(dataObj.numberOfPoints.ToString())); outData = ModbusHelper.ToString(readData); break; case "WriteSingleCoil": //05 ModbusTcpService.WriteSingleCoil(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), ModbusHelper.BoolParse(dataObj.value.ToString())); break; case "WriteSingleRegister": //06 ModbusTcpService.WriteSingleRegister(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), ushort.Parse(dataObj.value.ToString())); break; case "WriteMultipleCoils": //0F 寫一組線圈 var values = dataObj.value.ToString().Split(' '); var datas =new bool[values.Length]; for(var i=0;i< values.Length;i++) { datas[i] = ModbusHelper.BoolParse(values[i]); } ModbusTcpService.WriteMultipleCoils(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), datas); break; case "WriteMultipleRegisters": // 10 寫一組保持寄存器 values = dataObj.value.ToString().Split(' '); var udatas = new ushort[values.Length]; for (var i = 0; i < values.Length; i++) { udatas[i] = ushort.Parse(values[i]); } ModbusTcpService.WriteMultipleRegisters(byte.Parse(dataObj.slaveAddress.ToString()), ushort.Parse(dataObj.startAddress.ToString()), udatas); break; } return outData; } }
3.功能
- 讀單個線圈
- 讀取輸入線圈/離散量線圈
- 讀取保持寄存器
- 讀取輸入寄存器
- 寫單個線圈
- 寫單個輸入線圈/離散量線圈
- 寫一組線圈
- 寫一組保持寄存器
源代碼位置:\Plugins\DDS.IoT.Modbus
二、本機測試
1.測試前準備
需要安裝虛擬串口和modbusslave,可以在源代碼中下載:
https://gitee.com/yizhuqing/IoTBrowser/tree/master/soft
2.串口測試
3.TCP測試
三、部署到IoTBrowser
1.編譯
(建議生產環境使用Release模式)
2.拷貝到Plugins文件夾
也可以放到com文件夾。
注意:需要拷貝NModbus4.dll到\IoTBrowser\src\app_x64目錄下
四、IoTBrowser集成測試
1.串口測試
寫入多個數據寫入以空格分割,寫入線圈數據支持0/1或false/true。
2.TCP測試
TCP注意ip地址通過擴展數據傳入,端口號就是串口號。