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



我有一个通过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();的方法可能看起来与您最初启动的方式相似,但存在细微差异,例如

  1. 您不再需要在List<SerialPort>中添加它
  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中,或由于长时间导致的电压下降 电缆或不兼容的硬件:简而言之,与 编码),那么,不幸的是,解决方案不能来自代码 也。你必须找到真正的硬件问题。

请注意,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;

希望以后能对别人有所帮助,也感谢大家的帮助和努力。

相关内容

  • 没有找到相关文章

最新更新