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地址通过扩展数据传入,端口号就是串口号。