3

I have an Si7012 temperature / humidity sensor attached to the i2c pins on my Raspberry Pi. Specifically, I have the Adafruit "break-out" with this sensor attached https://www.adafruit.com/product/3251. The break-out board adds some power regulation, but should have the same i2c interface.

I'm attempting to read the data. I prefer something other than Python, but I'm working with it for now. The temperature and humidity data each come back as two bytes. I've found multiple examples that suggest that the can be read by successive calls to read_byte from the smbus package. But when I do this sequence:

import smbus
bus = smbus.SMBus(1)
bus.write(0x40, 0xF3)
print bus.read_byte(0x40)
print bus.read_byte(0x40)

I get 103 printed twice. In the example, 0x40 is the correct address for the sensor on i2c and 0xF3 is the command for "no hold" measurement of temperature. If I blindly apply the specified function for converting the two bytes to a temperature (even though I don't believe they are both right), I get approximately 75 deg F. That's about right, suggesting that maybe I'm getting the more significant byte correctly.

If I do the corresponding thing for humidity (0xF5), then I get 126 printed twice. That coverts - applying the specified formula blindly - to a humidity in the right ballpark.

It seems unlikely that both bytes should be the same on both measurements, so I suspect that I'm not actually getting the second byte like I want, despite the online examples that I've found. Documentation for smbus that I've found so far has been too terse for me to get much insight.

Here's a third-party example showing similar code for this sensor: http://www.instructables.com/id/Build-a-Hygrometer-at-Home-Using-Raspberry-Pi-and-/

Is there some different API call that I should use here, either instead of or in addition to what I'm doing to get two bytes via i2c? A reference to good documentation on smbus would help.

EDIT

After further reading, I eventually found it confirmed that the above does read the most significant bit twice. That explains why I see what I see, but it does not give any hints how to fix the problem.

  • Since you say both returned values evaluate to roughly correct readings, have you tried blowing on, or placing your finger over it to change the Temp and/or humidity as a quick check that the sensor is working as expected. – Steve Robillard May 21 '17 at 20:04
  • @SteveRobillard I just put my finger on for a second and repeated the example. Now I get 107 twice - so a higher temperature but both bytes the same. – Brick May 21 '17 at 20:06
2

See http://abyz.me.uk/rpi/pigpio/examples.html#Python_Si7021_py for a different implementation.

The Python smbus module doesn't have any useful documentation (in my opinion).

1

To close this out, I eventually solved my problem by abandoning Python and writing my own I2C code in C/C++. This really is the "right" way in my opinion since it has the added benefit of eliminating the need for any Python.

To read length bytes from the I2C device at address over I2C bus busNumber, use these includes:

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>

And then you can use this code fragment for a "read" operation:

char *rxBuffer = new char[length];
char devPath[11];
sprintf(devPath, "/dev/i2c-%d", busNumber);
int i2cHandle = open(devPath, O_RDWR);

int opResult = ioctl(i2cHandle, I2C_SLAVE, (int) address);
opResult = read(i2cHandle, rxBuffer, length);
close(i2cHandle);

(Add error checking on the return code opResult as appropriate.)

At the end of that fragment, rxBuffer is an array that has your bytes. Don't forget to delete that array when you're done with it.

To write, you can use basically the same code, but instead of the read call

opResult = write(i2cHandle, dataContents, length);

where dataContents is an array of bytes to write over I2C.

1

In case someone else has this same issue and comes across this I was also looking to interface with the Si7021 via python smbus. The python smbus code I found worked is:

import smbus
bus = smbus.SMBus(1)
A = bus.read_i2c_block_data(0x40,0xE3,2) #Use hold master mode here
#The read_i2c_block_data should return a 2 byte array A
#This 2 byte array can be turned into a 16 bit number using a bit shift with an or operation
T = 175.72*(A[0]<<8 | A[1])/65536.0 - 46.85

The last line of code is just the conversion formula from the Si7021 datasheet. In the end I use a read call for the RH (again using hold master mode) followed by a read of the temperature already read from the RH call:

RH_raw = bus.read_i2c_block_data(0x40,0xE5,2)
RH = 125.0*(RH_raw[0]<<8 | RH_raw[1]])/65536.0 - 6.0
T_raw = bus.read_i2c_block_data(0x40,0xE0,2)
#0xE0 give the previous temperature measurement instead of measuring again using 0xE3
T = 175.72*(T_raw[0]<<8 | T_raw[1])/65536.0 - 46.85 
0

in the SI70XX series, the I2C data update works in a different way. in it when you read the same data register to get the reading first it will send the MSB and then will send the LSB. Please use this code to test your sensor. https://github.com/ControlEverythingCommunity/SI7021/blob/master/Python/SI7021.py

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.