C# 中明显的 IO.Ports.SerialPort 缺陷或可能的硬件缺陷 [英] Apparent IO.Ports.SerialPort Flaw in C# or Possible Hardware Flaw

查看:115
本文介绍了C# 中明显的 IO.Ports.SerialPort 缺陷或可能的硬件缺陷的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请原谅我,这将是一篇很长的文章.我目前正在使用 C# 中的 SerialPort 类编写一个应用程序来与名为 Fluke 5500A 的设备进行通信.过去,我遇到过很多问题,因为设备发出命令并返回其输出的任何内容所花费的时间最多是不可预测的.我昨天在这里问了一个问题:System.Timers.Timer Usage 问题的答案很棒并且大部分时间似乎都能完美运行.例如,我用来连接到 SerialPort 的类现在看起来像这样:

Please forgive me as this is going to be quite a long post. I'm currently using the SerialPort class in C# to write an application to communicate with a device called a Fluke 5500A. I've, in the past, had many problems as the amount of time the device takes to issue a command and return whatever it outputs in unpredictable at best. I asked a question yesterday here: System.Timers.Timer Usage The answer to the question is wonderful and most of the time appears to work perfectly. As an example my the class I use to connect to a SerialPort now looks like this:

public class SerialPortConnection
{
    private SerialPort serialPort;
    private string ping;
    double failOut;
    bool isReceiving;

    public SerialPortConnection(string comPort = "Com1", int baud = 9600, System.IO.Ports.Parity parity = System.IO.Ports.Parity.None, int dataBits = 8, System.IO.Ports.StopBits stopBits = System.IO.Ports.StopBits.One, string ping = "*IDN?", double failOut = 2)
    {
        this.ping = ping;
        this.failOut = failOut * 1000;

        try
        {
            serialPort = new SerialPort(comPort, baud, parity, dataBits, stopBits);
            serialPort.NewLine = ">";
            serialPort.ReadTimeout = 1000;
        }
        catch (Exception e)
        {
            serialPort = null;
        }
    }

    //Open Serial Connection. Returns False If Unable To Open.
    public bool OpenSerialConnection()
    {
        //Opens Initial Connection:
        try
        {
            serialPort.Open();
            serialPort.Write("REMOTE\r");
        }
        catch (Exception e)
        {
            return false;
        }

        serialPort.Write(ping + "\r");
        var testReceived = "";

        try
        {
            testReceived += serialPort.ReadLine();
            return true;
        }
        catch
        {
            return false;
        }
    }

    public string WriteSerialConnection(string SerialCommand)
    {
        serialPort.Write(String.Format(SerialCommand + "\r"));
        var received = "";

        try
        {
            received += serialPort.ReadLine();
            return received;
        }
        catch
        {
            received = "Error: No Data Received From Device";
            return received;
        }
    }

    public bool CloseSerialConnection()
    {
        try
        {
            serialPort.Write("LOCAL\r");
            serialPort.Close();
            return true;
        }
        catch (Exception e)
        {
            return false;
        }
    }
}

如您所见,当我打开与 Com1 的连接时,我通过向 SerialPort 写入命令 *IDN? 来测试连接.此命令的返回如下所示:

As you can see, when I open the a connection to, in this case, Com1 I test the connection by writing a command *IDN? to the SerialPort. The return for this command looks like so:

FLUKE,5500A,8030005,2.61+1.3+2.0+*
66>

在类中,我将 ">" 设置为 NewLine 属性,以便 SerialPort.ReadLine() 在找到该标记之前不会完成.我从来没有让类本身抛出异常,但我在调试时注意到有时 testReceived 不会正确捕获返回的数据,尽管没有抛出异常并且代码继续正确执行,而是 received 将捕获返回的字符串:

