PySerial 非阻塞读取循环

新手上路,请多包涵

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

 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 毫秒发送一次数据。

原文由 DominicM 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 2k
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

原文由 Fredrik Håård 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

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

笔记:

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

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

  1. 要检查你的 pyserial 库( serial 模块)版本,运行这个——我首先在 这里 学到了这个:
    python3 -c 'import serial; \
       print("serial.__version__ = {}".format(serial.__version__))'

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

如果您的 pyserial 版本是 3.0 或更高版本,请在下面的代码中使用 属性 in_waiting 。如果您的 pyserial 版本小于 3.0,请在下面的代码中使用 函数 inWaiting() 。请在此处查看官方 pyserial 文档: https ://pyserial.readthedocs.io/en/latest/pyserial_api.html#serial.Serial.in_waiting。

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

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
        # ('\n') 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 non-blocking read with pySerial (Cannot get pySerial’s “in_waiting” property to work)

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

更新:

  • 2018 年 12 月 27 日:添加了关于 in_waitinginWaiting() 的评论。感谢@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 在评论中提出这一点。

多线程注意事项:

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

参考:

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

原文由 Gabriel Staples 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题