Python串行端口事件 [英] Python Serial port event

查看:38
本文介绍了Python串行端口事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个通过串行接口连接到计算机的MCU.MCU可能会定期或很少发送数据,具体取决于所连接的传感器的类型.因此,我希望有一个python函数,只要有串行端口传入的数据就调用它,而不是一直轮询.

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.

在阅读了许多类似的问题之后(使用Threading的pyserial的小示例. PySerial/Arduino PySerial/中断模式Python串行侦听器,依此类推),我得出的结论是解决方案是线程化.所以我想出了3种有效的代码:

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:

第一:

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()

第二:

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()

第三:

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()

问题1:这些代码中的任何一个是否比其他代码更好?

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

问题2::使用全局变量是在线程和主进程之间传递数据的最佳方法吗?

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

我还阅读了 PySerial API提供了一种使用线程的方式,但是我不理解文档.

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

问题3:有人可以给我一个使用PySerial API的阅读线程的例子吗?

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

最后,我读到了 Qt串行端口提供了一种在线程中处理传入数据的方法(示例).

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

问题4:,如果我也要用PyQt5编写GUI,这是解决我的问题的最佳方法吗?

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

推荐答案

您已经得出正确的结论,即解决方案是线程化.但是我建议尽量利用您正在使用的框架/库的API.

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.

因此,根据您要实现的目标,pySerial中有一个API 正在等待,它将返回接收缓冲区中的字节数.

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.

要在串行读取线程和主线程之间共享接收到的数据,更好的方法是利用队列.根据FIFO原理,您的串行读取线程将仅负责排队操作,而main仅负责出队操作.不会出现数据重复等情况.在主要情况下,您可以确定此队列中必须有多少个字节,然后才可以出队.

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.

这应该与您用PyQt5编写的GUI一起很好地工作.

This should work well with your GUI written in PyQt5.

这篇关于Python串行端口事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