A Real Device
Using an I2C device has two problems - the physical connection between master and slave and second figuring out what the software has to do to make it work. In this chapter we take the principle outlined in the previous one and add the information in the HTU21D/Si7021 data sheet to make a working temperature humidity sensor using the I2C functions.
First the hardware.
The SparkFun HTU21D/Si7021
The HTU21D Humidity and Temperature sensor or its recent replacement the is one of the easiest of I2C devices to use.
The only problem is that the HTU21D is only available in a surface mount package. To overcome this simply solder some wires onto the pads, it is possible to do, or you can buy a general breakout board.
However, it is much simpler to buy the SparkFun HTU21D/Si7021 breakout board because this has easy connections and built-in pull up resistors. The HTU21D has been replaced by the Si7021 which is more robust than the original and works the same.
https://www.sparkfun.com/products/12064
https://www.sparkfun.com/products/13763
If you decide to work with some other I2C device you can still follow the steps in this account, but you would have to modify what you do to be correct for the device you are using. In particular if you select a device that only works at 5V you might need a level converter.
Wiring the HTU21D
Given that the HTU21D has pull up resistors we really should disable them when used on the internal I2C bus which already has pullups. In practice the additional pullups don't seem to make much difference to the waveforms and you can leave them in place while testing.
You can use a prototype board to make the connections and this makes it easier to connect other instruments such as a logic analyzer.
A First Program
After wiring up any i2C device the first question that needs to be answered is - does it work?
Unfortunately for most complex devices finding out if it works is a multi-step process.
Our first program will aim to read some data back from the HTU21D - any data will do.
If you look at the data sheet you will find that the device address is 0x40 and its supports the following commands/registers:
Command | Code | Comment |
Trigger Temperature Measurement | 0xE3 | Hold master |
Trigger Humidity Measurement | 0xE5 | Hold master |
Trigger Temperature Measurement | 0xF3 | No Hold master |
Trigger Humidity Measurement | 0xF5 | No Hold master |
Write user register | 0xE6 | |
Read user register | 0xE7 | |
Soft Reset | 0xFE |
The easiest of these to get started with is the Read user register command. The user register gives the current setup of the device and can be used to set the resolution of the measurement.
Notice that the codes that you send to the device can often be considered addresses or commands. In this case you can think of sending 0xE7 as a command to read the register or the read address of the register - it makes no difference. In most cases the term command is used when sending the code makes the device do something and and the term address is used when it simply makes the device read or write specific data.
To read the user register we have to write a byte containing 0xE7 and then read the byte the device sends back. Notice that means sending an address frame, a data frame and then another address frame and reading a data frame. The device seems to be happy if you send a stop bit between each transaction or just a new start bit.
A program to read the user register is fairly easy to put together. The address of the device is 0x40 so its write address is 0x80 and its read address is 0x81. As the I2C functions adjust the address as needed we simply use 0x40 as the device's address but it does alter what you expect to see if you example the data being exchanged:
#include <stdio.h> #include <stdlib.h> #include <bcm2835.h> int main(int argc, char** argv) { if (!bcm2835_init()) return 1; char buf[] = {0xE7}; bcm2835_i2c_begin (); bcm2835_i2c_setSlaveAddress (0x40); bcm2835_i2c_write (buf,1); bcm2835_i2c_read (buf,1); printf("User Register = %X \r\n",buf[0]); bcm2835_i2c_end (); return (EXIT_SUCCESS); }
This sends the address frame for 0x80 and then the data byte 0xE7 to select the user register. Next it sends an address frame for 0x81 to read the data.
If you run the program you will see:
Register= 02
this is the default value of the register and it corresponds to a resolution of 12 and 14 bits for the humidity and temperature respectively and a supply voltage greater than 2.25V.