我有一台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?
答案 0 :(得分:29)
也许我误解了你的问题,但由于它是一个串行线,你必须按顺序读取从Arduino发送的所有内容 - 它将被释放到Arduino中,直到你阅读它为止。
如果你想要一个显示最新发送内容的状态显示 - 使用一个包含你问题代码的线程(减去睡眠),并将最后一行完整的行保留为Arduino的最新行。< / p>
更新: 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]
关于readline()
的使用:这是Pyserial文档所说的内容(为了清晰起见而略微编辑,并提及readlines()):
使用“readline”时要小心。做 打开时指定超时 串口,否则可能阻塞 永远,如果没有换行符 接收。另请注意“readlines()” 仅适用于超时。它 取决于超时和 将其解释为EOF(文件结束)。
这对我来说似乎很合理!
答案 1 :(得分: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()
答案 2 :(得分: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
...并像以前一样做分手。
答案 3 :(得分:6)
您可以使用ser.flushInput()
清除当前缓冲区中的所有串行数据。
清除旧数据后,您可以使用ser.readline()从串行设备获取最新数据。
我认为这比其他提议的解决方案简单一点。为我工作,希望它适合你。
答案 4 :(得分:3)
此方法允许您单独控制收集每行所有数据的超时,以及等待其他行的不同超时。
# get the last line from serial port
lines = serial_com()
lines[-1]
def serial_com():
'''Serial communications: get a response'''
# open serial port
try:
serial_port = serial.Serial(com_port, baudrate=115200, timeout=1)
except serial.SerialException as e:
print("could not open serial port '{}': {}".format(com_port, e))
# read response from serial port
lines = []
while True:
line = serial_port.readline()
lines.append(line.decode('utf-8').rstrip())
# wait for new data after each line
timeout = time.time() + 0.1
while not serial_port.inWaiting() and timeout > time.time():
pass
if not serial_port.inWaiting():
break
#close the serial port
serial_port.close()
return lines
答案 5 :(得分:2)
你需要一个循环来读取发送的所有内容,最后一次调用readline()阻塞直到超时。所以:
def readLastLine(ser):
last_data=''
while True:
data=ser.readline()
if data!='':
last_data=data
else:
return last_data
答案 6 :(得分:2)
略微修改为mtasic&amp; Vinay Sajip的代码:
虽然我发现此代码对于类似的应用程序非常有用,但我需要所有从串行设备返回的线路,这些线路会定期发送信息。
我选择从顶部弹出第一个元素,记录它,然后将剩余的元素作为新缓冲区重新加入并从那里继续。
我意识到这是不 Greg所要求的,但我认为值得分享作为旁注。
def receiving(ser):
global last_received
buffer = ''
while True:
buffer = buffer + ser.read(ser.inWaiting())
if '\n' in buffer:
lines = buffer.split('\n')
last_received = lines.pop(0)
buffer = '\n'.join(lines)
答案 7 :(得分:2)
在无限循环内使用.inWaiting()
可能会有问题。根据实施情况,它可能会占用整个CPU。相反,我建议使用特定大小的数据进行读取。因此,在这种情况下,应该执行以下操作:
ser.read(1024)
答案 8 :(得分:2)
并发症太多
用换行符或其他数组操作拆分字节对象的原因是什么? 我写了最简单的方法,它将解决你的问题:
import serial
s = serial.Serial(31)
s.write(bytes("ATI\r\n", "utf-8"));
while True:
last = ''
for byte in s.read(s.inWaiting()): last += chr(byte)
if len(last) > 0:
# Do whatever you want with last
print (bytes(last, "utf-8"))
last = ''
答案 9 :(得分:0)
这是一个使用包装器的示例,该包装器使您无需100%CPU即可读取最新行
class ReadLine:
"""
pyserial object wrapper for reading line
source: https://github.com/pyserial/pyserial/issues/216
"""
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)
s = serial.Serial('/dev/ttyS0')
device = ReadLine(s)
while True:
print(device.readline())