我正在读这样的串行数据:
connected = False
port = 'COM4'
baud = 9600
ser = serial.Serial(port, baud, timeout=0)
while not connected:
#serin = ser.read()
connected = True
while True:
print("test")
reading = ser.readline().decode()
问题是它阻止了其他任何事情的执行,包括瓶子py web框架。添加sleep()
无济于事。
在ser.readline()中更改“while True”“to”:“不打印”test“,这很奇怪,因为它在Python 2.7中有效。任何想法可能出错?
理想情况下,我应该能够在可用时读取串行数据。数据每1,000毫秒发送一次。
答案 0 :(得分:39)
将它放在一个单独的线程中,例如:
import threading
import serial
connected = False
port = 'COM4'
baud = 9600
serial_port = serial.Serial(port, baud, timeout=0)
def handle_data(data):
print(data)
def read_from_port(ser):
while not connected:
#serin = ser.read()
connected = True
while True:
print("test")
reading = ser.readline().decode()
handle_data(reading)
thread = threading.Thread(target=read_from_port, args=(serial_port,))
thread.start()
答案 1 :(得分:33)
使用单独的线程是完全没必要的。只需为你的无限循环执行此操作(在Python 3.2.3中测试):
import serial
import time # Optional (if using time.sleep() below)
while (True):
# NB: for PySerial v3.0 or later, use property `in_waiting` instead of function `inWaiting()` below!
if (ser.inWaiting()>0): #if incoming bytes are waiting to be read from the serial input buffer
data_str = ser.read(ser.inWaiting()).decode('ascii') #read the bytes and convert from binary array to ASCII
print(data_str, end='') #print the incoming string without putting a new-line ('\n') automatically after every print()
#Put the rest of your code you want here
time.sleep(0.01) # Optional: sleep 10 ms (0.01 sec) once per loop to let other threads on your PC run during this time.
这样,只有在有东西的情况下才能阅读和打印。你说,“理想情况下,只有当串行数据可用时才能读取它。”这正是上面的代码所做的。如果没有任何内容可供阅读,它会跳转到while循环中的其余代码。完全没有阻塞。
(此答案最初发布并在此处调试:Python 3 non-blocking read with pySerial (Cannot get pySerial's "in_waiting" property to work))
pySerial文档:http://pyserial.readthedocs.io/en/latest/pyserial_api.html
更新:
in_waiting
vs inWaiting()
的评论。感谢@FurkanTürkal在下面的评论中指出了这一点。请参阅此处的文档:https://pyserial.readthedocs.io/en/latest/pyserial_api.html#serial.Serial.in_waiting。即使读取串行数据,如上所示,不要求使用多个线程,以非阻塞方式读取键盘输入 。因此,为了完成非阻塞键盘输入读取,我写了这个答案:How to read keyboard-input?。
答案 2 :(得分:0)
使用定时器驱动的事件来测试和读取串行端口。 未经测试的例子:
import threading
class serialreading():
def __init__(self):
self.active = True
self.test()
def test(self):
n_in =comport.in_waiting()
if n_in> 0:
self.data = self.data + comport.read(size=n_in)
if len(self.data) > 0:
print(self.data)
self.data=""
if self.active:
threading.Timer(1, test).start() # start new timer of 1 second
def stop(self):
self.active = False
答案 3 :(得分:0)
我会警告不要在线程中使用阻塞IO。请记住,Python有一个GIL,一次只能执行一个线程。现在请注意,pyserial模块是访问串行端口的OS实现的包装。这意味着它将调用Python外部的代码。如果该代码被阻止,则解释器也将被阻止,并且即使在主线程中,Python程序中也不会执行任何操作。
如果底层设备驱动程序不能很好地实现超时,甚至在使用非阻塞IO或基于超时的轮询时,甚至可能发生这种情况。
更健壮的方法是将multiprocessing模块与queue一起使用。在单独的过程中运行串行读取的代码。这样可以确保主线程和其他线程不会被阻塞,并且程序可以以干净的方式退出。