using Modbus; using Modbus.Device; using Modbus.IO; using MV485.model; using System; using System.Collections.Generic; using System.IO.Ports; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MV485.helper { //读取设备的基本参数 public class RWBasicConfig { private SerialPort _serialPort; private ModbusSerialMaster _modbusMaster; private ModbusSerialTransport _modbusTransport; private byte[] sentData; //发送到设备的数据 private byte[] recvData; //从设备接收的数据 //private bool _isRead = false; //已经读取的标志 //public bool IsRead { get; set; } private string _portName; private int _readBaudrate; //读时使用的波特率额 private int _readDevId; //读时使用的地址 private string _message; //public event Action SearchFinished; public event Action RWLog; public event Action SerialConnected; //串口是否已连接 public event Action SerialStatusChanged; //串口连接状态变化 public RWBasicConfig() { //IsRead = false; } public BasicConfig ReadBasicConfig(string portName,int baudrate,byte devId) { //IsRead = false; BasicConfig config = null; _portName = portName; _readBaudrate = baudrate; _readDevId = devId; if (OpenSerial(portName, baudrate)) { config = GetBasicConfig(devId); } CloseSerial(); //IsRead = true; return config; } public bool WriteBasicConfig(BasicConfig readConfig, BasicConfig writeConfig) { //设置波特率 try { if (OpenSerial(_portName, _readBaudrate)) //if(OpenSerial("COM1",14400)) { //地址要最后设置 bool blSetDeviceAddress = true; if (readConfig.DeviceAddress != writeConfig.DeviceAddress) { blSetDeviceAddress = SetDeviveAddress(readConfig.DeviceAddress, writeConfig.DeviceAddress); } //波特率要最后设置,因为改变波特率设备要重启 bool blSetBaudRate = true; if (readConfig.BaudRate != writeConfig.BaudRate) { blSetBaudRate = SetBaudRate(readConfig.DeviceAddress, writeConfig.BaudRate); } //IsRead = false; return blSetBaudRate && blSetDeviceAddress; } } catch { } finally { CloseSerial(); } return false; } //获取485参数 private BasicConfig GetBasicConfig(byte devId) { BasicConfig config = null; try { string deviceType = GetDeviceType(devId); string deviceSn = GetDeviceSn(devId); string fireware = GetFireware(devId); byte devAddress = GetDeiveAddress(devId); //bool blBaudRate = GetBaudrate(devId, out int baudrate, out string parityName, out string stopbitsName); bool blBaudRate = GetBaudrate(devId, out int baudrate); bool blParity = GetPartyName(devId, out string parityName); bool blStopbits = GetStopbitsName(devId, out string stopbitsName); if (!string.IsNullOrEmpty(deviceType) && !string.IsNullOrEmpty(deviceSn) && !string.IsNullOrEmpty(fireware) && blBaudRate && blParity && blStopbits) { config = new BasicConfig() { DeviceType = deviceType, DeviceSn = deviceSn, FireWare = fireware, DeviceAddress = devAddress, BaudRate = baudrate, ParityName = parityName, StopbitsName = stopbitsName }; } else { _message = "读取基本参数失败"; RWLog?.Invoke(_message); } } catch{} return config; } private string GetDeviceType(byte devId) { string devType = ""; try { //D2为模块名称 ushort[] modelNameRegisters = _modbusMaster.ReadHoldingRegisters(devId, 0xD2, 1); //printModbusSRData("模块名称"); sentData = _modbusTransport.GetLastSentData(); recvData = _modbusTransport.GetLastReceivedData(); string sendDataHex = BitConverter.ToString(sentData).Replace("-", " "); string recvDataHex = BitConverter.ToString(recvData).Replace("-", " "); string srMsg = $"发送: {sendDataHex},接收: {recvDataHex}"; ushort modelName = modelNameRegisters[0]; //一个寄存器的内容 devType = "0x" + modelName.ToString("X4"); _message = $"获取设备类型: {modelName}({devType}),{srMsg}"; RWLog?.Invoke(_message); } catch (Exception ex) { sentData = _modbusTransport.GetLastSentData(); string sendDataHex = BitConverter.ToString(sentData).Replace("-", " "); string srMsg = $"发送: {sendDataHex}"; _message = $"获取设备类型出错,{srMsg},{ex.Message}"; RWLog?.Invoke(_message); } return devType; } private string GetDeviceSn(byte devId) { string deviceSn = ""; try { //E5~E7读取SN ushort[] snRegisters = _modbusMaster.ReadHoldingRegisters(devId, 0xE5, 3); // 读取 3 个寄存器 // 解析 BCD 码 deviceSn = Tools.SNBcdToString(snRegisters); //Console.WriteLine("设备序列号: " + deviceSn); sentData = _modbusTransport.GetLastSentData(); recvData = _modbusTransport.GetLastReceivedData(); string sendDataHex = BitConverter.ToString(sentData).Replace("-", " "); string recvDataHex = BitConverter.ToString(recvData).Replace("-", " "); string srMsg = $"发送: {sendDataHex},接收: {recvDataHex}"; _message = $"获取设备SN: {deviceSn},{srMsg}"; RWLog?.Invoke(_message); } catch (Exception ex) { _message = $"获取设备SN出错,{ex.Message}"; RWLog?.Invoke(_message); } return deviceSn; } //获取固件版本 private string GetFireware(byte devId) { string fireware = ""; try { //D4~D5固件版本号 ushort[] firewareRegisters = _modbusMaster.ReadHoldingRegisters(devId, 0xD4, 2); sentData = _modbusTransport.GetLastSentData(); recvData = _modbusTransport.GetLastReceivedData(); string sendDataHex = BitConverter.ToString(sentData).Replace("-", " "); string recvDataHex = BitConverter.ToString(recvData).Replace("-", " "); string srMsg = $"发送: {sendDataHex},接收: {recvDataHex}"; string mcuVer = $"{(firewareRegisters[0] & 0xFF).ToString("D2")}." + $"{(firewareRegisters[1] >> 8).ToString("D2")}." + $"{(firewareRegisters[1] & 0xFF).ToString("D2")}"; fireware = mcuVer; _message = $"获取固件版本: {mcuVer},{srMsg}"; RWLog?.Invoke(_message); } catch(Exception ex) { _message = $"获取固件版本出错,{ex.Message}"; RWLog?.Invoke(_message); } return fireware; } private byte GetDeiveAddress(byte devId) { byte devAddress = 0; try { //F0模块ID,即站地址 ushort[] slaveAddressRegisters = _modbusMaster.ReadHoldingRegisters(devId, 0xF0, 1); byte slaveAdress = (byte)(slaveAddressRegisters[0] & 0xFF); devAddress = slaveAdress; sentData = _modbusTransport.GetLastSentData(); recvData = _modbusTransport.GetLastReceivedData(); string sendDataHex = BitConverter.ToString(sentData).Replace("-", " "); string recvDataHex = BitConverter.ToString(recvData).Replace("-", " "); string srMsg = $"发送: {sendDataHex},接收: {recvDataHex}"; _message = $"获取485地址: {slaveAdress},{srMsg}"; RWLog?.Invoke(_message); } catch (Exception ex) { _message = $"获取485地址出错,{ex.Message}"; RWLog?.Invoke(_message); } return devAddress; } //不能一起读 public bool GetBaudrate(byte devId,out int baudrate,out string parity,out string stopbits) { bool blResult = false; baudrate = -1; parity = ""; stopbits = ""; try { ushort[] baudRateTypeRegisters = _modbusMaster.ReadHoldingRegisters(devId, 0xF2, 3); sentData = _modbusTransport.GetLastSentData(); recvData = _modbusTransport.GetLastReceivedData(); string sendDataHex = BitConverter.ToString(sentData).Replace("-", " "); string recvDataHex = BitConverter.ToString(recvData).Replace("-", " "); string srMsg = $"发送: {sendDataHex},接收: {recvDataHex}"; byte bauddRateType = (byte)(baudRateTypeRegisters[0] & 0xFF); byte parityCheckType = (byte)(baudRateTypeRegisters[1] & 0xFF); byte stopbitsType = (byte)(baudRateTypeRegisters[2] & 0xFF); baudrate = Tools.GetBaudRate(bauddRateType); parity = Tools.GetParityCheck(parityCheckType); stopbits = Tools.GetStopBits(stopbitsType); _message = $"获取波特率:{bauddRateType}({baudrate},校验和:{parityCheckType}({parity}),停止位:{stopbitsType}({stopbits}),{srMsg}"; RWLog?.Invoke(_message); } catch(SlaveException ex) { } catch (Exception ex) { _message = $"获取波特率、校验位、停止位出错,{ex.Message}"; RWLog?.Invoke(_message); } return blResult; } public bool GetBaudrate(byte devId, out int baudrate) { baudrate = -1; try { ushort[] baudRateTypeRegisters = _modbusMaster.ReadHoldingRegisters(devId, 0xF2, 1); sentData = _modbusTransport.GetLastSentData(); recvData = _modbusTransport.GetLastReceivedData(); string sendDataHex = BitConverter.ToString(sentData).Replace("-", " "); string recvDataHex = BitConverter.ToString(recvData).Replace("-", " "); string srMsg = $"发送: {sendDataHex},接收: {recvDataHex}"; byte bauddRateType = (byte)(baudRateTypeRegisters[0] & 0xFF); baudrate = Tools.GetBaudRate(bauddRateType); _message = $"获取波特率: {bauddRateType}({baudrate}),{srMsg}"; RWLog?.Invoke(_message); return true; } catch (SlaveException ex) { _message = $"获取波特率Modbus错误,{ex.Message}"; RWLog?.Invoke(_message); } catch (TimeoutException ex) { _message = $"获取波特率超时错误,{ex.Message}"; RWLog?.Invoke(_message); } catch (Exception ex) { _message = $"获取波特率出错,{ex.Message}"; RWLog?.Invoke(_message); } return false; } public bool GetPartyName(byte devId, out string partyName) { partyName = ""; try { ushort[] parityCheckTypeRegisters = _modbusMaster.ReadHoldingRegisters(devId, 0xF3, 1); byte parityCheckType = (byte)(parityCheckTypeRegisters[0] & 0xFF); sentData = _modbusTransport.GetLastSentData(); recvData = _modbusTransport.GetLastReceivedData(); string sendDataHex = BitConverter.ToString(sentData).Replace("-", " "); string recvDataHex = BitConverter.ToString(recvData).Replace("-", " "); string srMsg = $"发送: {sendDataHex},接收: {recvDataHex}"; partyName = Tools.GetParityCheck(parityCheckType); _message = $"获取校验和: {parityCheckType}({partyName}),{srMsg}"; RWLog?.Invoke(_message); return true; } catch (SlaveException ex) { _message = $"获取校验和Modbus错误,{ex.Message}"; RWLog?.Invoke(_message); } catch (TimeoutException ex) { _message = $"获取校验和超时错误,{ex.Message}"; RWLog?.Invoke(_message); } catch (Exception ex) { _message = $"获取校验和出错,{ex.Message}"; RWLog?.Invoke(_message); } return false; } public bool GetStopbitsName(byte devId, out string stopbitsName) { stopbitsName = ""; try { //F4(这一位,MCU程序中并未起作用) ushort[] stopbitsTypeRegisters = _modbusMaster.ReadHoldingRegisters(devId, 0xF4, 1); byte stopbitsType = (byte)(stopbitsTypeRegisters[0] & 0xFF); sentData = _modbusTransport.GetLastSentData(); recvData = _modbusTransport.GetLastReceivedData(); string sendDataHex = BitConverter.ToString(sentData).Replace("-", " "); string recvDataHex = BitConverter.ToString(recvData).Replace("-", " "); string srMsg = $"发送: {sendDataHex},接收: {recvDataHex}"; stopbitsName = Tools.GetStopBits(stopbitsType); _message = $"获取停止位: {stopbitsType}({stopbitsName}),{srMsg}"; RWLog?.Invoke(_message); return true; } catch (SlaveException ex) { _message = $"获取停止位Modbus错误,{ex.Message}"; RWLog?.Invoke(_message); } catch (TimeoutException ex) { _message = $"获取停止位超时错误,{ex.Message}"; RWLog?.Invoke(_message); } catch (Exception ex) { _message = $"获取停止位出错,{ex.Message}"; RWLog?.Invoke(_message); } return false; } private bool SetBaudRate(byte devId,int newBaudrate ) { ushort newBaudrateType = Tools.GetBaudRateType(newBaudrate); try { // 发送 Modbus 命令修改地址 _modbusMaster.WriteSingleRegister(devId, 0xF2, newBaudrateType); //await _modbusMaster.WriteSingleRegisterAsync(devId, 0xF2, newBaudrateType); //_modbusMaster.WriteSingleRegister(devId, 0xF0, newDeviceAddress); sentData = _modbusTransport.GetLastSentData(); recvData = _modbusTransport.GetLastReceivedData(); string sendDataHex = BitConverter.ToString(sentData).Replace("-", " "); string recvDataHex = BitConverter.ToString(recvData).Replace("-", " "); string srMsg = $"发送: {sendDataHex},接收: {recvDataHex}"; _message = $"设置波特率: {newBaudrateType}({newBaudrate}),{srMsg}"; RWLog?.Invoke(_message); return true; } catch (SlaveException ex) { _message = $"设置波特率: {newBaudrateType}({newBaudrate})Modbus错误,{ex.Message}"; RWLog?.Invoke(_message); } catch (TimeoutException ex) { sentData = _modbusTransport.GetLastSentData(); string sendDataHex = BitConverter.ToString(sentData).Replace("-", " "); string srMsg = $"发送: {sendDataHex}"; _message = $"设置波特率: {newBaudrateType}({newBaudrate})超时错误,{srMsg}"; RWLog?.Invoke(_message); } catch (Exception ex) { _message = $"设置波特率: {newBaudrateType}({newBaudrate})出错,{ex.Message}"; RWLog?.Invoke(_message); } return false; } private bool SetDeviveAddress(byte devId, byte newDeviceAddress) { try { // 发送 Modbus 命令修改地址 _modbusMaster.WriteSingleRegister(devId, 0xF0, newDeviceAddress); sentData = _modbusTransport.GetLastSentData(); recvData = _modbusTransport.GetLastReceivedData(); string sendDataHex = BitConverter.ToString(sentData).Replace("-", " "); string recvDataHex = BitConverter.ToString(recvData).Replace("-", " "); string srMsg = $"发送: {sendDataHex},接收: {recvDataHex}"; _message = $"设置地址: {newDeviceAddress},{srMsg}"; RWLog?.Invoke(_message); return true; } catch (SlaveException ex) { _message = $"设置地址Modbus错误,{ex.Message}"; RWLog?.Invoke(_message); } catch (TimeoutException ex) { _message = $"设置地址超时错误,{ex.Message}"; RWLog?.Invoke(_message); } catch (Exception ex) { _message = $"设置地址出错,{ex.Message}"; RWLog?.Invoke(_message); } return false; } private bool OpenSerial(string portName, int baudRate) { CloseSerial(); try { //除去波特率外,其它参数默认为不会被修改 SerialPort serialPort = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One); serialPort.ReadTimeout = 100; //读取的超时时间应该短一些 serialPort.WriteTimeout = 100; serialPort.Open(); _serialPort = serialPort; _modbusMaster = ModbusSerialMaster.CreateRtu(_serialPort); _modbusTransport = (ModbusSerialTransport)_modbusMaster.Transport; //_modbusTransport.Retries = 1; //_modbusTransport.WaitToRetryMilliseconds = 1000; //_modbusTransport.RetryOnOldResponseThreshold = 500; _message = $"串口{portName}连接成功"; RWLog?.Invoke(_message); Logger.Info(_message); SerialConnected?.Invoke(true); return true; } catch (Exception ex) { _message = $"串口{portName}连接失败"; RWLog?.Invoke(_message); SerialConnected?.Invoke(false); Logger.Info(_message); Logger.Error(ex.Message); return false; } } private void CloseSerial() { try { if (_serialPort != null) { if (_serialPort.IsOpen) { _serialPort.Close(); _message = $"串口{_portName}已关闭"; SerialStatusChanged?.Invoke(false); //串口关闭 RWLog?.Invoke(_message); Logger.Info(_message); } _serialPort.Dispose(); _serialPort = null; } _modbusTransport?.Dispose(); _modbusTransport = null; } catch (Exception ex) { _message = $"关闭串口{_portName}失败: {ex.Message}"; RWLog?.Invoke(_message); Logger.Error(_message); } } //------------------------------------------------------------------ } }