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 = 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
)。
笔记:
要检查你的 python3 版本,请运行以下命令:
python3 --version
我第一次编写和测试这个答案时的输出是Python 3.2.3
。
要检查你的 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_waiting。in_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_waiting
2018 年 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 在评论中提出这一点。
关于多线程的注意事项:
尽管如上所示,读取串行数据不需要使用多个线程,但以非阻塞方式读取键盘输入则需要。因此,为了实现非阻塞键盘输入读取,我写了这个答案:如何读取键盘输入?。
参考:
官方 pySerial
serial.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
- 2025年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)