htu21dflib.h
int i2c_open(const char *i2cdevname);
int i2c_close(int i2cfd);
int htu21df_init(int i2cfd, uint8_t i2caddr);
int htu21df_read_temperature(int i2cfd, float *temperature);
int htu21df_read_humidity(int i2cfd, float *humidity);
htu21dflib.c
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include "htu21dflib.h"
static const int MAX_TEMP_CONVERSION = 50; // milliseconds
static const int MAX_HUMI_CONVERSION = 16; // ms
static const int MAX_RESET_DELAY = 15; // ms
static uint8_t HTU21DF_READTEMP_NH = 0xF3; // NH = no hold
static uint8_t HTU21DF_READHUMI_NH = 0xF5;
static uint8_t HTU21DF_WRITEREG = 0xE6;
static uint8_t HTU21DF_READREG = 0xE7;
static uint8_t HTU21DF_RESET = 0xFE;
#define sleepms(ms) usleep((ms)*1000)
static uint8_t I2Caddr;
static int calc_crc8(const uint8_t *buf, int len);
int i2c_open(const char *i2cdevname_caller)
{
int i2cfd; // i2c file descriptor
FILE *boardrev; // get raspberry pi board revision
const char *i2cdevname;
i2cdevname = i2cdevname_caller;
boardrev = fopen("/sys/module/bcm2708/parameters/boardrev", "r");
if (boardrev) {
char aLine[80];
if (fgets(aLine, sizeof(aLine), boardrev)) {
long board_revision;
// Older board revisions use i2c-0, newer use i2c-1
board_revision = strtol(aLine, NULL, 10);
if ((board_revision == 2) || (board_revision == 3)) {
i2cdevname = "/dev/i2c-0";
}
else {
i2cdevname = "/dev/i2c-1";
}
}
fclose(boardrev);
}
if ((i2cdevname == NULL) || (*i2cdevname == '\0')) return -1;
if ((i2cfd = open(i2cdevname, O_RDWR)) < 0) {
printf("%s:Failed to open the i2c bus %d/%d\n", __func__, i2cfd,
errno);
return i2cfd;
}
return i2cfd;
}
int i2c_close(int i2cfd)
{
return close(i2cfd);
}
int htu21df_init(int i2cfd, uint8_t i2caddr)
{
uint8_t buf[32]; // i2c messages
int rc; // return code
struct i2c_rdwr_ioctl_data msgbuf;
struct i2c_msg reset[1] = {
{i2caddr, 0, 1, &HTU21DF_RESET},
};
struct i2c_msg read_user_reg[2] = {
{i2caddr, 0, 1, &HTU21DF_READREG},
{i2caddr, I2C_M_RD, 1, buf}
};
I2Caddr = i2caddr;
msgbuf.nmsgs = 1;
msgbuf.msgs = reset;
rc = ioctl(i2cfd, I2C_RDWR, &msgbuf);
if (rc < 0) {
printf("%s:htu21df I2C_RDWR failed %d/%d\n", __func__, rc, errno);
return rc;
}
sleepms(MAX_RESET_DELAY);
msgbuf.nmsgs = 2;
msgbuf.msgs = read_user_reg;
rc = ioctl(i2cfd, I2C_RDWR, &msgbuf);
if (rc < 0) {
printf("%s:htu21df I2C_RDWR failed %d/%d\n", __func__, rc, errno);
return rc;
}
if (buf[0] != 0x02) {
printf("%s:htu21df did not reset\n", __func__);
return -1;
}
return 0;
}
int htu21df_read_temperature(int i2cfd, float *temperature)
{
uint8_t buf[32]; // i2c messages
int rc; // return code
uint16_t rawtemp; // raw temperature reading
struct i2c_rdwr_ioctl_data msgbuf;
struct i2c_msg read_temp[2] = {
{I2Caddr, 0, 1, &HTU21DF_READTEMP_NH},
{I2Caddr, I2C_M_RD, 3, buf}
};
struct i2c_msg read_temp3[1] = {
{I2Caddr, I2C_M_RD, 3, buf}
};
msgbuf.nmsgs = 2;
msgbuf.msgs = read_temp;
rc = ioctl(i2cfd, I2C_RDWR, &msgbuf);
if (rc < 0) {
//printf("I2C_RDWR %d/%d\n", rc, errno);
sleepms(MAX_TEMP_CONVERSION);
msgbuf.nmsgs = 1;
msgbuf.msgs = read_temp3;
rc = ioctl(i2cfd, I2C_RDWR, &msgbuf);
if (rc < 0) {
printf("%s:I2C_RDWR %d/%d\n", __func__, rc, errno);
return rc;
}
}
//printf("READTEMP = 0x%x 0x%x 0x%x\n", buf[0], buf[1], buf[2]);
if (calc_crc8(buf, 3) != 0) {
printf("%s:Bad CRC\n", __func__);
return -1;
}
// Remove low 2 bits because they are status
rawtemp = ((buf[0] << 8) | buf[1]) & 0xFFFC;
//printf("rawtemp %x\n", rawtemp);
*temperature = ((rawtemp / 65536.0) * 175.72) - 46.85;
return 0;
}
int htu21df_read_humidity(int i2cfd, float *humidity)
{
uint8_t buf[32];
uint16_t rawhumi; // raw humidity
int rc; // return code
struct i2c_rdwr_ioctl_data msgbuf;
struct i2c_msg read_humi[2] = {
{I2Caddr, 0, 1, &HTU21DF_READHUMI_NH},
{I2Caddr, I2C_M_RD, 3, buf}
};
struct i2c_msg read_temp3[1] = {
{I2Caddr, I2C_M_RD, 3, buf}
};
msgbuf.nmsgs = 2;
msgbuf.msgs = read_humi;
rc = ioctl(i2cfd, I2C_RDWR, &msgbuf);
if (rc < 0) {
//printf("I2C_RDWR %d/%d\n", rc, errno);
sleepms(MAX_HUMI_CONVERSION);
msgbuf.nmsgs = 1;
msgbuf.msgs = read_temp3;
rc = ioctl(i2cfd, I2C_RDWR, &msgbuf);
if (rc < 0) {
printf("%s:I2C_RDWR %d/%d\n", __func__, rc, errno);
return rc;
}
}
//printf("READHUM= 0x%x 0x%x 0x%x\n", buf[0], buf[1], buf[2]);
if (calc_crc8(buf, 3) != 0) {
printf("%s:Bad CRC\n", __func__);
return -1;
}
// Remove low 2 bits because they are status
rawhumi = ((buf[0] << 8) | buf[1]) & 0xFFFC;
//printf("rawhumi %x\n", rawhumi);
*humidity = ((rawhumi / 65536.0) * 125.0) - 6.0;
return 0;
}
// buf = 3 bytes from the HTU21DF for temperature or humidity
// 2 data bytes and 1 crc8 byte
// len = number of bytes in buf but it must be 3.
// return value < 0 error
// return value = 0 CRC good
// return value > 0 CRC bad
static int calc_crc8(const uint8_t *buf, int len)
{
uint32_t dataandcrc;
// Generator polynomial: x**8 + x**5 + x**4 + 1 = 1001 1000 1
const uint32_t poly = 0x98800000;
int i;
if (len != 3) return -1;
if (buf == NULL) return -1;
// Justify the data on the MSB side. Note the poly is also
// justified the same way.
dataandcrc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8);
for (i = 0; i < 24; i++) {
if (dataandcrc & 0x80000000UL)
dataandcrc ^= poly;
dataandcrc <<= 1;
}
return (dataandcrc != 0);
}
#ifdef HTU21DFTEST
static const char I2CDEV[] = "/dev/i2c-1"; // raspberry pi
static const uint8_t I2CADDR = 0x40; // htu21df i2c address
int main(int argc, char *argv[])
{
int rc; // return code
int i2cfd; // i2c file descriptor
int i;
float temperature, humidity;
char *i2c_devname;
i2c_devname = I2CDEV;
if (argc > 1) {
i2c_devname = argv[1];
}
printf("opening %s\n", i2c_devname);
i2cfd = i2c_open(i2c_devname);
if (i2cfd < 0) {
printf("i2c_open(%s) failed %d\n", i2c_devname, i2cfd);
return -1;
}
rc = htu21df_init(i2cfd, I2CADDR);
if (rc < 0) {
printf("i2c_init failed %d\n", rc);
return -2;
}
for (i = 0; i < 100; i++) {
rc = htu21df_read_temperature(i2cfd, &temperature);
if (rc < 0) {
printf("i2c_read_temperature failed %d\n", rc);
return -3;
}
rc = htu21df_read_humidity(i2cfd, &humidity);
if (rc < 0) {
printf("i2c_read_humidity failed %d\n", rc);
return -4;
}
printf("%.1f %.1f\n", temperature, humidity);
sleep(1);
}
rc = i2c_close(i2cfd);
if (rc < 0) {
printf("i2c_close failed %d\n", rc);
return -5;
}
return 0;
}
#endif