pyserial - 如何读取从串行设备发送的最后一行

Gre*_*reg 19 python serial-port arduino pyserial

我有一个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?
Run Code Online (Sandbox Code Playgroud)

Vin*_*jip 29

也许我误解了你的问题,但由于它是一个串行线,你必须按顺序读取从Arduino发送的所有内容 - 它将被缓存在Arduino中直到你阅读它.

如果你想要一个显示最新发送内容的状态显示 - 使用一个包含你问题中的代码的线程(减去睡眠),并将最后一行完整的行保留为Arduino的最新行.

更新: mtasic示例代码非常好,但如果Arduino在inWaiting()调用时发送了部分行,则会得到截断的行.相反,你想要做的是将最后一条完整的行放入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]
Run Code Online (Sandbox Code Playgroud)

关于使用readline():以下是Pyserial文档所说的内容(为了清晰起见而略微编辑并提及readlines()):

使用"readline"时要小心.在打开串口时指定超时,否则如果没有收到换行符,它可能永远阻塞.另请注意,"readlines()"仅适用于超时.它取决于具有超时并将其解释为EOF(文件结束).

这对我来说似乎很合理!


mta*_*c85 11

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()
Run Code Online (Sandbox Code Playgroud)


Ruf*_*fus 7

这些解决方案会在等待字符时占用CPU.

你应该至少进行一次阻塞调用来读取(1)

while True:
    if '\n' in buffer: 
        pass # skip if a line already in buffer
    else:
        buffer += ser.read(1)  # this will block until one more char or timeout
    buffer += ser.read(ser.inWaiting()) # get remaining buffered chars
Run Code Online (Sandbox Code Playgroud)

......和以前一样做分裂的事情.


小智 6

您可以使用ser.flushInput()刷新当前缓冲区中的所有串行数据.

清除旧数据后,您可以使用ser.readline()从串行设备获取最新数据.

我认为这比其他提出的解决方案简单一点.为我工作,希望它适合你.