首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >经常使用后台线程从串行端口读取

经常使用后台线程从串行端口读取
EN

Stack Overflow用户
提问于 2010-11-12 21:32:51
回答 3查看 11.7K关注 0票数 3

由于串口通信是异步的,我在项目的早期就意识到,涉及到与RS 232设备的通信,我必须有一个后台线程不断地读取接收到的数据的端口。现在,我使用的是IronPython (.NET 4.0),因此我可以访问内置于.NET中的光滑的SerialPort类。

代码语言:javascript
复制
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事件提供!

代码语言:javascript
复制
self.port.DataReceived += self.OnDataReceived

def OnDataReceived(self, sender, event):
    reading = self.port.ReadExisting()
    ...

可惜这是一文不值的,因为不一定会引发此事件

对于接收到的每个字节,都不能保证引发DataReceived事件。

那么,回到编写侦听器线程。我用一个只会一次又一次地调用BackgroundWorkerport.ReadExisting()来完成这个任务。当它看到一行结束(\r\n)时,它会将读取的内容放置到linebuffer中。然后,我的程序的其他部分查看linebuffer,看看是否有任何完整的行等待使用。

显然,这是一个经典的producer-consumer问题。生产者是BackgroundWorker,将完整的行放入linebuffer中。使用者是一些尽可能快地从linebuffer中消耗这些行的代码。

然而,消费者的效率有点低。现在,他不断地检查linebuffer,每次都感到失望,发现它是空的;尽管偶尔会有一条排队等待在里面。优化这一点的最佳方法是什么,这样消费者只有在有可用行时才会醒来?这样,消费者就不会不断地访问linebuffer,这可能会带来一些并发问题。

此外,如果有一种更简单/更好的方式不断地从串口读取,我是开放的建议!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-11-12 21:45:45

我不明白为什么不能使用DataReceived事件。就像医生说的那样

对于接收到的每个字节,都不能保证引发DataReceived事件。使用BytesToRead属性确定缓冲区中要读取的数据数量。

这就是说,不能保证每个数据字节都会有一个单独的事件。您可能需要使用BytesToRead属性检查和查看端口上是否有多个可用字节,并读取相应的字节数。

票数 4
EN

Stack Overflow用户

发布于 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

票数 3
EN

Stack Overflow用户

发布于 2010-11-16 18:50:51

下面是一些VB代码,它们表达了我对应该如何做到这一点的看法:

代码语言:javascript
复制
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的速度处理了串口数据。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4169219

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档