问题
I'd like to read from two (or more) serial ports (/dev/ttyUSB0 etc) at the same time in python on Linux. I want to read complete lines from each port (whichever has data) and process the results in the order received (without race conditions). As a simple example could just write the lines to a single merged file.
I assume the way to do this is based on pyserial, but I can't quite figure out how to do it. Pyserial has non-blocking reads using asyncio and using threads. Asyncio is marked as experimental. I assume there wouldn't be any race conditions if the processing is done in asyncio.Protocol.data_received()
. In the case of threads, the processing would probably have to be protected by a mutex.
Perhaps this can also be done not in pyserial. The two serial ports can be opened as files and then read from when data is available using select()
.
回答1:
As suggested by @AlexHall in a comment, here is a solution that uses one thread for each serial port and a queue to synchronize access:
import serial
import Queue
import threading
queue = Queue.Queue(1000)
def serial_read(s):
while True:
line = s.readline()
queue.put(line)
serial0 = serial.Serial('/dev/ttyUSB0')
serial1 = serial.Serial('/dev/ttyUSB1')
thread1 = threading.Thread(target=serial_read, args=(serial0,),).start()
thread2 = threading.Thread(target=serial_read, args=(serial1,),).start()
while True:
line = queue.get(True, 1)
print line
It may be possible to write this more elegantly, but it works.
回答2:
Consider using aioserial.
Here's an example:
import asyncio
import concurrent.futures
import queue
import aioserial
async def readline_and_put_to_queue(
aioserial_instance: aioserial.AioSerial,
q: queue.Queue):
while True:
q.put(await aioserial_instance.readline_async())
async def process_queue(q: queue.Queue):
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
while True:
line: bytes = await asyncio.get_running_loop().run_in_executor(
executor, q.get)
print(line.decode(errors='ignore'), end='', flush=True)
q.task_done()
q: queue.Queue = queue.Queue()
aioserial_ttyUSB0: aioserial.AioSerial = \
aioserial.AioSerial(port='/dev/ttyUSB0')
aioserial_ttyUSB1: aioserial.AioSerial = \
aioserial.AioSerial(port='/dev/ttyUSB1', baudrate=115200)
asyncio.run(asyncio.wait([
readline_and_put_to_queue(aioserial_ttyUSB0, q),
readline_and_put_to_queue(aioserial_ttyUSB1, q),
process_queue(q),
]))
回答3:
You could try to take the values in order and memorise it in variables:
a = data1.read ()
b = data2.read ()
And after process it in order:
If len (a) != 0 or len (b ) != 0:
Process a
Process b
Using this method if one or both of the value has data, process it
来源:https://stackoverflow.com/questions/37505062/read-from-two-serial-ports-asynchronously