树莓派Zero W与MCP3008 SPI通信报错:Too many open files: /dev/spidev0.0
问题描述
我尝试通过SPI将MCP3008与树莓派Zero W连接以读取通道数据,使用Adafruit Blinka库实现。运行一段时间后出现错误:[Errno 24] Too many open files: '/dev/spidev0.0'。
我的Python代码如下:
import wiringpi from time import sleep wiringpi.wiringPiSetup() import busio import digitalio import board import adafruit_mcp3xxx.mcp3008 as MCP from adafruit_mcp3xxx.analog_in import AnalogIn class Readspi(Node): def execute(self): try: input_io = self.get_input_params() clock = int(input_io['clock']) miso = int(input_io["miso"]) mosi = int(input_io["mosi"]) channel = int(input_io['channel']) spi = busio.SPI(clock, mosi, miso) cs = digitalio.DigitalInOut(board.D5) mcp = MCP.MCP3008(spi, cs) temp_value = AnalogIn(mcp, channel) new_value = temp_value.value print(type(new_value), " ", new_value) spi.deinit() except Exception as exception: self.set_next_node_params([str(exception), ]) print("fail")
问题分析与解决
核心原因
错误[Errno 24] Too many open files是因为每次调用execute方法时,虽然调用了spi.deinit(),但CS引脚的DigitalInOut对象没有被正确释放,导致系统文件句柄持续泄漏,积累到一定数量后触发报错。另外,wiringpi.wiringPiSetup()的初始化放在全局区域,若execute被多次调用,可能也会引发资源冲突。
修复步骤
- 正确释放CS引脚资源
在spi.deinit()之后,需要调用cs.deinit()来释放CS引脚的文件句柄,避免泄漏。 - 优化资源初始化逻辑
将SPI和MCP3008的初始化移到类的初始化方法(__init__)中,而不是每次execute都重新创建。这样可以避免重复打开/关闭SPI设备,减少资源消耗。 - 移除不必要的wiringpi初始化
代码中使用了Adafruit Blinka库的busio和digitalio,与wiringpi属于不同的GPIO控制框架,同时使用可能引发冲突,建议移除wiringpi相关代码。
修复后的代码
import busio import digitalio import board import adafruit_mcp3xxx.mcp3008 as MCP from adafruit_mcp3xxx.analog_in import AnalogIn class Readspi(Node): def __init__(self): # 初始化SPI和MCP3008,只执行一次 input_io = self.get_input_params() clock = int(input_io['clock']) miso = int(input_io["miso"]) mosi = int(input_io["mosi"]) self.channel = int(input_io['channel']) self.spi = busio.SPI(clock, mosi, miso) self.cs = digitalio.DigitalInOut(board.D5) self.mcp = MCP.MCP3008(self.spi, self.cs) def execute(self): try: temp_value = AnalogIn(self.mcp, self.channel) new_value = temp_value.value print(type(new_value), " ", new_value) except Exception as exception: self.set_next_node_params([str(exception), ]) print("fail") # 类销毁时自动释放资源 def __del__(self): self.cs.deinit() self.spi.deinit()
额外建议
- 检查系统文件句柄限制:可以通过
ulimit -n命令查看当前用户的文件句柄上限,若需要可临时调整为更大的值(如ulimit -n 1024),但修复代码泄漏才是根本解决办法。 - 确保树莓派已启用SPI:通过
raspi-config进入Interfacing Options,确认SPI已开启。
内容的提问来源于stack exchange,提问作者Ax111_
相关产品推荐
相关产品推荐

