Python Serial port event

大兔子大兔子 提交于 2021-02-11 14:12:00

问题


I have an MCU connected to the computer through a serial interface. The MCU might send data at regular intervals or very seldom depending on the type of sensor connected to it. So I want to have a python function that gets called whenever there is data incoming from the serial port instead of polling all the time.

After reading a lot of similar questions (Small Example for pyserial using Threading. PySerial/Arduino, PySerial/interrupt mode, Python Serial listener, and so on), I came to the conclusion that the solution to this is threading. So I came up with 3 different codes that work:

First:

import time
import serial
import threading

ser = serial.Serial("/dev/ttyUSB0", 19200)
datos = ""

class SerialReaderThread(threading.Thread):
'''
The class with the method that reads the serial port in the backgroud.
'''
    def __init__(self):
        super().__init__()
        self._stop_event = threading.Event()
    
    def run(self):
        '''
        The method that actually gets data from the port
        '''
        global ser, datos
        while not self.stopped():
            datos = ser.readline().decode('ascii').strip() 
    
    def stop(self):
        self._stop_event.set()
        
    def stopped(self):
        return self._stop_event.is_set()

serial_thread = SerialReaderThread()
serial_thread.start()

i = 0
while i < 5:
    if datos != "":
        print(datos)
        datos = ""
        i += 1

serial_thread.stop()

while serial_thread.isAlive():
    pass
print("Thread stopped.")
ser.close()

Second:

import serial
import threading
import time

ser = serial.Serial("/dev/ttyUSB0", 19200)
read = True
datos = ""

def serialEvent():
    global ser, read, datos
    while read is True:
        datos = ser.read_until().decode('ascii').strip()
    return

t = threading.Thread(target=serialEvent)
t.start()

i = 0
while i < 5:
    if datos != "":
        print(datos)
        datos = ""
        i += 1

    
read = False
t.join()

while t.isAlive():
    pass
print("Thread stopped.")
ser.close()

Third:

import serial
import concurrent

ser = serial.Serial("/dev/ttyUSB0", 19200)
datos = ""
readData = True

def serialReadEvent():
    global ser, readData, datos
    
    while readData is True:
        datos = ser.read_until().decode('ascii').strip()
    
    return
    
executor = concurrent.futures.ThreadPoolExecutor()
serialData = executor.submit( serialReadEvent )
    
i = 0
while i < 5:
    if datos != "":
        print(datos)
        datos = ""
        i += 1

readData = False
while serialData.running():
    pass

print('Thread stopped.')
ser.close()

Question 1: is any of those codes better than the others?

Question 2: is using a global variable the best way to pass data between the thread and the main process?

I've also read that the PySerial API provides a way to work with threads, but I don't understand the documentation.

Question 3: can anybody give me an example of a reading thread using PySerial API?

Finally, I've read that Qt Serial Port also provides a way to process incoming data in a thread (example).

Question 4: is this the best way to solve my problem if I'm going to have a GUI written in PyQt5 as well?


回答1:


You got to the correct conclusion that the solution to this is Threading. But I would recommend to make maximum use of APIs of the framework/library you are using.

So in light of what you are trying to achieve, there is an API in pySerial in_waiting which return the number of bytes in receive buffer.

Making use of this, you can fire up a thread which will continuously monitor the underlying receive buffer and only read when your desired number of bytes are present in the buffer.

To share the received data between the Serial Read Thread and main, the better way to do is to make use of queues. Based on FIFO principle, your Serial Read Thread will be the one responsible for the enqueue operation only and main will be responsible for dequeue operation only. There won't be a case of data duplication etc. In main, you can decide how many bytes must be in this queue and only then you can dequeue.

This should work well with your GUI written in PyQt5.



来源:https://stackoverflow.com/questions/62836625/python-serial-port-event

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!