In the class I've set ">" as the NewLine property so that SerialPort.ReadLine() doesn't finish till it finds that token. I've never once had the class itself throw an exception but I've noticed while debugging that sometimes testReceived won't catch that returned data properly, despite the fact that no exceptions are thrown and the code continues executing properly, and instead received will catch the returned string:

FLUKE,5500A,8030005,2.61+1.3+2.0+*
66>

每当我通过 SerialPort.Write(); 传递我的第一个命令时,重要的是要知道命令可以在不完全返回数据的情况下执行.我担心的是最初的 ReadLine() 似乎偶尔会跳过它而没有捕获整个返回.我的想法是我正在与之通信的设备存在固有缺陷导致这种情况,但我希望在继续之前完全确定.

whenever I pass my first command via SerialPort.Write(); Something important to know is that commands can be executed without that data being fully returned. My concern is that the initial ReadLine() appears to be skipping past that occasionally without catching the entire return. My thought is that there's an inherent flaw in the device I'm communicating with causing this but I'd prefer to be entirely sure before continuing.

我的命令顺序如下:

首先我在启动时提交一个命令:

First I submit a command on startup:

REMOTE

这会禁用与设备手动界面的交互,并允许我通过串行端口提交命令.

This disables interaction with the device's manual interface and allows me to submit commands via the Serial Port.

然后我发出 *IDN?,在这种情况下,检查设备是否已连接:

Then I issue *IDN?, in this case, to check that the device is connected:

*IDN?

如果没有任何返回,应用程序设置为在消息框中显示错误,然后FailFast.如果一切顺利,可以像这样提交命令:

If nothing is return, the application is set to display an error in a message box and then FailFast. If all goes well a command can be submitted like so:

STBY
OUT 30MV,60HZ
OPER

这里手动提交的唯一命令是OUT 30,MV,60HZ.STBYOPER 在 app.config 中设置,因为它们只是为应用程序的使用添加了一个不必要的步骤.出于安全原因,STBY 命令将机器置于待机状态.OPER 命令将其置于运行模式,设备开始在设置的参数下运行.

The only command submitted here manually is OUT 30,MV,60HZ. STBY and OPER are set in the app.config as they only add an unnecessary step to the usage of the application. The STBY command puts the machine in standby for safety reasons. The OPER command puts it in operating mode and the device begins operating under the set parameters.

然后应用程序等待技术人员将结果输入到文本框中并提交.这些结果的内容并不是特别相关,但在点击结果按钮后,机器会重新进入待机状态:

The application then waits for a technician to enter a result into a textbox and submit it. The content of these results aren't particularly pertinent but upon hitting the result button the machine is put back in standby:

STBY

最后,应用关闭时再提交两条命令:

Finally, two more commands are submitted when the application is closed:

*RST
LOCAL

首先 *RST 重置机器以确保它处于与开机时相同的状态(即它不运行且未设置任何参数).然后 LOCAL 设置重新启用用户交互的手动界面并禁用通过串行端口的访问,直到再次发出 REMOTE.

First *RST resets the machine to ensure that it's in the same state as when it was powered on (I.E. It's not operating and no parameters are set). Then LOCAL sets the re-enables the manual interface for user interaction and disables access via the Serial Port till REMOTE is issued once more.

如您所见,在 *IDN? 之后和发送的第一个手动命令之前发出命令(在这种情况下,我们假设命令是 OUT 30MV,60HZ>).问题是,有时每当我检查 OUT 30MV,60HZ 的输出时,我都会收到 *IDN 的输出,但我在我的代码或程序中看不到任何问题我是用来操作机器的.是否有任何原因可能会发生这种情况?

As you can see, a command is issued after *IDN? and before the first manual command that's sent (In this case we assume the command is OUT 30MV,60HZ). The problem is, sometimes I receive the output of *IDN whenever I check what the output of OUT 30MV,60HZ is yet I can see no problems within my code or the procedure I'm using to operate the machine. Is there any reason this could be happening?

