在Python中实时读取串行数据

时间:2021-07-15 18:11:17

I am using a script in Python to collect data from a PIC microcontroller via serial port at 2Mbps.

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

The PIC works with perfect timing at 2Mbps, also the FTDI usb-serial port works great at 2Mbps (both verified with oscilloscope)

PIC工作在2Mbps的完美时序,FTDI usb串口也能在2Mbps下工作(均通过示波器验证)

Im sending messages (size of about 15 chars) about 100-150x times a second and the number there increments (to check if i have messages being lost and so on)

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

On my laptop I have Xubuntu running as virtual machine, I can read the serial port via Putty and via my script (python 2.7 and pySerial)

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

The problem:

  • When opening the serial port via Putty I see all messages (the counter in the message increments 1 by 1). Perfect!
  • 当通过Putty打开串口时,我看到所有消息(消息中的计数器递增1乘1)。完善!

  • When opening the serial port via pySerial I see all messages but instead of receiving 100-150x per second i receive them at about 5 per second (still the message increments 1 by 1) but they are probably stored in some buffer as when I power off the PIC, i can go to the kitchen and come back and im still receiving messages.
  • 当通过pySerial打开串口时,我看到所有消息,但不是每秒接收100-150x,而是以每秒约5次的速度接收它们(仍然是消息以1为单位递增)但它们可能存储在某个缓冲区中,就像我关机时一样PIC,我可以去厨房然后回来,我仍然收到消息。

Here is the code (I omitted most part of the code, but the loop is the same):

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

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)

Anyone knows why pySerial takes so much time to read from the serial port till the end of the line? Any help?

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

I want to have this in real time.

我想实时拥有这个。

Thank you

3 个解决方案

#1


27  

You can use inWaiting() to get the amount of bytes available at the input queue.

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

Then you can use read() to read the bytes, something like that:

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

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

Why not to use readline() at this case from Docs:

为什么不在Docs中使用readline():

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

You are waiting for the timeout at each reading since it waits for eol. the serial input Q remains the same it just a lot of time to get to the "end" of the buffer, To understand it better: you are writing to the input Q like a race car, and reading like an old car :)

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

#2


4  

You need to set the timeout to "None" when you open the serial port:

打开串口时,需要将超时设置为“无”:

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

This is a blocking command, so you are waiting until you receive data that has newline (\n or \r\n) at the end: line = ser.readline()

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

Once you have the data, it will return ASAP.

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

#3


1  

From the manual:

从手册:

Possible values for the parameter timeout: … x set timeout to x seconds

参数超时的可能值:... x set timeout to x seconds

and

readlines(sizehint=None, eol='\n') Read a list of lines, until timeout. sizehint is ignored and only present for API compatibility with built-in File objects.

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

Note that this function only returns on a timeout.

请注意,此函数仅在超时时返回。

So your readlines will return at most every 2 seconds. Use read() as Tim suggested.

所以你的阅读线最多每2秒返回一次。 Tim建议使用read()。

#1


27  

You can use inWaiting() to get the amount of bytes available at the input queue.

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

Then you can use read() to read the bytes, something like that:

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

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

Why not to use readline() at this case from Docs:

为什么不在Docs中使用readline():

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

You are waiting for the timeout at each reading since it waits for eol. the serial input Q remains the same it just a lot of time to get to the "end" of the buffer, To understand it better: you are writing to the input Q like a race car, and reading like an old car :)

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

#2


4  

You need to set the timeout to "None" when you open the serial port:

打开串口时,需要将超时设置为“无”:

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

This is a blocking command, so you are waiting until you receive data that has newline (\n or \r\n) at the end: line = ser.readline()

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

Once you have the data, it will return ASAP.

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

#3


1  

From the manual:

从手册:

Possible values for the parameter timeout: … x set timeout to x seconds

参数超时的可能值:... x set timeout to x seconds

and

readlines(sizehint=None, eol='\n') Read a list of lines, until timeout. sizehint is ignored and only present for API compatibility with built-in File objects.

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

Note that this function only returns on a timeout.

请注意,此函数仅在超时时返回。

So your readlines will return at most every 2 seconds. Use read() as Tim suggested.

所以你的阅读线最多每2秒返回一次。 Tim建议使用read()。