使用Python模块SMBus、树莓派和Arduino时输入/输出错误
我把一个树莓派和一个Rainbowduino连接在一起,使用的是自己做的I²C电平转换器,并且安装了Python模块SMBus。这样,树莓派就可以和Rainbowduino进行通信了。不过,有时候在执行命令bus.write_i2c_block_data(address, signal, data)
时,会出现输入/输出错误的信息。
错误信息是:
IOError: [Errno 5] 输入/输出错误
这是什么原因,怎么解决或者忽略这些错误呢?
5 个回答
根据你的树莓派型号,你可能需要用 bus = SMBus(0)
或者 bus = SMBus(1)
来初始化SMBus。
希望这能帮到你解决问题。
我正在用树莓派和Arduino UNO创建一个嗡嗡作响的服务器,使用的是i2c协议,但遇到了同样的问题。我的设计是这样的:当树莓派收到来自网络上某些外部机器的连接请求时,它会向Arduino发送一个'1',然后Arduino会通过改变一个全局变量来启动一个循环。在发送完'1'后,树莓派会不断读取Arduino的数据,以检查按钮的状态。当树莓派想停止读取时,它会发送'0'来停止循环,并重置所有计数器和LED灯。
问题是,在写入字节时,Python会随机出现IOError错误。在Arduino的串口监视器上,我注意到最后接收到的字节是1,而不是树莓派应该发送的0。查看i2cdetect -y 1时,我发现地址是错误的。我尝试了Jon的方法,但正如用户3126397提到的,错误的数据已经发送,导致Arduino停止工作。我尝试了他的modprobe命令,这只是压制了错误信息,Arduino仍然处于停止状态。
我最开始怀疑数据出错是因为读写不完整,所以在onReceive()中添加了一个Serial.println()来检查参数byteCount。没有改动其他代码的情况下,我观察到成功操作的次数在IOError之前大幅增加。因此,我尝试添加更多的println()来测试相关性,结果发现失败的次数显著增加。最后,我注释掉了所有的Serial语句,结果我能够在没有错误的情况下使用服务器进行了相当多次的测试(我测试了大约30次,仍然没有IOError)。
我怀疑,结合用户3126397关于重置波特率的解决方案和我对Serial.println()关系的观察,错误确实是由于树莓派和Arduino之间的同步问题造成的(因为串口相对较慢,会导致程序延迟,从而增加失败的可能性)。
简单来说,很多人都遇到这个问题,我找到了一种很简单的解决办法。
这个方法可以让你忽略错误,继续进行数据的发送和接收。调用 i2cdetect 似乎会重新初始化总线,而不是让 Arduino 从总线中消失。
我在这里发布了我找到这个解决方案的解释(现在在等待管理员审核) http://www.raspberrypi.org/phpBB3/viewtopic.php?f=41&t=52517
try:
bus.write_i2c_block_data(address, signal, data)
except IOError:
subprocess.call(['i2cdetect', '-y', '1'])
flag = 1 #optional flag to signal your code to resend or something
虽然这样可以让树莓派继续发送数据,但仍然会有错误的数据发送到 Arduino。 我找到的最简单的解决办法是在我的数据块末尾添加一个额外的校验和字节。
我把消息中的每个字节相加,放在一个字节变量里,这样当值超过最大值时会自动回绕,然后把校验和字节设置为使整个消息的和为零所需的值。
然后,Arduino 可以通过将所有字节相加来检查每个接收到的传输。如果消息的和不为零,就会被当作错误的传输而忽略。
我还给我的消息分配了一个字节的消息 ID,每次成功发送后递增,这样可以避免意外的重复发送。不过,这个可能并不是特别必要。