pyserial - 如何读取来自串口设备的最后一行数据

23 投票
10 回答
108573 浏览
提问于 2025-04-15 12:44

我有一个Arduino设备,它连接着我的电脑,并且在不断循环,每100毫秒就会通过串口发送一个数值回电脑。

我想写一个Python脚本,让它每隔几秒钟读取一次串口的数据,这样它就只需要看到Arduino最后发送的内容。

请问在Pyserial中怎么实现这个功能呢?

这是我尝试过的代码,但它不管用,因为它是顺序读取每一行数据。

import serial
import time

ser = serial.Serial('com4',9600,timeout=1)
while 1:
    time.sleep(10)
    print ser.readline() #How do I get the most recent line sent from the device?

10 个回答

11

你可以使用 ser.flushInput() 来清空当前缓冲区里的所有串口数据。

在清除掉旧数据后,你可以使用 ser.readline() 来获取串口设备最新的数据。

我觉得这个方法比这里其他人提的解决方案简单一些。对我有效,希望也适合你。

11

在编程中,有时候我们会遇到一些问题,特别是在使用某些工具或库的时候。比如,有人可能在使用某个库时,发现它的某些功能没有按照预期工作。这种情况可能会让人感到困惑,因为我们可能不知道问题出在哪里。

解决这类问题的一个好方法是查看文档。文档通常会详细说明如何正确使用这个库,里面可能会有示例代码和常见问题的解答。如果文档没有解决你的疑问,可以考虑在网上搜索一下,看看其他人是否遇到过类似的问题。

另外,参与社区讨论也是一个不错的选择。你可以在像StackOverflow这样的论坛上提问,描述你的问题和你尝试过的解决方法。这样,其他有经验的人就能帮助你找到问题的根源。

总之,遇到问题时不要慌张,先查文档、搜索资料,或者向社区求助,通常都能找到解决办法。

from serial import *
from threading import Thread

last_received = ''

def receiving(ser):
    global last_received
    buffer = ''

    while True:
        # last_received = ser.readline()
        buffer += ser.read(ser.inWaiting())
        if '\n' in buffer:
            last_received, buffer = buffer.split('\n')[-2:]

if __name__ ==  '__main__':
    ser = Serial(
        port=None,
        baudrate=9600,
        bytesize=EIGHTBITS,
        parity=PARITY_NONE,
        stopbits=STOPBITS_ONE,
        timeout=0.1,
        xonxoff=0,
        rtscts=0,
        interCharTimeout=None
    )

    Thread(target=receiving, args=(ser,)).start()
29

也许我误解了你的问题,但因为这是一个串行连接,你需要顺序读取从Arduino发送过来的所有数据——这些数据会在Arduino里被缓存,直到你去读取它。

如果你想要一个状态显示,能够显示最新发送的内容——可以使用一个线程,把你提到的代码放进去(去掉睡眠的部分),并把最后读取到的完整行保存为来自Arduino的最新行。

更新:mtasic的示例代码挺不错的,但如果在调用inWaiting()时Arduino发送了一部分数据,你会得到一行不完整的数据。你应该把最后一行完整的数据放入last_received,而把不完整的部分保存在buffer里,以便下次循环时可以继续拼接。可以这样做:

def receiving(ser):
    global last_received

    buffer_string = ''
    while True:
        buffer_string = buffer_string + ser.read(ser.inWaiting())
        if '\n' in buffer_string:
            lines = buffer_string.split('\n') # Guaranteed to have at least 2 entries
            last_received = lines[-2]
            #If the Arduino sends lots of empty lines, you'll lose the
            #last filled line, so you could make the above statement conditional
            #like so: if lines[-2]: last_received = lines[-2]
            buffer_string = lines[-1]

关于使用readline():这是Pyserial文档中的一些说明(稍作编辑以便更清晰,并提到readlines()):

使用“readline”时要小心。打开串口时一定要指定超时时间,否则如果没有接收到换行符,它可能会一直阻塞下去。此外,请注意“readlines()”只有在设置了超时时间的情况下才能工作。它依赖于超时,并将其视为文件结束(EOF)。

我觉得这些说法很合理!

撰写回答