差异 I2C 传感器读数 Raspberry Pi 和 Arduino
Difference I2C Sensor Reading Raspberry Pi and Arduino
我正在使用 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);
}
但使用 Raspberry Pi 我编写了几乎相同的代码,希望它也能工作。
这是代码:
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)
代码看起来确实一样,但我只得到 -273,06666666666 作为 return 值。有人知道 Raspberry Pi 和 Arduino I2C 之间的区别在哪里,可以帮助我在 Pi 上获得正确的值吗?
我认为您在 python 中的阅读过程不正确。从端口 40 读取两次与从端口 40 读取两个字节不同。
我建议使用 read_byte_data(0x40, 0, 2) 并用 struct.unpack(">H")
处理它。
您可以使用read_i2c_block_data(addr, offset, numOfBytes)
方法从i2c 获取多于1 个字节的数据。 return 数据是一个字节列表。所以很容易转换成整数。
根据数据表和 Arduino 草图编辑
这是 Python 的完整代码,应该与 Arduino 示例相匹配:
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)
我找到了可行的解决方案。如果 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)
我正在使用 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);
}
但使用 Raspberry Pi 我编写了几乎相同的代码,希望它也能工作。 这是代码:
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)
代码看起来确实一样,但我只得到 -273,06666666666 作为 return 值。有人知道 Raspberry Pi 和 Arduino I2C 之间的区别在哪里,可以帮助我在 Pi 上获得正确的值吗?
我认为您在 python 中的阅读过程不正确。从端口 40 读取两次与从端口 40 读取两个字节不同。
我建议使用 read_byte_data(0x40, 0, 2) 并用 struct.unpack(">H")
处理它。
您可以使用read_i2c_block_data(addr, offset, numOfBytes)
方法从i2c 获取多于1 个字节的数据。 return 数据是一个字节列表。所以很容易转换成整数。
根据数据表和 Arduino 草图编辑
这是 Python 的完整代码,应该与 Arduino 示例相匹配:
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)
我找到了可行的解决方案。如果 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)