如何在 python 中使用多处理读取串行数据?
How to read serial data with multiprocessing in python?
我有一个不定期输出数据的设备。我想以 2 秒的间隔将数据写入 csv。所以我认为使用队列进行多处理可能会起作用。
在这里,我试图将数据从一个进程传递到另一个进程,但出现串行异常。另外,我无法在 IDLE 上 运行 它。所以我坚持使用终端。结果,错误消息一打开就关闭了。
代码如下:
import multiprocessing
import time
import datetime
import serial
try:
fio2_ser = serial.Serial("COM3",
baudrate=2400,
bytesize=serial.EIGHTBITS,
parity =serial.PARITY_ODD)
except serial.SerialException:
print("FiO2 Analyser Device not detected")
def Read_Data(q):
global fio2_ser
while True:
try:
fio2_data = fio2_ser.readline().decode('utf-8')
fio2_data = str(fio2_data).replace("\r\n","")
fio2_data = fio2_data.replace("\x000","")
except:
fio2_data = "FiO2 Data Unavailable"
q.put(fio2_data)
def Disp_Data(q):
while q.empty() is False:
fio2_data = q.get()
print(fio2_data)
time.sleep(2)
if __name__ == "__main__":
q = multiprocessing.Queue()
p1 = multiprocessing.Process(target=Read_Data, args=(q,))
p2 = multiprocessing.Process(target=Disp_Data, args=(q,))
p1.start()
p2.start()
p1.join()
p2.join()
当我运行一个单独的模块来收集数据时,它运行很好并收集数据。
import serial
try:
fio2_ser = serial.Serial("COM3",
baudrate=2400,
bytesize=serial.EIGHTBITS,
parity =serial.PARITY_ODD)
except serial.SerialException:
print("FiO2 Analyser Device not detected")
def Reader():
global fio2_ser
try:
fio2_data = fio2_ser.readline().decode('utf-8')
fio2_data = str(fio2_data).replace("\r\n","")
fio2_data = fio2_data.replace("\x000","")
return fio2_data
except:
return "FiO2 Data Unavailable"
if __name__ =='__main__':
value = Reader()
print(value)
当 q.empty() 为真时,Disp_Data() 函数将停止 运行。在我的例子中,循环立即退出。
可能有助于显示 SerialException 抛出的错误消息以查看原因:
except serial.SerialException as msg:
print( "Error opening serial port %s" % msg)
此外,最好优雅地关闭子进程。在我的例子中,他们在杀死主进程后保持 运行,所以 Read_Data() 进程保持端口打开。
多处理模块不喜欢 pickling pyserial。
以下代码片段适用于我的 Windows10 盒子
- 改为使用线程。
- 在这里和那里添加了一些打印语句以了解什么是
正在发生。
- 已使用 multiprocessing.Event() 改进关机。
- 打印异常错误消息以查看导致串行异常的原因。
- 串口超时一秒以允许读取循环继续。
- 可能不需要发布代码。
import threading, multiprocessing
import time
import serial
import sys
def OpenSerialPort(port=""):
print ("Open port %s" % port)
fio2_ser = None
try:
fio2_ser = serial.Serial(port,
baudrate=2400,
bytesize=serial.EIGHTBITS,
parity =serial.PARITY_ODD)
except serial.SerialException as msg:
print( "Error opening serial port %s" % msg)
except:
exctype, errorMsg = sys.exc_info()[:2]
print ("%s %s" % (errorMsg, exctype))
return fio2_ser
def Read_Data(queue, serialPort, stopped):
print ("Start reading data.")
serialPort.timeout = 1.0
while not stopped.is_set():
fio2_data = ''
try:
#print "Reading port..."
fio2_data = serialPort.readline()
except:
exctype, errorMsg = sys.exc_info()[:2]
print ("Error reading port - %s" % errorMsg)
stopped.set()
break
if len(fio2_data) > 0:
fio2_data = fio2_data.decode('utf-8')
fio2_data = str(fio2_data).replace("\r\n","")
fio2_data = fio2_data.replace("\x000","")
queue.put(fio2_data)
else:
queue.put("Read_Data() no Data")
serialPort.close()
print ("Read_Data finished.")
def Disp_Data(queue, stopped):
print ("Disp_Data started")
while not stopped.is_set():
#print "Check message queue."
if queue.empty() == False:
fio2_data = queue.get()
print(fio2_data)
print ("Disp_Data finished")
if __name__ == "__main__":
#serialPort = OpenSerialPort('/dev/ttyUSB0')
serialPort = OpenSerialPort('COM3')
if serialPort == None: sys.exit(1)
queue = multiprocessing.Queue()
stopped = threading.Event()
p1 = threading.Thread(target=Read_Data, args=(queue, serialPort, stopped,))
p2 = threading.Thread(target=Disp_Data, args=(queue, stopped,))
p1.start()
p2.start()
loopcnt = 20
while (loopcnt > 0) and (not stopped.is_set()):
loopcnt -= 1
print ("main() %d" % loopcnt)
try:
time.sleep(1)
except KeyboardInterrupt: #Capture Ctrl-C
print ("Captured Ctrl-C")
loopcnt=0
stopped.set()
stopped.set()
loopcnt=0
print ("Stopped")
p1.join()
p2.join()
serialPort.close()
print ("Done")
我有一个不定期输出数据的设备。我想以 2 秒的间隔将数据写入 csv。所以我认为使用队列进行多处理可能会起作用。
在这里,我试图将数据从一个进程传递到另一个进程,但出现串行异常。另外,我无法在 IDLE 上 运行 它。所以我坚持使用终端。结果,错误消息一打开就关闭了。
代码如下:
import multiprocessing
import time
import datetime
import serial
try:
fio2_ser = serial.Serial("COM3",
baudrate=2400,
bytesize=serial.EIGHTBITS,
parity =serial.PARITY_ODD)
except serial.SerialException:
print("FiO2 Analyser Device not detected")
def Read_Data(q):
global fio2_ser
while True:
try:
fio2_data = fio2_ser.readline().decode('utf-8')
fio2_data = str(fio2_data).replace("\r\n","")
fio2_data = fio2_data.replace("\x000","")
except:
fio2_data = "FiO2 Data Unavailable"
q.put(fio2_data)
def Disp_Data(q):
while q.empty() is False:
fio2_data = q.get()
print(fio2_data)
time.sleep(2)
if __name__ == "__main__":
q = multiprocessing.Queue()
p1 = multiprocessing.Process(target=Read_Data, args=(q,))
p2 = multiprocessing.Process(target=Disp_Data, args=(q,))
p1.start()
p2.start()
p1.join()
p2.join()
当我运行一个单独的模块来收集数据时,它运行很好并收集数据。
import serial
try:
fio2_ser = serial.Serial("COM3",
baudrate=2400,
bytesize=serial.EIGHTBITS,
parity =serial.PARITY_ODD)
except serial.SerialException:
print("FiO2 Analyser Device not detected")
def Reader():
global fio2_ser
try:
fio2_data = fio2_ser.readline().decode('utf-8')
fio2_data = str(fio2_data).replace("\r\n","")
fio2_data = fio2_data.replace("\x000","")
return fio2_data
except:
return "FiO2 Data Unavailable"
if __name__ =='__main__':
value = Reader()
print(value)
当 q.empty() 为真时,Disp_Data() 函数将停止 运行。在我的例子中,循环立即退出。
可能有助于显示 SerialException 抛出的错误消息以查看原因:
except serial.SerialException as msg:
print( "Error opening serial port %s" % msg)
此外,最好优雅地关闭子进程。在我的例子中,他们在杀死主进程后保持 运行,所以 Read_Data() 进程保持端口打开。
多处理模块不喜欢 pickling pyserial。
以下代码片段适用于我的 Windows10 盒子
- 改为使用线程。
- 在这里和那里添加了一些打印语句以了解什么是 正在发生。
- 已使用 multiprocessing.Event() 改进关机。
- 打印异常错误消息以查看导致串行异常的原因。
- 串口超时一秒以允许读取循环继续。
- 可能不需要发布代码。
import threading, multiprocessing
import time
import serial
import sys
def OpenSerialPort(port=""):
print ("Open port %s" % port)
fio2_ser = None
try:
fio2_ser = serial.Serial(port,
baudrate=2400,
bytesize=serial.EIGHTBITS,
parity =serial.PARITY_ODD)
except serial.SerialException as msg:
print( "Error opening serial port %s" % msg)
except:
exctype, errorMsg = sys.exc_info()[:2]
print ("%s %s" % (errorMsg, exctype))
return fio2_ser
def Read_Data(queue, serialPort, stopped):
print ("Start reading data.")
serialPort.timeout = 1.0
while not stopped.is_set():
fio2_data = ''
try:
#print "Reading port..."
fio2_data = serialPort.readline()
except:
exctype, errorMsg = sys.exc_info()[:2]
print ("Error reading port - %s" % errorMsg)
stopped.set()
break
if len(fio2_data) > 0:
fio2_data = fio2_data.decode('utf-8')
fio2_data = str(fio2_data).replace("\r\n","")
fio2_data = fio2_data.replace("\x000","")
queue.put(fio2_data)
else:
queue.put("Read_Data() no Data")
serialPort.close()
print ("Read_Data finished.")
def Disp_Data(queue, stopped):
print ("Disp_Data started")
while not stopped.is_set():
#print "Check message queue."
if queue.empty() == False:
fio2_data = queue.get()
print(fio2_data)
print ("Disp_Data finished")
if __name__ == "__main__":
#serialPort = OpenSerialPort('/dev/ttyUSB0')
serialPort = OpenSerialPort('COM3')
if serialPort == None: sys.exit(1)
queue = multiprocessing.Queue()
stopped = threading.Event()
p1 = threading.Thread(target=Read_Data, args=(queue, serialPort, stopped,))
p2 = threading.Thread(target=Disp_Data, args=(queue, stopped,))
p1.start()
p2.start()
loopcnt = 20
while (loopcnt > 0) and (not stopped.is_set()):
loopcnt -= 1
print ("main() %d" % loopcnt)
try:
time.sleep(1)
except KeyboardInterrupt: #Capture Ctrl-C
print ("Captured Ctrl-C")
loopcnt=0
stopped.set()
stopped.set()
loopcnt=0
print ("Stopped")
p1.join()
p2.join()
serialPort.close()
print ("Done")