长电缆超时时串行通信超时

我有一个应用程序通过rs232读取不同的硬件。 它已经过测试,并且运行良好。 对于最终的应用,我需要引入一些hunder m长电缆,这意味着我有rs485转换器。

当我运行我的应用程序来读取硬件时,我收到System.IO.Ports.SerialStream.Read的超时错误。 我已将超时增加到20秒,不幸的是它没有解决问题

我尝试了不同的应用程序来读取硬件,即使读取频率为1秒,它们也能正常工作。

通信正在使用modbus协议,我认为这是当前阶段无关紧要,因为我没有到达接收任何东西的阶段。

我的代码看起来像这样:首先是串口打开和初始化:

//get the right modbus data structure element ModBus MB = (ModBus)s[0].sensorData; //set up the serial port regarding the data structure's data SerialPort sp = new SerialPort(); sp.PortName = MB.portName; sp.BaudRate = Convert.ToInt32(MB.baudRate); sp.DataBits = MB.dataBits; sp.Parity = MB.parity; sp.StopBits = MB.stopBits; //Set time outs 20 sec for now sp.ReadTimeout = 20000; sp.WriteTimeout = 20000; 

//将端口添加到List,读者可以访问portList.Add(sp); sp.Open();

读硬件:

 //get the right port for com SerialPort sp = getRightPort(); ModBus MB = getRightModBusStructureelement(); try { //Clear in/out buffers: sp.DiscardOutBuffer(); sp.DiscardInBuffer(); //create modbus read message byte[] message = createReadModBusMessage(); try { sp.Write(message, 0, message.Length); // FM.writeErrorLog output included for easier debug FM.writeErrorLog(DateTime.Now + ": ModBus Message Sent"); FM.writeErrorLog(DateTime.Now + ": Read TimeOut = " + sp.ReadTimeout + " Write TimeOut = " + sp.WriteTimeout); int offset = 0, bytesRead; int bytesExpected = response.Length; FM.writeErrorLog(DateTime.Now + ": start read"); while (bytesExpected > 0 && (bytesRead = sp.Read(response, offset, bytesExpected)) > 0) { FM.writeErrorLog(DateTime.Now + ": read - " + offset); offset += bytesRead; bytesExpected -= bytesRead; } } catch (Exception err) { Console.WriteLine("ERROR Modbus Message to serial port ModBus: " + err); FM.writeErrorLog(DateTime.Now + " - " + "ERROR Modbus Message to serial port ModBus: " + err); } } 

在尝试应用程序后,我从ErroLog.txt获得以下输出:

 14/01/2016 17:18:17: ModBus Message Sent 14/01/2016 17:18:17: Read TimeOut = 20000 Write TimeOut = 20000 14/01/2016 17:18:18: start read 14/01/2016 17:18:38 - ERROR Modbus Message to serial port ModBus: System.TimeoutException: The operation has timed out. at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count, Int32 timeout) at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count) at System.IO.Ports.SerialPort.Read(Byte[] buffer, Int32 offset, Int32 count) at ProbReader.SensorReader.modbusReading(List`1 mm, Int32 spCounter) 14/01/2016 17:18:38: 0 14/01/2016 17:18:38: 0 

我已将超时增加到60秒以防万一,但同样的错误:

 15/01/2016 11:11:51: ModBus Message Sent 15/01/2016 11:11:51: Read TimeOut = 60000 Write TimeOut = 60000 15/01/2016 11:11:51: start read 15/01/2016 11:12:51 - ERROR Modbus Message to serial port ModBus: System.TimeoutException: The operation has timed out. at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count, Int32 timeout) at System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count) at System.IO.Ports.SerialPort.Read(Byte[] buffer, Int32 offset, Int32 count) at ProbReader.SensorReader.modbusReading(List`1 mm, Int32 spCounter) 15/01/2016 11:12:51: 0 15/01/2016 11:12:51: 0 

我已经尝试了几种不同的方法来读取串口,我认为当前的方法看起来最好,这是我的阅读代码中的while循环。

我没有包含其余的代码,因为它超时之前,我认为它是无关紧要的。

如果您使用数百米的串行电缆(这本身就是一个硬件工程问题),那么我强烈建议在电缆的两端安装一个合适的收发器。 电缆本身应采用EMC屏蔽且质量上乘。 长距离的非屏蔽电缆可能是感应电压波动的受害者,可能会损坏设计不能处理长电缆的设备。

