HTU21D Temperature and Humidity Sensor Tutorial Part 2

If you’ve missed out on part 1 of this tutorial, you can catch up here.

If you closely read the HTU21D_datasheet, you’ll realise that the humidity data that you read directly from the HTU21D sensor does not meet the device’s guaranteed humidity accuracy of +-3%. Additionally, the sensor is only optimised to perform in the range of 5-95%RH, the rated accuracy of +-3% only applies between 20-80%RH.

This excerpt from the datasheet shows the device’s range of performance.


To ensure that your readings are as accurate as possible, you’ll need to apply the datasheet supplied temperature compensation equation. Calculating the temperature coefficient compensated relative humidity is easy as we already have code that reads the temperature and humidity values. If we check the datasheet we’ll find the temperature coefficient value of -0.15%RH/C is on page 3.

HTU21D temperature compensation coefficient datasheetModifying the existing code is straightforward and yields the following results.

Screenshot of HTU21D temperature compensated humidity readingsAs you can see from the screenshot, there isn’t much of a difference between the raw and compensated value at 29 degrees Celsius. In fact at 29.06C the %RH only increases by 0.609%RH. However, its effect does get more pronounced at higher temperatures – at 80C the %RH will increase by 8.25% – but I don’t foresee me ever needing to measure the humidity at these temperatures.

Below is the code for you to use and improve. If you like it, share it with others and let me know what you are using your HTU21D sensor for.

//Code to read the temperature and humidty from a HTU21D temperature sensor
//Tim Hansen 12/2/15 -
//Protocol: I2C (TWI)
//Specs - Temperature: -40 to 125 degrees Celcius
// - Humidity: 0 to 100% relative humidity
// - Voltage: 3.8VDC max

//What libraries do we need?
#include <Wire.h> //The "Wire.h" library is required to use the I2C commands

//Avoid global variables where practical. Global variables consume SRAM as soon as the micro starts. Whereas a local variable declared inside
//a function only consumes SRAM when the function is called.

void RequestMeas(int Address, int CommandCode)
Wire.beginTransmission(Address); // The HTU21D will respond to its address
Wire.write(CommandCode); // request the measurement, ie temperature or humidity

long ReadMeas(int Address)
//A measurement from the HTU21D is returned in 3 consecutive bytes. See page 11 of the datasheet
//the order of returend data is: [DATA (Most Sig Byte)], [DATA (Least Sig Byte)], [Checksum]
//We will ignore the checksum to save computation time and complexity. Page 14 of the datasheet details how to calculate the checksum

byte DataHIGH; //The location to store the high measurement byte
byte DataLOW; //The low measurement byte
byte CRC; //If you want to compute the CRC feel free to do so.

long Data; //The temporary memory location we are storing our data in as we receive it from the HTU21D
//Each packet of data is only 8bits in length, but if we do a bit shift we can store the 2 packets of
//measurement data in a variable. Remember you can only return 1 variable when a function finishes.
//Ideally, we'd use an int to store the result, however, at high measurement values in 14bit mode, an int overflows.
//To prevent overflow, we must use a single long (32bits).

Wire.requestFrom(Address, 3); //We are requesting data from the HTU21D and there will be 3x bytes that must be read.
while(Wire.available()) // Check for data from the HTU21D
DataHIGH =; // Read high byte
DataLOW =; // Read low byte
CRC =; // Read the CRC byte

//OK, so now we are going to 'pack' our 2x bytes of data measuremetns into a single int so only 1 variable is returned.
//To do this, we will use the left bitshift operator '<<'. What this does is push all the bits across to the left.
//FUN FACT: performing a left bit shift is equivalent to multiplication by 2 for each shift. The reverse is true for right
//bitshift which is equivalent to dividing by 2. This is a far more efficient method to perform multiply or divide by 2.

Data = DataHIGH; //The data sits in the low byte of 'int Data'.
//Ie, Data = [00000000][00000000][00000000][8 bits of DataHIGH]
Data = Data << 8; //Shift all the bits to the left for 8 bits. The old locations fill with zeros.
//Ie, Data = [00000000][00000000][8 bits of DataHIGH][00000000]
Data = Data + DataLOW; //Now simply add the low byte of data to the int.
//Ie, Data = [00000000][00000000][8 bits of DataHIGH][8 bits of DataLOW]

return Data; //return our measurement.

void setup()
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial for output

void loop()
//Set the address of the HTU21D. This detail is hidden at the bototm of page 10 of the datasheet.
const int I2C_address = 0x40; // I2C write address. Note that 'const' has been declared. If you try to write to this variable
// anywhere else in your code you'll get a compilation error. This prevents you from doing silly things.

const int TempCode = 0xE3; // A temperature measurement is executed with this command code. See page 11 of datasheet.
const int HumidCode = 0xE5; // A humidity measurement is executed with this command code. See page 11 of datasheet.
const float TempCoefficient = -0.15; //The temperature compensation coefficient value to guaratnee RH accuracy between 20-80%RH

long Temperature; //Perform our calculation using LONG to prevent overflow at high measuremetn values when using 14bit mode.
long Humidity;

float TemperatureFL; //Variable to store our final calculated temperature measurement
float HumidityFL;
float HumidityCompFL; //%RH value that has been temperature compensated to gurantee performance of +-3% between 20-80%RH

delay(100); // a short delay to let everything stabilise

while(true) // execute all the instructions in this loop forever
delay(10); //add a small delay to slow things down

RequestMeas(I2C_address, TempCode); //Request the current temperature
Temperature = ReadMeas(I2C_address); //read the result

//We must now convert our temp measurement into an actual proper temperature value
//According to page 15, the conversion equation is: Temp = -46.85 + 175.72 x TeampMeas / 2^16
//Becasue the result will have decimal places in the result we must use a Float datatype.
TemperatureFL = -46.85 + 175.72*(Temperature/pow(2, 16));

delay(10); //add a small delay to slow things down

RequestMeas(I2C_address, HumidCode); //Request the current humidity
Humidity = ReadMeas(I2C_address); //read the result

//We must now convert our humidity measurement into an actual proper humidity value
//According to page 15, the conversion equation is: Humidity = 6 + 125 x TeampMeas / 2^16
//Because the result will have decimal places in the result we must use a Float datatype.
HumidityFL = -6 + 125*(Humidity/pow(2, 16));

//The relative humidty value read from directly from the chip is not the optimised value.
//We must perfrom the 'temperature Coefficient Compensation Equation" specified on page 4 of the datasheet
//RHcompensated = RHactual + (25 - TEMPactual) * coefficient
//The coefficient value is -0.15%RH/C - from page 3 of datasheet
HumidityCompFL = HumidityFL +(25 - TemperatureFL) * TempCoefficient;

//All the calculations are complete, lets now display our values for temperature and humidity on the serial port.
Serial.print("Temperature: ");

Serial.print("Humidity (raw): ");

Serial.print("Humidity (Comp): ");


One thought on “HTU21D Temperature and Humidity Sensor Tutorial Part 2

  1. You need to lop off the lower two bits of the DataLOW value for both temperature and humidity measurements as these bits are status bits, not real data.


Share your thoughts

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.