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

时间:2016-01-15 12:05:12

标签: c# serial-port timeout

我有一个通过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循环。

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

5 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分:4)

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

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

答案 2 :(得分:3)

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

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

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

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

答案 3 :(得分:2)

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

您需要创建一个“正确”的错误处理程序,就像创建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可以使用该端口。
  5. 这样的事情:

    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中,或由于长电压下降   电缆或不兼容的硬件:简而言之,与此无关   然后,不幸的是,解决方案不能来自代码   同样。你必须找到真正的硬件问题。

答案 4 :(得分:1)

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

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

                            sp.ReadTimeout = 60000;
                            sp.WriteTimeout = 60000;

                            sp.DtrEnable = true;
                            sp.RtsEnable = true;
                            sp.Handshake = Handshake.None;

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