我有一个通过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;
将端口添加到读者可以访问的列表中 portList.Add(sp); UPH打开();
读取硬件:
//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屏蔽和高质量。 长距离非屏蔽电缆可能会受到感应电压波动的影响,这些波动可能会损坏不适合处理长电缆的设备。
即使使用良好的电缆,您仍然会有相当大的压降和电感/电容效应,这可能会阻止以更高的波特率进行通信。 以您可以逃脱的最低波特率运行。
假设这不是硬件/长电缆问题,您可以在代码中执行一些操作来处理错误:
您需要创建一个"正确"的错误处理程序,就像创建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();
的方法可能看起来与您最初启动的方式相似,但存在细微差异,例如:
- 您不再需要在
List<SerialPort>
中添加它 - 您不必在方法中声明
SerialPort
,而是从输入参数中获取它。 - 最好引入一些输入检查有效性,以避免以后的已知错误
- 也许您可以关闭以前的连接,只是为了确保新
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中,或由于长时间导致的电压下降 电缆或不兼容的硬件:简而言之,与 编码),那么,不幸的是,解决方案不能来自代码 也。你必须找到真正的硬件问题。
请注意,RS232 和 RS485 之间的区别在于 RS232 是全双工,而 RS485 只是半双工。由于 modbus 是一种请求响应类型的协议,这不是您的问题,但了解这一点很重要。
因此,RS232<->RS485必须知道何时打开RS485发射器。这可以在不同的转换器上以不同的方式完成,也可以进行配置。这可以通过RS232具有但RS485缺少的附加控制线来完成。即时战略/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。
假设这是一个硬件问题(我想是,我也必须解决类似的问题),我建议用串行设备旁边的设备服务器(通过以太网)替换数百米长的串行电缆。设备服务器可以模拟 PC 上的 COM 端口,因此保持串行电缆短。
不幸的是,这些服务器比几米长的电缆贵一点。
正如我在问题中提到的,我能够使用其他软件读取硬件,因此它必须是软件错误。在调查了我可以在串行端口设置下操作的所有可能变量之后,我想出了转动握手并让它始终被接受的想法。
稍微挖掘一下,给我以下代码,增加写入和读取超时。它解决了我的问题:
sp.ReadTimeout = 60000;
sp.WriteTimeout = 60000;
sp.DtrEnable = true;
sp.RtsEnable = true;
sp.Handshake = Handshake.None;
希望以后能对别人有所帮助,也感谢大家的帮助和努力。