SerialPort DataReceived事件会重复触发吗?

时间:2010-05-16 18:25:06

标签: c# events serial-port buffer

假设每当有100个字节可用时我就从SerialPort读取数据,否则什么都不做。这意味着,剩余的数据仍然可以在SerialPort缓冲区中使用。此读取在DataReceived的事件处理程序内完成。

现在假设出现这样的情况,当存在时,在SerilaPort缓冲区中说50个字节并且不再有数据出现。根据我的理解,只要有一定数量的字节可用于从缓冲区读取,就会触发DataReceived事件。

现在,在给定的场景中,如果我从未读过这50个字节,那么由于这些未读字节的存在,事件是否会被连续激活?

3 个答案:

答案 0 :(得分:3)

是的,它会在其他字节进入时继续触发,直到你调用Read()。您可以使用ReceivedBytesThreshold属性来延迟它。这通常是一个坏主意,由于溢出错误而丢失一个字节可能导致通信完全占用。在你自己的事件处理程序中缓冲你的Read()。

另请注意,这只是Microsoft串行端口驱动程序的已知行为。 SerialPort类使用WaitCommEvent API函数,由驱动程序来实现。特别是过多的USB驱动程序模拟串行端口以便于与自定义设备进行交互,这些驱动程序并不相同。

答案 1 :(得分:3)

我确实发了答案(见上面的评论)。它在文档中。 “......从SerialPort对象接收数据时。” OP说“如果我从未读过那50个字节,那么由于这些未读字节的存在,事件是否会被连续激活?”并且你回答说“是的,它会继续射击,直到你打电话给Read()。”

只有在收到新数据时才会触发事件。如果您不处理该数据,那么该数据不会导致新事件。但是,如果新数据到达,则会触发新事件,然后您可以对其进行处理。

答案 2 :(得分:0)

我认为这证明了我的观点,对VB代码感到抱歉。

Private Sub Button1_Click(ByVal sender As System.Object, _
                          ByVal e As System.EventArgs) _
                          Handles Button1.Click
    'set up the com port for a test
    SerialPort1.PortName = "COM5" 'attached to breakout box with loopback
    SerialPort1.BaudRate = 115200 'some speed
    SerialPort1.Encoding = System.Text.Encoding.GetEncoding("windows-1252")
    Dim b() As Byte = New Byte() {42, 16, 20, 254, 255, 128} 'test data

    ctrcv = 0 'counter
    SerialPort1.Open() 'open the port
    Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss.ffff")) 'show time
    SerialPort1.Write(b, 0, b.Length) 'write the test data

    'give the DataReceived event handler chances to fire
    Threading.Thread.Sleep(30000)

    'show the last time it fired and how many times
    Debug.WriteLine(lastRCV.ToString("HH:mm:ss.ffff") & " " & ctrcv)
    'show how many are available to read
    Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss.ffff") & " " & SerialPort1.BytesToRead)
    Array.Clear(b, 0, b.Length)
    SerialPort1.Read(b, 0, SerialPort1.BytesToRead) 'read them

    SerialPort1.Close() 'close the port
    Stop
End Sub
Dim ctrcv As Integer = 0, lastRCV As DateTime
Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, _
                                     ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _
                                     Handles SerialPort1.DataReceived
    ctrcv += 1
    lastRCV = DateTime.Now
End Sub

调试输出

 09:34:11.3241 <- when the test started
 09:34:11.3642 3 <- the last data received event!, and how many events
 09:34:41.3718 6 <- when the test ended