由于串口通信是异步的,我在项目的早期就意识到,涉及到与RS 232设备的通信,我必须有一个后台线程不断地读取接收到的数据的端口。现在,我使用的是IronPython (.NET 4.0),因此我可以访问内置于.NET中的光滑的SerialPort类。
self.port = System.IO.Ports.SerialPort('COM1', 9600, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One)
self.port.Open()
reading = self.port.ReadExisting() #grabs all bytes currently sitting in the input buffer很简单。但是,正如我所提到的,我想在新数据到达时不断检查这个端口。理想情况下,无论何时有数据等待,我都会让操作系统告诉我。谁知道,我的祈祷已经得到了回应,有一个DataReceived事件提供!
self.port.DataReceived += self.OnDataReceived
def OnDataReceived(self, sender, event):
reading = self.port.ReadExisting()
...可惜这是一文不值的,因为不一定会引发此事件!
对于接收到的每个字节,都不能保证引发DataReceived事件。
那么,回到编写侦听器线程。我用一个只会一次又一次地调用BackgroundWorker的port.ReadExisting()来完成这个任务。当它看到一行结束(\r\n)时,它会将读取的内容放置到linebuffer中。然后,我的程序的其他部分查看linebuffer,看看是否有任何完整的行等待使用。
显然,这是一个经典的producer-consumer问题。生产者是BackgroundWorker,将完整的行放入linebuffer中。使用者是一些尽可能快地从linebuffer中消耗这些行的代码。
然而,消费者的效率有点低。现在,他不断地检查linebuffer,每次都感到失望,发现它是空的;尽管偶尔会有一条排队等待在里面。优化这一点的最佳方法是什么,这样消费者只有在有可用行时才会醒来?这样,消费者就不会不断地访问linebuffer,这可能会带来一些并发问题。
此外,如果有一种更简单/更好的方式不断地从串口读取,我是开放的建议!
发布于 2010-11-12 21:45:45
我不明白为什么不能使用DataReceived事件。就像医生说的那样
对于接收到的每个字节,都不能保证引发DataReceived事件。使用BytesToRead属性确定缓冲区中要读取的数据数量。
这就是说,不能保证每个数据字节都会有一个单独的事件。您可能需要使用BytesToRead属性检查和查看端口上是否有多个可用字节,并读取相应的字节数。
发布于 2011-02-21 22:51:31
没有必要有一个旋转线程来轮询串口。
我建议使用SerialPort.BaseStream.BeginRead(.)方法。它比尝试在SerialPort类中使用事件要好得多。对BeginRead的调用立即返回,并注册一个异步回调,该回调在读取完成后被调用。在回调方法中,调用EndRead并返回读取到所提供缓冲区的字节数。BaseStream(SerialStream)继承了.Net流并遵循.Net流的一般模式,这是非常有用的。
但是重要的是要记住,调用回调的是.Net线程,所以您需要快速处理数据,或者将任何繁重的工作传递给您自己的线程。我强烈建议阅读以下链接,特别是备注部分。
http://msdn.microsoft.com/en-us/library/system.io.stream.beginread.aspx
发布于 2010-11-16 18:50:51
下面是一些VB代码,它们表达了我对应该如何做到这一点的看法:
Dim rcvQ As New Queue(Of Byte()) 'a queue of buffers
Dim rcvQLock As New Object
Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, _
ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _
Handles SerialPort1.DataReceived
'an approach
Do While SerialPort1.IsOpen AndAlso SerialPort1.BytesToRead <> 0
'what if the number of bytes available changes at ANY point?
Dim bytsToRead As Integer = SerialPort1.BytesToRead
Dim buf(bytsToRead - 1) As Byte
bytsToRead = SerialPort1.Read(buf, 0, bytsToRead)
'place the buffer in a queue that can be processed somewhere else
Threading.Monitor.Enter(rcvQLock)
rcvQ.Enqueue(buf)
Threading.Monitor.Exit(rcvQLock)
Loop
End Sub值得注意的是,与此非常相似的代码以接近1 1Mbps的速度处理了串口数据。
https://stackoverflow.com/questions/4169219
复制相似问题