解决RPi+MCP3008压力传感器读取冻结及线程重复启动报错问题
解决树莓派MCP3008压力传感读取冻结及线程重复启动问题
核心问题分析
- 线程重复启动报错:Python的
threading.Thread对象一旦执行过start(),就不能再次调用该方法。你复用同一个measurement_thread实例,第二次调用start()必然触发"线程只能启动一次"的错误。 - 读取操作冻结:
- 每次读取都实例化
MCP3008(0),会重复初始化SPI总线,增加阻塞风险; - 数值过滤循环没有终止条件,极端情况会无限循环;
- 循环中未检查停止事件,调用
stop()后线程无法及时终止。
- 每次读取都实例化
修复后的代码实现
import threading import time from your_mcp3008_module import MCP3008 # 替换成实际导入路径 class PressureMeasurementThread(threading.Thread): def __init__(self): super().__init__() self.stop_event = threading.Event() self.pressure = None self.adc = MCP3008(0) # 初始化一次ADC实例,复用避免重复初始化SPI def run(self): try: p_list = [] # 读取5次有效数据 while len(p_list) < 5 and not self.stop_event.is_set(): p = 0.0 max_retries = 20 # 最大重试次数,防止无限循环 retry_count = 0 # 过滤无效值,同时检查停止事件 while not (0.05 <= p <= 0.99) and retry_count < max_retries and not self.stop_event.is_set(): if retry_count > 0: time.sleep(0.02) p = self.adc.value # 复用已初始化的ADC实例 retry_count += 1 # 如果拿到有效数据且未停止,加入列表 if 0.05 <= p <= 0.99 and not self.stop_event.is_set(): p_list.append(p) time.sleep(0.01) # 仅当未被强制停止时,保存结果 if not self.stop_event.is_set(): self.pressure = p_list except Exception as e1: print(f"Error while measuring pressure: {e1}") def stop(self): self.stop_event.set() def pressure_measure(): # 每次测量创建新的线程实例,避免重复启动问题 measurement_thread = PressureMeasurementThread() measurement_thread.start() # 等待线程完成测量(如果需要同步获取结果) measurement_thread.join(timeout=2) # 设置超时,防止线程冻结导致主程序阻塞 # 检查线程是否正常结束 if measurement_thread.is_alive(): measurement_thread.stop() measurement_thread.join() return None # 超时或强制终止,返回None标识失败 return measurement_thread.pressure
关键改动说明
- 线程实例化策略:每次调用
pressure_measure()时创建新的PressureMeasurementThread实例,彻底解决线程重复启动的问题。 - ADC实例复用:在线程初始化时创建一次
MCP3008实例,避免重复初始化SPI总线,降低阻塞概率。 - 循环终止条件:给数值过滤循环添加最大重试次数,同时在所有循环中检查停止事件,确保线程能及时响应终止请求。
- 超时机制:调用
join(timeout)设置超时,防止测量线程冻结导致主程序长时间阻塞。
使用说明
调用pressure_measure()后,会返回包含5个有效压力值的列表;如果测量超时或被强制终止,返回None,你可以根据这个结果做异常处理。
内容的提问来源于stack exchange,提问作者MrRaggamuffin
相关产品推荐
相关产品推荐