即使使用良好的电缆,您仍然会有相当大的电压降和电感/电容效应,这可能会阻止更高波特率的通信。 以最低的波特率运行,您可以逃脱。

假设这是一个硬件问题(我想它也是,我不得不解决类似的问题),我建议用串行设备旁边的设备服务器(通过以太网)替换数百米的串行电缆。 设备服务器可以模拟PC上的COM端口,从而使串行电缆短路。

不幸的是,这些服务器比几米的电缆贵一点。

请注意,RS232和RS485之间的区别在于RS232是全双工而RS485只是半双工。 由于modbus是请求响应类型协议,因此这不是您的问题,但重要的是要知道。

因此,RS232 < - > RS485必须知道何时打开它的RS485发射器。 这可以在不同的转换器上以不同方式完成,也可以是可配置的。 这可以通过RS232具有但RS485缺少的附加控制线来完成。 RTS / CTS。 如果配置错误,响应方(等待请求响应)发送器可能会打开,然后它就无法接收任何内容。

手册中的一个示例是http://ftc.beijer.se/files/C125728B003AF839/992C59EC02C66E00C12579C60051484E/westermo_ug_6617-2203_mdw-45.pdf这是瑞典的一种流行模型,它有三种操作模式。 它可以通过输入数据打开/关闭变送器,由DB9-RS232连接器上的RTS引脚控制,或者始终打开变送器(对于每个方向都有单独电线的RS422) http://screencast.com/t / KrkEw13J8

这很难,因为一些制造商没有打印出它的实际工作方式。 由于不清楚什么是DCE和DTE,因此错误地接线也很容易。

假设这不是硬件/长电缆问题,您可以在代码中执行一些操作来处理错误:

您需要创建一个“正确”的error handling程序,就像创建getRightPort

 SerialPort sp = getRightPort(); 

假设内部有一个串口项目Collection并且您返回正确的序列项目,如果此SerialPort出现错误,请确保使用相同的设置重新创建错误SerialPort object

 catch (Exception err) { Console.WriteLine("ERROR Modbus Message to serial port ModBus: " + err); FM.writeErrorLog(DateTime.Now + " - " + "ERROR Modbus Message to serial port ModBus: " + err); reinitRightPort(sp); //add this } 

方法reinitRightPort(); 可能看起来与你第一次发起的方式相似, 只有很小的差异

  1. 您不需要再在List添加它
  2. 你不要在方法中声明SerialPort ,你可以从输入参数中获取它。
  3. 最好引入一些输入检查有效性以避免以后发现的错误
  4. 也许你可以关闭以前的连接,只是为了确保新的SerialPort object可以使用该端口。

像这样的东西:

 private void reinitRightPort(SerialPort sp){ //get SerialPort from outside of method //Add whatever necessary here, to close all the current connections //Plus all the error handlings if (sp == null) //Read 3. return; sp.Close(); //Read 4. close the current connections //get the right modbus data structure element ModBus MB = (ModBus)s[0].sensorData; //set up the serial port regarding the data structure's data sp = new SerialPort(); //Read 2. sp is from outside the method, but use new keyword still sp.PortName = MB.portName; sp.BaudRate = Convert.ToInt32(MB.baudRate); sp.DataBits = MB.dataBits; sp.Parity = MB.parity; sp.StopBits = MB.stopBits; //Set time outs 20 sec for now sp.ReadTimeout = 20000; sp.WriteTimeout = 20000; //portList.Add(sp); Read 1. no need to add this! It is already there! sp.Open(); } 

注意:执行此操作并确保端口运行良好后,只要有可能,您还可以将上面的reinitRightPort方法与实际初始化相结合,并进行一些修改。 但您可能想要做的第一件事是让您的串口工作失误。

但是,如果错误源来自硬件/长电缆问题(例如电缆放置在RS232或RS485中,或由于长电缆或不兼容的硬件导致电压下降:简而言之,完全与编码无关),然后,不幸的是,解决方案也不能来自代码。 你必须找到真正的硬件问题。

正如我在我的问题中提到的,我能够用其他软件读取硬件,因此它需要是一个软件错误。 在调查了我可以在串口设置中操作的所有可能变量后,我想出了转动握手并让它始终被接受的想法。

稍微挖掘一下就可以通过增加写入和读取时间来提供以下代码。 它解决了我的问题:

  sp.ReadTimeout = 60000; sp.WriteTimeout = 60000; sp.DtrEnable = true; sp.RtsEnable = true; sp.Handshake = Handshake.None; 

我希望将来能帮助其他人,并感谢大家的帮助和努力。