Python含异常处理仍挂起:树莓派+MCP3008 ADC测温问题
解决树莓派MCP3008 ADC读取挂起的问题
我之前在做树莓派+MCP3008测热敏电阻的项目时,也碰到过类似的长时间运行后读取操作挂起的情况,结合你的问题,给你几个可行的解决方案:
核心问题分析
你用Signal设置超时但还是挂起,大概率是因为GPIOZero封装的MCP3008在底层调用SPI硬件接口时卡住了——Signal信号没法中断内核级的硬件IO操作,所以抛出异常后,底层的阻塞还是没法解除。
解决方案1:用进程封装ADC读取(最有效)
进程和主线程是独立的资源空间,超时后可以强制终止进程,彻底解决底层阻塞的问题。这里给你一个用multiprocessing实现的示例:
from multiprocessing import Process, Queue from gpiozero import MCP3008 def _read_adc_avg(queue, channel=0): # 子进程中执行ADC读取,避免阻塞主线程 try: adc = MCP3008(channel=channel) samples = [adc.value for _ in range(5)] avg_value = sum(samples) / 5 queue.put(avg_value) except Exception as e: queue.put(e) def get_temp_percent(timeout=1): result_queue = Queue() # 启动子进程执行读取操作 read_process = Process(target=_read_adc_avg, args=(result_queue,)) read_process.start() # 等待进程执行完成,超时则强制终止 read_process.join(timeout=timeout) if read_process.is_alive(): read_process.terminate() read_process.join() # 确保进程完全退出 raise TimeoutError("ADC读取超时,已终止阻塞进程") # 从队列获取结果 result = result_queue.get() if isinstance(result, Exception): raise result return result
这个方法的优势在于,哪怕底层SPI调用彻底卡住,我们也能通过terminate()直接杀死子进程,不会影响主线程的运行。
解决方案2:改用底层spidev库,手动控制SPI通信
有时候GPIOZero的高层封装会隐藏一些细节,改用spidev直接操作SPI总线,能更灵活地处理异常和重启设备:
import spidev import threading # 初始化SPI设备 spi = spidev.SpiDev() spi.open(0, 0) # bus=0, device=0对应CE0引脚 spi.max_speed_hz = 1000000 # 设置SPI速率,匹配MCP3008的规格 def _read_single_adc(channel): # MCP3008的原始读取逻辑 adc_data = spi.xfer2([1, (8 + channel) << 4, 0]) raw_value = ((adc_data[1] & 3) << 8) + adc_data[2] return raw_value / 1023.0 # 转换为0-1的百分比值 def get_temp_percent(timeout=1): samples = [] def _read_task(): nonlocal samples samples = [_read_single_adc(0) for _ in range(5)] # 用线程执行读取操作 read_thread = threading.Thread(target=_read_task) read_thread.start() read_thread.join(timeout=timeout) if read_thread.is_alive(): # 线程卡住时,重启SPI设备恢复通信 spi.close() spi.open(0, 0) raise TimeoutError("ADC读取超时,已重启SPI设备") return sum(samples) / 5
如果碰到SPI总线卡住,关闭再重新打开设备通常能恢复通信,比GPIOZero的封装更可控。
解决方案3:排查硬件与系统问题
除了代码层面,你也可以检查这两个点:
- 硬件连接:长时间运行后,SPI引脚(SCK、MOSI、MISO、CE0)或者热敏电阻的接线可能松动,导致通信异常。可以用万用表测一下引脚电压,或者重新插拔接线加固。
- 系统与驱动更新:树莓派的SPI内核驱动偶尔会有bug,执行
sudo apt update && sudo apt upgrade -y更新系统,或者用sudo rmmod spi_bcm2835 && sudo modprobe spi_bcm2835重新加载SPI模块,可能解决底层驱动的阻塞问题。
内容的提问来源于stack exchange,提问作者Aryeh Gielchinsky
相关产品推荐
相关产品推荐

