C# 在程序关闭时处理串口

C# Handling a Serial Port when program is closing

我正在用 C# 构建一个 运行 与 Excel 的应用程序,最终目的是允许用户单击 excel sheet 上的按钮,然后向串行端口发送一些命令,然后读回数据。

这已经完成并且工作正常。

我的问题是,我如何检查以确保在应用程序关闭之前 serialport_DataReceived; 事件上没有任何事件/函数被 运行异常崩溃 -

The I/O operation has been aborted because of either a thread exit or an application request.

所以,在某种程度上我需要 运行 某种清理说明串行端口仍在收集数据,等到完成后再关闭。

到目前为止,这是我的代码;

     while (!dataCollected)
     {
        if (data.Contains(carrier)) // If the read data doesn't contain end carriage return, then retry until it does
        {
             if (data.Contains(resultMessage)) // Check to make sure it has the result message - this guarantees a fully built read data with no missing bytes 
             {
                 ParseIncomingDataToExcel(data); // put the string into a specfic excel row
                 dataCollected = true; // exits out of the while loop
             }
        }
        else // Carriage not found, data loss - try again
        {
            data = wrench.ReadLine();
        }
}


if (dataCollected)
    SetControlPropertyValue(button, "Enabled", true); // Invoke to turn the button enabled to true

基本上,您通过串口发送命令,然后获得输出。如果您在此过程中尝试退出,那么它将给出一个异常(我知道这会发生,我宁愿将代码放入以阻止它发生而不是将它放在一个 try 块中

private void Sheet1_Shutdown(object sender, System.EventArgs e)
{
     dataCollected = true;
     wrench.Close();
}

这会使程序在尝试关闭串行端口上的连接时挂起...如果我删除 wrench.close - 则会显示上述异常(如我所料)。

--编辑--

我已经尝试在我的 while 循环中将我的布尔值声明为全局 volatile 类型,但我对使用这样的东西感觉很糟糕,看起来像是 hack(但仍然不起作用,只是挂起...)

我认为您的错误是因为您仍在等待来自 serial.ReadLine() 的更多数据。 serial.ReadLine() 的问题在于它的阻塞性。如果您打算 serial.Close() 或 serial.Dispose() 而 serial.ReadLine() 仍在等待中,您最终会遇到您指定的情况。

毕竟丢失马车 return 似乎是因为你有这个 "Carriage not found, data loss - try again" 案例。

你最好做一个不阻塞的serial.Read(x-characters),让你控制何时停止阅读,这样你就可以干净利落地关闭。

两个问题。第一个是您的 SetControlPropertyValue() 方法。这是一个隐藏 Control.Invoke() 调用的邪恶方法。这非常可能导致死锁。在所有事件处理程序停止 运行 之前,SerialPort.Close() 方法无法关闭端口。但是 Invoke() 调用无法完成,直到 UI 线程进入空闲状态。它不是空闲的,它正忙于尝试关闭端口。无法完成事件处理程序,无法关闭端口,死锁城市。您必须改用 BeginInvoke()。

第二个问题是你在串口忙于接收数据的时候猛拉地垫。 .NET 在此通知您,ReadLine() 调用无法正常完成。它当然是通过抛出异常来实现的。你肯定会因为随意地阅读数据而失去优雅的点数。一个实现良好的串行端口协议要求设备发送数据,设备以单个数据项响应。听起来您的设备只是不断地发出数据。如果您无法很好地控制它,比如关闭 RtsEnable 握手信号,那么异常可能是您最不反对的解决方案。

请注意一个错误,// data loss - try again 评论看起来很不健康。您通过清除您使用的任何响应缓冲区来重试,DataReceived 事件将在没有您帮助的情况下再次触发。使用 ReadLine() 通常是让 SerialPort 处理从设备获取完整响应的简单方法,但如果您不能确定它总是完成,那么您确实需要设置 ReadTimeout 属性。不要将它设置得太低,10 秒是一个安全的赌注。如何处理 TimeoutException 取决于您。