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

时间:2015-02-09 14:26:07

标签: c# serial-port

我正在使用Excel运行C#中的应用程序,最终游戏是允许用户单击Excel工作表上的按钮,然后在串行端口发送一些命令,然后读取数据。

这样做完成并且运行正常。

我的问题是,我如何检查以确保在应用程序关闭之前没有在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

所以基本上,你通过串口发送命令,然后得到一个输出。如果你试图在这个过程中退出,那么它会给出一个例外(我知道会发生这种情况,我宁愿把代码放进去阻止它发生而不是把它放在一个试块中

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

这使得程序在尝试关闭串口上的连接时挂起...如果我删除了wrench.close - 那么上面的异常显示(正如我所料)。

- 编辑 -

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

2 个答案:

答案 0 :(得分:4)

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

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

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

答案 1 :(得分:2)

我认为您的错误来自于您仍在等待来自serial.ReadLine()的更多数据。这个serial.ReadLine()的问题在于它的阻塞特性。如果你打算使用serial.Close()或serial.Dispose(),而serial.ReadLine()仍处于未决状态,那么你最终会遇到你所指出的情况。

所有丢失的回车似乎都发生了,因为你有“未找到运输,数据丢失 - 再试一次”的情况。

你最好做一个没有阻塞的serial.Read(x-characters),让你控制何时停止阅读,以便你可以干净地关闭。