在Python中实时读取串行数据

时间:2013-11-11 13:58:08

标签: python python-2.7 serial-port pyserial

我使用Python中的脚本通过串行端口以2Mbps从PIC单片机收集数据。

PIC工作在2Mbps的完美时序,FTDI usb串行端口在2Mbps下运行良好(均通过示波器验证)

我发送消息(大约15个字符大小)大约每秒100-150倍,然后增加数量(检查我是否有丢失消息等等)

在我的笔记本电脑上,我将Xubuntu作为虚拟机运行,我可以通过Putty和我的脚本(python 2.7和pySerial)读取串口

问题:

  • 当通过Putty打开串口时,我看到所有消息(消息中的计数器逐1递增)。完美!
  • 当通过pySerial打开串口时,我看到所有消息,但不是每秒接收100-150x,而是以每秒约5次接收它们(仍然是消息逐渐递增1)但它们可能存储在某个缓冲区中,就像当我关掉PIC,我可以去厨房然后回来,我仍然收到消息。

这是代码(我省略了大部分代码,但循环是相同的):

ser = serial.Serial('/dev/ttyUSB0', 2000000, timeout=2, xonxoff=False, rtscts=False, dsrdtr=False) #Tried with and without the last 3 parameters, and also at 1Mbps, same happens.
ser.flushInput()
ser.flushOutput()
While True:
  data_raw = ser.readline()
  print(data_raw)

任何人都知道为什么pySerial需要花费很多时间从串口读取直到行尾? 有什么帮助吗?

我希望实时拥有此功能。

谢谢

4 个答案:

答案 0 :(得分:33)

您可以使用inWaiting()来获取输入队列中可用的字节数。

然后你可以使用read()来读取字节,类似的东西:

While True:
    bytesToRead = ser.inWaiting()
    ser.read(bytesToRead)

为什么不在文档中使用readline()

Read a line which is terminated with end-of-line (eol) character (\n by default) or until timeout.

你正在等待每次阅读的超时,因为它等待eol。串行输入Q保持不变,只需要很长时间才能到达缓冲区的“结束”,为了更好地理解它:你正在像输入赛车一样写入输入Q,并像老车一样阅读:)< / p>

答案 1 :(得分:4)

您需要将超时设置为&#34;无&#34;当你打开串口时:

ser = serial.Serial(**bco_port**, timeout=None, baudrate=115000, xonxoff=False, rtscts=False, dsrdtr=False) 

这是一个阻塞命令,所以你要等到收到最后有换行符(\ n或\ r \ n)的数据: line = ser.readline()

获得数据后,它将尽快返回。

答案 2 :(得分:2)

来自the manual

  

参数超时的可能值:   ...    x 将超时设置为 x

  

readlines(sizehint = None,eol ='\ n')读取行列表,   直到超时sizehint被忽略,仅适用于API   与内置File对象的兼容性。

     

请注意,此功能仅在超时时返回。

所以你的readlines最多每2秒返回一次。如蒂姆建议的那样使用read()

答案 3 :(得分:0)

here找到了一个很好的解决方案:

  

这是一个用作pyserial对象的包装器的类。它   使您无需100%CPU即可读取行。它不包含任何   超时逻辑。如果发生超时,self.s.read(i)返回一个空   字符串,您可能想抛出一个异常来指示   超时。

据作者说,它应该很快:

  

下面的代码给我790 kB / sec,同时将代码替换为   pyserial的readline方法仅给我170kB / sec。

class ReadLine:
    def __init__(self, s):
        self.buf = bytearray()
        self.s = s

    def readline(self):
        i = self.buf.find(b"\n")
        if i >= 0:
            r = self.buf[:i+1]
            self.buf = self.buf[i+1:]
            return r
        while True:
            i = max(1, min(2048, self.s.in_waiting))
            data = self.s.read(i)
            i = data.find(b"\n")
            if i >= 0:
                r = self.buf + data[:i+1]
                self.buf[0:] = data[i+1:]
                return r
            else:
                self.buf.extend(data)

ser = serial.Serial('COM7', 9600)
rl = ReadLine(ser)

while True:

    print(rl.readline())