简体   繁体   English

I2C 传感器读取 Raspberry Pi 和 Arduino 的差异

[英]Difference I2C Sensor Reading Raspberry Pi and Arduino

I am using the Sensirion SFM3300 flow sensor and can read the correct values with the Arduino with the following code (I2C):我正在使用 Sensirion SFM3300 流量传感器,可以使用以下代码 (I2C) 使用 Arduino 读取正确值:

#include <Wire.h>

void setup() {
  // put your setup code here, to run once:
  Wire.begin();
  Serial.begin(115200);
  Wire.beginTransmission(byte(0x40));
  Wire.write(byte(0x10));
  Wire.write(byte(0x00));
  Wire.endTransmission();
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(100);
  Wire.requestFrom(0x40,2);
  uint16_t a = Wire.read();
  uint8_t  b = Wire.read();
  a = (a<<8) | b;
  float flow = ((float)a - 32768) / 120;
  Serial.println(flow);
}

But using the Raspberry Pi I have written the nearly the same code, hoping that it also will works.但是使用 Raspberry Pi 我编写了几乎相同的代码,希望它也能工作。 This is the code:这是代码:

from smbus2 import SMBus
import time
import numpy as np

address=0x40
bus = SMBus(1)

def write(value):
    bus.write_byte(address,value)

write(0x10)
write(0x00)

while True:
    time.sleep(0.1)
    a = np.uint16(bus.read_byte(0x40))
    b = np.uint8(bus.read_byte(0x40))
    a = (a<<8) | b
    flow = (float(a)-32768)/120
    print(flow)

The code really looks the same, but I only get -273,06666666666 as a return value.代码看起来真的一样,但我只得到 -273,06666666666 作为返回值。 Does somebody knows where are the differences between Raspberry Pi and Arduino I2C and can help me to get the right values on the Pi?有人知道 Raspberry Pi 和 Arduino I2C 之间的区别在哪里,可以帮助我在 Pi 上获得正确的值吗?

You can use read_i2c_block_data(addr, offset, numOfBytes) method to get more than 1 byte of data from i2c.您可以使用read_i2c_block_data(addr, offset, numOfBytes)方法从 i2c 中获取超过 1 个字节的数据。 the return data is a list of bytes.返回数据是一个字节列表。 So it is very easy to convert into an integer.所以很容易转换成整数。

Edited based on datasheet and Arduino sketch根据数据表和 Arduino 草图编辑

Here is the complete code for Python that should matched the Arduino example:这是应与 Arduino 示例匹配的 Python 完整代码:

from SMBus2 import SMBus
import time

offset = 32768
scale = 120

addr = 0x40
cmd = [0x10, 0x00]

with SMBus(1) as bus:
    bus.write_i2c_block_data(addr, 0, cmd)
    time.sleep(0.1)
    block = bus.read_i2c_block_data(addr, 0, 3)
reading = block[0] * 256 + block[1]
crc = block[2]    # should do some crc check for error
flow = (reading - offset)/scale
print(flow)

I don't think your read process in python is correct.我不认为你在 python 中的读取过程是正确的。 Reading from port 40 two times is different from reading two bytes from port 40.从端口 40 读取两次与从端口 40 读取两个字节不同。

I suggest to use read_byte_data(0x40, 0, 2) and process that with struct.unpack(">H") .我建议使用 read_byte_data(0x40, 0, 2) 并使用struct.unpack(">H")

I found a working solution.我找到了一个可行的解决方案。 It would be nice if a I2C-expert could tell me why the following code is working instead of the python code above.如果 I2C 专家能告诉我为什么下面的代码可以工作而不是上面的 python 代码,那就太好了。

from fcntl import ioctl
from struct import unpack
from smbus import SMBus

address = 0x40

SMBus(1).write_byte_data(address,16,0)
i2c = open("/dev/i2c-1", "rb", buffering=0)
ioctl(i2c,0x0703,address)
i2c.read(3)

d0,d1,c = unpack('BBB', i2c.read(3))
d = d0 << 8 | d1
a = (float(d)-32768.)/120
print(a)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM