PySerial 非阻塞读取循环

2025-03-05 09:14:00
admin
原创
2
摘要:问题描述:我正在读取这样的串行数据:connected = False port = 'COM4' baud = 9600 ser = serial.Serial(port, baud, timeout=0) while not connected: #serin = ser.read() ...

问题描述:

我正在读取这样的串行数据:

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

问题是它阻止了其他任何东西的执行,包括 Bottle Py Web 框架。添加sleep()无济于事。

将“while True”更改为“while ser.readline():”不会打印“test”,这很奇怪,因为它在 Python 2.7 中可以正常工作。有什么想法可能出错了吗?

理想情况下,我应该只在串行数据可用时才读取它。数据每 1,000 毫秒发送一次。


解决方案 1:

使用单独的线程完全没有必要。只需按照下面的示例进行无限 while 循环即可。

我在此处的eRCaGuy_PyTerm串行终端程序中使用了这种技术(在代码中搜索inWaiting()in_waiting

笔记:

  1. 要检查你的 python3 版本,请运行以下命令:

python3 --version

我第一次编写和测试这个答案时的输出是Python 3.2.3

  1. 要检查你的 pyserial 库(serial模块)版本,请运行此程序——我第一次在这里了解到这一点:

python3 -c 'import serial; \n    print("serial.__version__ = {}".format(serial.__version__))'

这只是导入serial模块并打印其serial.__version__属性。截至 2022 年 10 月,我的输出为:serial.__version__ = 3.5

如果您的 pyserial 版本为 3.0 或更高版本,请使用以下代码中的属性 。如果您的 pyserial 版本低于 3.0,请使用以下代码中的函数。请参阅此处的官方 pyserial 文档: https://pyserial.readthedocs.io/en/latest/pyserial_api.html#serial.Serial.in_waitingin_waiting inWaiting()

非阻塞、单线程串行读取示例

import serial
import time # Optional (required if using time.sleep() below)

ser = serial.Serial(port='COM4', baudrate=9600)

while (True):
    # Check if incoming bytes are waiting to be read from the serial input 
    # buffer.
    # NB: for PySerial v3.0 or later, use property `in_waiting` instead of
    # function `inWaiting()` below!
    if (ser.inWaiting() > 0):
        # read the bytes and convert from binary array to ASCII
        data_str = ser.read(ser.inWaiting()).decode('ascii') 
        # print the incoming string without putting a new-line
        # ('
') automatically after every print()
        print(data_str, end='') 

    # Put the rest of your code you want here
    
    # Optional, but recommended: sleep 10 ms (0.01 sec) once per loop to let 
    # other threads on your PC run during this time. 
    time.sleep(0.01) 

这样,您只在有数据时才读取和打印。您说:“理想情况下,我应该只在有数据时才读取串行数据。”这正是上面的代码所做的。如果没有数据可读取,它会跳到 while 循环中的其余代码。完全无阻塞。

(这个答案最初发布并调试在这里:Python 3 使用 pySerial 进行非阻塞读取(无法使 pySerial 的“in_waiting”属性工作))

pySerial 文档:http://pyserial.readthedocs.io/en/latest/pyserial_api.html

更新:

  • in_waiting2018 年 12 月 27 日:添加了关于vs的评论inWaiting()。感谢 @FurkanTürkal 在下面的评论中指出了这一点。请参阅此处的文档:https://pyserial.readthedocs.io/en/latest/pyserial_api.html#serial.Serial.in_waiting

  • 2018 年 10 月 27 日:添加睡眠功能以让其他线程运行。

  • 文档:https://docs.python.org/3/library/time.html#time.sleep

  • 感谢@RufusV2 在评论中提出这一点。

关于多线程的注意事项:

尽管如上所示,读取串行数据不需要使用多个线程,但以非阻塞方式读取键盘输入则需要。因此,为了实现非阻塞键盘输入读取,我写了这个答案:如何读取键盘输入?。

参考:

  1. 官方 pySerialserial.Serial()类 API - https://pyserial.readthedocs.io/en/latest/pyserial_api.html

解决方案 2:

将其放在单独的线程中,例如:

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

http://docs.python.org/3/library/threading

解决方案 3:

我要警告不要在线程中使用阻塞 IO。请记住,Python 有一个GIL,并且一次只能执行一个线程。现在请注意,pyserial 模块是访问串行端口的 OS 实现的包装器。这意味着它调用 Python 外部的代码。如果该代码阻塞,那么解释器也会被阻塞,Python 程序中什么都不会执行,即使是主线程也不会执行。

如果底层设备驱动程序没有很好地实现超时,那么在使用非阻塞 IO 或基于超时的轮询时也会发生这种情况。

更强大的方法是使用带有队列的多处理模块。在单独的进程中运行串行读取代码。这将确保主线程和其他线程不会阻塞,并且程序可以干净地退出。

解决方案 4:

使用定时器驱动事件来测试和读取串行端口。未经测试的示例:

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
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1324  
  IPD研发管理体系作为一种先进的研发管理理念和方法,对于打造优质产品体验起着至关重要的作用。它涵盖了从产品规划、研发、上市到生命周期管理的全流程,通过整合资源、优化流程、加强团队协作等方式,确保产品能够精准满足用户需求,提升用户满意度和忠诚度。IPD研发管理体系的核心原则IPD研发管理体系以市场驱动为核心原则。这意味着...
IPD集成产品开发   8  
  IPD(Integrated Product Development)产品开发流程作为一种先进的产品开发管理模式,在众多企业中得到广泛应用。它强调跨部门团队协作、并行工程以及基于市场的产品开发理念,旨在提高产品开发效率、缩短产品上市时间、提升产品质量。而成本控制在产品开发过程中至关重要,关乎企业的利润空间和市场竞争力。...
华为IPD流程   6  
  IPD(Integrated Product Development)产品开发流程作为一种先进的产品开发管理模式,在众多企业中得到了广泛应用。它从多个维度对产品开发过程进行优化和整合,为企业创新提供了强大的支撑。通过实施IPD产品开发流程,企业能够更加高效地将创意转化为具有市场竞争力的产品,从而在激烈的市场竞争中占据优...
华为IPD流程管理   10  
  华为作为全球知名的科技企业,其产品质量在市场上有口皆碑。华为IPD产品开发流程在确保产品质量方面发挥了至关重要的作用。IPD(Integrated Product Development)即集成产品开发,是一套先进的、成熟的产品开发管理思想、模式和方法。它打破了传统产品开发中各部门之间的壁垒,强调跨部门团队协作,从产品...
IPD集成产品开发流程   9  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用