由于串口通信是异步的,早在我开始涉及与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 事件,所以它没什么用处。
数据接收事件 DataReceived 并不保证每个字节都能触发该事件。
因此,需要编写监听线程。我很快就使用了 BackgroundWorker 实现了这一点,它只是反复调用 port.ReadExisting()。它会读取传入的字节,并在看到行尾符(\r\n)时将读取的内容放入 linebuffer 中。然后程序中的其他部分查看 linebuffer 是否有完整的行等待使用。
现在,这显然是一个经典的生产者-消费者问题。生产者是 BackgroundWorker,将完整的行放入 linebuffer 中。消费者是一些代码,尽可能地快速从 linebuffer 中消耗这些行。
但是,消费者效率有些低下。目前,它一直在检查 linebuffer,每次都会失望地发现它为空;虽然偶尔也会发现里面有一行在等待。最好的方法是如何优化消费者,使其只在有可用行时才唤醒?这样消费者就不会不断地访问 linebuffer,从而可能引入一些并发问题。
另外,如果有更简单/更好的方法来从串行端口读取数据,我会很乐意听取建议!
ReadExisting
应该可以满足你的需求。但请确保你仔细阅读文档,ReadExisting
并不能保证获取到所有字节,它明确指出“根据编码读取所有立即可用的字节”。 - heavydport.Read(buffer, 0, port.BytesToRead)
,我猜测是这样吗? - Aphex