I2C字节收到乱序的Raspberry Pi Python SMBus

时间:2018-09-08 15:26:28

标签: python raspberry-pi sensor i2c smbus

我正在设置Raspberry Pi,以记录来自Sensirion SCD30传感器的数据(CO2,湿度和温度)。我的代码在python3中,使用SMBus库通过Pi的GPIO中的I2C引脚与传感器通信。有一条命令可以确定传感器是否准备好发送数据。

Link to SCD30 interface datasheet

Link to SCD30 library for arduino by Sparkfun

0x0202通过I2C发送,并返回3个字节​​的数据:

0x00 0x00 0x81 for data not ready
0x00 0x01 0xB0 for data ready

前两个字节是数据就绪值的MSB和LSB。正确组合后,它们应分别为0x00000x0001。 第三个字节是前两个字节的CRC8。这是通过0x31的多项式和0xFF的初始化来计算的。

大约一半的时间,字节以错误的顺序发送。代替MSB LSB CRC而是发送MSB CRC LSB。例如,如果数据准备就绪,则可能发送0x00, 0xB0, 0x01而不是0x00, 0x01, 0xB0。我不知道为什么会这样,而且我担心在发送数据时会出现损坏或问题。我可以更改代码以识别CRC是否是第二个字节,但是我想找到潜在的问题。

我正在使用smbus库发送和接收I2C数据。这是我发送命令和读取数据的代码:

bus = smbus.SMBus(0)
I2C_ADDRESS = 0x61

def sendCommand(self, cmd):  # sends a 2 byte command (cmd)
    data = [0]*2
    data[0] = cmd >> 8  # splits 2 byte command into MSB and LSB
    data[1] = cmd & 0xFF
    bus.write_i2c_block_data(I2C_ADDRESS, data[0], data[1:])

def readRegister(self, reg, length):  # sends 2 byte command (reg) and receives (length) bytes
    sendCommand(reg)
    data = bus.read_i2c_block_data(I2C_ADDRESS, 0, length)
    return data

对于上面给出的示例,我将运行以下代码:

ready = readRegister(0x0202, 3)  # returns a list of 3 bytes
print(ready)

并返回上面演示的3个字节的列表。

5 个答案:

答案 0 :(得分:4)

您拥有什么样的工具和技能?

(我的第一反应是搜索SCD30勘误,但我找不到任何内容,快速的网络搜索也没有发现任何类似的问题)

如果您有示波器或逻辑分析仪,请查看SCL和SDA并确认问题出在RPi上(也可能在传感器上)。

您可以更换设置的任何硬件组件吗?只是为了消除出现故障的几率。

您能否用C重写代码(使用/ dev / i2c-x),并查看问题是否仍然存在-这可以告诉您问题出在I2C主站的内核驱动程序,接线,SCD30芯片中还是在位于您的代码段和内核驱动程序之间的lib smbus或其他软件。

祝你好运

答案 1 :(得分:1)

SMBUS库不正确,因为SCD30需要的I2C命令比linux i2c-dev库提供的更长。

我们成功使用pigpiod通过python与传感器进行对话。我们的SCD30代码和安装说明(以及时钟延长问题的解决方案)可以在here on Github中找到。

答案 2 :(得分:0)

可能发生的情况是,传递用于读取的缓冲区不为空,并给您不稳定的数据。 读取数据之前,请尝试清除缓冲区(将值设置为0)。

答案 3 :(得分:0)

为此i2c设备使用SMBus是不正确的。

您应该将SMBus 6.5.7块读取(如果我正确的话,应该是read_i2c_block_data)与设备数据表1.3.4的数据就绪状态进行比较。它们与SMBus发送命令字节不同。

设备界面看起来足够简单,您不需要库。只需打开 i2c-dev ,执行I2C_SLAVE ioctl来设置地址,然后写入两个字节并读取三个字节。 kernel i2c device interface文档介绍了详细信息。

I2C_SLAVE=0x703
with open('/dev/i2c-1', 'r+b') as f:
    fcntl.ioctl(f, I2C_SLAVE, 0x61)
    f.write(b'\2\2')
    data = f.read(3)

要获取ioctl I2C_SLAVE值,请编译一个小的C程序以打印它。

#include <stdio.h>
#include <linux/i2c-dev.h>
int main() { printf("%#x\n", I2C_SLAVE); return 0; }

类似于cc file.c && ./a.out的值。

数据表确实在1.1中说:“ 主机必须支持时钟延长”。没有时钟延长,您必须为错误做好准备。有几种方法可以使用i2c-gpio在Pi上进行时钟延长。抱歉,我没有时间在这里详细说明,但是Google至少找到了some instructions

答案 4 :(得分:0)

可能是上拉电阻器问题。

请参见http://www.ti.com/lit/an/slva689/slva689.pdf

上拉电阻计算 强上拉电阻(小电阻器)会阻止IC上的I2C引脚驱动为低电平。 VOL水平 IC的输入缓冲器可以将其读取为有效逻辑低,从而确定最小上拉 阻力[RP (分钟)]。 RP (min)是VCC,VOL(max)和IOL的函数

Rp(min)=(Vcc-Vol(max))/ Iol

最大上拉电阻受总线电容(Cb )由于I2C标准的上升时间 规格。如果上拉电阻值太高,则I2C线可能在此之前未上升到逻辑高电平。 拉低。从时间t = 0开始,RC电路对幅度VCC的电压阶跃的响应为 以时间常数RC为特征。