Thursday, November 5, 2015

HDC100x Temperature/Humidity Sensor

Humidity is notoriously difficult to measure accurately. And now I have found that humidity sensors are very fickle. I had been using the AM2315 sensor, which Adafruit clearly states is not weatherproof. I can attest that it is definitely not. It worked OK for a few months, although it did have a problem when it rained. After rain, it would show 100% humidity for a few days until it dried out. Finally a couple of months ago, it died completely.

I have now installed an HDC1008 sensor. This device uses an I2C interface and has a very simple protocol. There is some sample code below.
To get a reliable temperature reading from any sensor it should be placed in a shroud that provides shade and good ventilation. I mounted the HDC1008 inside the shroud from my old weather system. This will protect it from the weather and prevent a spike in temperature reading when the sun hits it.

Accuracy Issues

The image below shows a plot of temperature for an entire day. The HDC1008 is the top line and the bottom line is a DS18B20 one-wire temperature sensor.

There are two things easily noticeable - First, there is a two degree difference in the sensors. I placed my laboratory thermometer next to these sensors for several minutes to get an accurate reading of the true temperature. It was exactly in between the two sensors, so one is one degree low and the other is one degree high. The DS18B20 specifications say it has an accuracy of ±0.5°C which is 0.9°F, so this reading is only a little outside its claimed accuracy. The HDC1008 claims an accuracy of ±0.2°C which is 0.36°F, but mine shows a difference of 0.9°F.

The second thing to notice in the plot below is how wavy the top line is. The reading from the HDC1008 often fluctuate by a degree or more in a very short period. My software takes twenty readings per minute and averages them. This data is recorded each minute. This averaging does not smooth out the plot so I have to conclude that the readings from the HDC1008 really are changing like the plot shows.


Neither of the sensors discussed are going to provide laboratory level accuracy, but I wouldn't expect that from a low cost device. Both are fine for typical home weather monitoring. I use the DS18B20 on several other devices and prefer it because it is very low cost and very simple to use.

I have no way to measure the accuracy of the humidity readings from the HDC1008, but they seem to correlate well with nearby weather stations. My overall impression of the device is positive and I find it considerably better than the AM2315 that it replaced.


Below is sample code that I used to initially test the device. This was adapted from the library for arduino provided by Ladyada.  Many thanks to her and the other folks at Adafruit. 

  sample code for the HDC1000 Humidity & Temp Sensor
  adapted from Adafruit_HDC1000 library, license follows:  
  Designed specifically to work with the HDC1000 sensor from Adafruit

  These sensors use I2C to communicate, 2 pins are required to  
  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution

#include <errno.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <wiringPi.h>
#include <wiringPiI2C.h>

#define HDC1000_I2CADDR       0x40
#define HDC1000_TEMP          0x00
#define HDC1000_HUMID         0x01
#define HDC1000_CONFIG_MODE   (1 << 12)
#define HDC1000_CONFIG_RST    (1 << 15)
#define HDC1000_CONFIG_TRES_14  0
#define HDC1000_CONFIG_HRES_14  0
#define HDC1000_MANUFID       0xFE
#define HDC1000_DEVICEID      0xFF

uint16_t i2c_read16(int fd, uint8_t outbyte) 
 uint16_t retval;
 write(fd, &outbyte, 1);
 read(fd, &retval, 2);
 return ntohs(retval); 

uint32_t i2c_read32(int fd, uint8_t outbyte) 
 uint32_t retval;
 write(fd, &outbyte, 1);
 read(fd, &retval, 4);
 return ntohl(retval); 

int HDC1000_Init(uint8_t addr) 
 uint32_t x;
 int fd = wiringPiI2CSetup(addr);
 if (fd==-1)
  printf("wiringPiI2CSetup for hdc1000 failed\n");
  return -1;

 // reset, and select 14 bit temp & humidity
 uint16_t config = HDC1000_CONFIG_RST | HDC1000_CONFIG_MODE | HDC1000_CONFIG_TRES_14 | HDC1000_CONFIG_HRES_14;

 write(fd, &config, 2);

 x = i2c_read16(fd,HDC1000_MANUFID);
 if (x != 0x5449) 
  printf("HDC1000_MANUFID returned %4X\n",x);
  return -1;
 x = i2c_read16(fd,HDC1000_DEVICEID);
 if (x != 0x1000) 
  printf("HDC1000_DEVICEID returned %4X\n",x);
  return -1;
 return fd;

float HDC1000_readTemperature(int fd) 
  float temp = (i2c_read32(fd,HDC1000_TEMP) >> 16);
  temp /= 65536;
  temp *= 165;
  temp -= 40;

  return temp;

float HDC1000_readHumidity(int fd) 
  float hum = (i2c_read32(fd, HDC1000_TEMP) & 0xFFFF);

  hum /= 65536;
  hum *= 100;

  return hum;

int main()
 int fd;
 float x;
 fd = HDC1000_Init(HDC1000_I2CADDR);
 if (fd==-1)
  printf("HDC1000_Init failed\n");
  return 0;

 x = HDC1000_readTemperature(fd);
 printf("\n temperature = %4.1f degC %4.1f degF\n",x,((x*9)/5)+32);

 x = HDC1000_readHumidity(fd);
 printf("    humidity = %4.1f%%\n\n",x);
 return 0;

1 comment:

  1. RPi projects and items required to build them. Do read and comment