请原谅我,因为这将是一个相当长的帖子。我目前正在使用 C# 中的 SerialPort 类来编写一个应用程序来与一个名为 Fluke 5500A 的设备进行通信。过去,我遇到过很多问题,因为设备发出命令并返回其输出的任何内容所花费的时间充其量是不可预测的。我昨天在这里问了一个问题:System.Timers.Timer Usage这个问题的答案很精彩,而且大部分时间看起来都很完美。例如,我用来连接到 SerialPort 的类现在看起来像这样:
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;
        }
    }
}
如您所见,当我打开一个连接时,在这种情况下,我通过向 SerialPortCom1写入命令来测试连接。*IDN?此命令的返回如下所示:
FLUKE,5500A,8030005,2.61+1.3+2.0+*
66>
在我设置">"为 NewLine 属性的类中,以便 SerialPort.ReadLine() 在找到该令牌之前不会完成。我从来没有让类本身抛出异常,但我注意到在调试时有时testReceived无法正确捕获返回的数据,尽管没有抛出异常并且代码继续正确执行,而是received会捕获返回字符串:
FLUKE,5500A,8030005,2.61+1.3+2.0+*
66>
每当我通过SerialPort.Write();重要的事情传递我的第一个命令时,可以在不完全返回该数据的情况下执行命令。我担心的是,最初的ReadLine()似乎偶尔会跳过,而没有抓住整个回报。我的想法是我正在与之通信的设备存在固有缺陷,但我更愿意在继续之前完全确定。
我的命令顺序如下所示:
首先我在启动时提交一个命令:
REMOTE
这会禁用与设备手动界面的交互,并允许我通过串行端口提交命令。
然后我发出*IDN?,在这种情况下,检查设备是否已连接:
*IDN?
如果没有返回任何内容,则应用程序设置为在消息框中显示错误,然后FailFast. 如果一切顺利,可以像这样提交命令:
STBY
OUT 30MV,60HZ
OPER
此处手动提交的唯一命令是OUT 30,MV,60HZ. STBY并OPER在 app.config 中设置,因为它们只会在应用程序的使用中添加不必要的步骤。出于安全原因,该STBY命令使机器处于待机状态。该OPER命令将其置于操作模式,并且设备开始在设置的参数下运行。
然后应用程序等待技术人员将结果输入文本框并提交。这些结果的内容并不是特别相关,但在点击结果按钮时,机器会重新进入待机状态:
STBY
最后,当应用程序关闭时,又提交了两条命令:
*RST
LOCAL
首先*RST对机器进行复位,以确保它处于与上电时相同的状态(IE没有运行,也没有设置任何参数)。然后LOCAL设置重新启用用户交互的手动界面并禁用通过串行端口的访问,直到REMOTE再次发出。
如您所见,在*IDN?发送的第一个手动命令之后和之前发出命令(在这种情况下,我们假设命令是OUT 30MV,60HZ)。问题是,有时*IDN当我检查输出OUT 30MV,60HZ是什么时,我会收到输出,但在我的代码或我用来操作机器的过程中看不到任何问题。有什么理由会发生这种情况吗?
正如我所说,该错误极难重现(我在大约 40 次运行中见过两次)。即便如此,这种类型的任何错误在生产环境中都是不可接受的,并且需要先修复错误,然后我才能开始完整地测试我的应用程序。我将继续尝试重现该错误,以便我可以提供一个示例,并希望进一步说明问题可能是什么。
编辑:
我还想澄清一下,我相当确定该错误不在我的应用程序本身的某个位置,因为代码本质上有些简单:
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 "";
    }
然后像这样操作收到的:
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;
    }
如果需要,我可以提供更多代码,但我目前看不到任何其他可能与手头问题相关的代码。