正如我所说,该错误极难重现(我已经在大约 40 次运行中看到了两次).即便如此,任何此类错误在生产环境中都是不可接受的,需要先修复错误,然后才能开始完整地测试我的应用程序.我会继续尝试重现该错误,以便我可以提供一个示例,并希望进一步说明问题可能出在哪里.

As I've said, the error is extremely hard to reproduce (I've seen it twice in maybe forty runs). Even so, any error at all of this type is not acceptable in a production environment and the error needs to be fixed before I can begin testing my application in its entirety. I'll keep trying to reproduce the error so I can provide an example and hopefully provide further clarification as to what the problem might be.

我还想澄清一下,我相当确定该错误不在我的应用程序本身的某个地方,因为代码本质上有些简单:

I'd also like to clarify that I'm fairly certain the bug is not located somewhere within my application itself as the code is somewhat simplistic in nature:

public string SubmitCommand()
    {
        if (_command_Input != "No further commands to input.")
        {
            string received;
            serialPort.WriteSerialConnection("STBY");
            received = serialPort.WriteSerialConnection(_command_Input);
            serialPort.WriteSerialConnection("OPER");

            //Controls Enabled:
            _input_IsEnabled = false;
            _user_Input_IsEnabled = true;
            _results_Input_IsEnabled = false;
            RaisePropertyChanged("Input_IsEnabled");
            RaisePropertyChanged("User_Input_IsEnabled");
            RaisePropertyChanged("Results_Input_IsEnabled");

            return received;
        }
        else
            return "";
    }

然后像这样操作接收到:

received is then manipulated like so:

public bool SetOutput()
    {
        string inter1 = SubmitCommand();

        try
        {

            string[] lines = inter1.Split(Environment.NewLine.ToCharArray()).ToArray();
            _results_Changed = lines[2];
            RaisePropertyChanged("Results_Changed");
        }
        catch
        {
            _results_Changed = inter1;
            RaisePropertyChanged("Results_Changed");
        }
        return true;
    }

如果需要,我可以提供更多代码,但我目前看不到任何其他可能与手头问题相关的代码.

I can provide further code if need be but I can't currently see any other code that might be pertinent to the question at hand.

推荐答案

你让这个问题难以诊断,你不喜欢的回应看起来完全就像你喜欢的.

You made this hard to diagnose, the response you don't like looks exactly like the one you do like.

一般来说,您需要确保您的程序与设备同步.一种可能的故障模式是驱动程序在接收缓冲区中仍然有来自先前连接的未读数据.陈旧数据也可能存在于设备的传输缓冲区中.当您开始备份时,您将读取过时的数据并假设它是对您的命令的响应.不是.您现在将永远不同步,总是读取作为对上一个命令的响应的陈旧数据.

In general, you need to ensure that your program is in sync with the device. A possible failure mode is when the driver still has unread data in the receive buffer from a previous connection. Stale data could also exist in the device's transmit buffer. When you start back up, you'll read that stale data and assume it was a response to your command. It wasn't. You'll now be permanently out of sync, always reading stale data that was the response to the previous command.

这也很奇怪,无需注意握手,设备通常注意这一点.

It is also rather odd that this works without taking care of handshaking, device normally do pay attention to that.

为避免意外,请像这样初始化您的程序:

To avoid accidents, initialize your program like this:

  • 调用 Open() 方法打开端口
  • 将 RtsEnable 和 DtrEnable 属性设置为 true,以便设备始终看到允许其传输数据的良好信号
  • 休眠大约 100 毫秒以允许设备发送它仍然从前一个连接缓冲但由于握手关闭而无法发送的任何数据
  • 调用 DiscardInBuffer() 以丢弃任何过时的响应字节.

您现在有一个合理的保证,您将保持同步.

You have now a reasonable guarantee you'll be in sync.

这篇关于C# 中明显的 IO.Ports.SerialPort 缺陷或可能的硬件缺陷的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