Skip to content
Home » Embedded Systems » Sensors » Humidity Sensors Explained: Capacitive, Resistive, and Digital Types

Humidity Sensors Explained: Capacitive, Resistive, and Digital Types

Sensors for Embedded Systems
Part 13 of 18 — View Full Path →

KEY TAKEAWAYS

  • Capacitive humidity sensors (SHT31, BME280) offer the best accuracy and long-term stability for embedded projects.
  • DHT22 provides ±2% RH accuracy at low cost; SHT31 delivers ±1.5% RH with I2C and faster sampling.
  • Calibration using saturated salt solutions is the most reliable method for verifying humidity sensor accuracy.
  • Self-heating, poor airflow, and condensation are the top causes of humidity measurement errors in embedded designs.
  • Real applications include HVAC control, greenhouse automation, weather stations, and electronics environmental monitoring.

Part of the Complete Guide to Sensors for Embedded Systems series.

Humidity measurement is critical for weather stations, HVAC systems, greenhouses, food storage, and electronics environmental monitoring. This guide explains the different humidity sensor technologies, provides working code examples for the most popular sensors, and covers calibration techniques and common design pitfalls to help you build reliable humidity-aware embedded systems.

Humidity Measurement Basics

Relative humidity (RH) is the ratio of the current water vapor pressure to the saturation vapor pressure at the same temperature, expressed as a percentage. At 100% RH, the air is fully saturated and condensation (dew) forms. At 0% RH, the air is completely dry.

Temperature strongly affects humidity. Warm air can hold more moisture than cold air. This is why heating a room lowers the relative humidity — the actual moisture content stays the same, but the capacity increases. For every 1°C increase in temperature, the saturation vapor pressure rises by roughly 6-7%, which means the relative humidity drops proportionally if no moisture is added.

Dew point temperature is the temperature at which air becomes saturated. If a surface is at or below the dew point, condensation forms. This matters for electronics: condensation on PCBs causes short circuits and corrosion. Many embedded systems monitor humidity specifically to prevent condensation damage in enclosures.

Absolute humidity (grams of water per cubic meter) is temperature-independent but rarely used in embedded systems. Relative humidity is what most sensors measure and what most applications need.

Capacitive vs Resistive Humidity Sensors

Capacitive sensors use a thin polymer film (typically polyimide) sandwiched between two electrodes. As the film absorbs water molecules from the surrounding air, its dielectric constant changes, which alters the capacitance. The sensing circuit measures this capacitance change and converts it to a humidity reading. Capacitive sensors are the dominant technology in modern embedded humidity sensors including the SHT31, BME280, HDC1080, and the sensing elements inside DHT11/DHT22 modules.

Advantages of capacitive sensors include excellent linearity across the full 0-100% RH range, good long-term stability (drift under 0.5% RH per year), fast response time (5-30 seconds for a 63% step change), and the ability to recover from condensation without permanent damage. They consume very little power, making them ideal for battery-operated devices.

Resistive sensors use a hygroscopic material (ceramic or polymer) whose electrical resistance changes as it absorbs moisture. The resistance typically drops exponentially as humidity increases. While cheaper to manufacture, resistive sensors have several drawbacks: nonlinear response requiring correction, lower accuracy (±3-5% RH), significant drift over time (1-2% RH per year), and vulnerability to contamination from chemicals, dust, and oils. They also have a limited useful range, typically 20-80% RH, compared to the full 0-100% range of capacitive sensors.

For new embedded designs, capacitive sensors are almost always the better choice. Resistive sensors may still appear in legacy products or extremely cost-sensitive consumer goods, but the price gap has narrowed considerably.

DHT11 vs DHT22 Comparison

The DHT series sensors are the most widely used humidity sensors in hobbyist and educational embedded projects. Both use a capacitive sensing element with a built-in signal conditioning chip and communicate over a proprietary single-wire protocol. Here is a detailed comparison:

DHT11: Humidity range 20-80% RH, humidity accuracy ±5% RH, temperature range 0-50°C, temperature accuracy ±2°C, resolution 1% RH / 1°C (integer only), sampling rate once per second, price $1-2.

DHT22 (AM2302): Humidity range 0-100% RH, humidity accuracy ±2% RH, temperature range -40 to 80°C, temperature accuracy ±0.5°C, resolution 0.1% RH / 0.1°C, sampling rate once per 2 seconds, price $3-5.

The DHT22 is clearly superior in every specification except sampling rate and cost. For any project where accuracy matters, use the DHT22. The DHT11 is only suitable for rough indication where you just need to know if a room is “dry,” “comfortable,” or “humid.”

DHT22 Single-Wire Protocol: C Code Example

The DHT22 uses a proprietary single-wire protocol that requires precise timing. The MCU sends a start signal by pulling the data line low for at least 1ms, then releases it. The sensor responds with 40 bits of data: 16 bits humidity, 16 bits temperature, and 8 bits checksum. Each bit is encoded by the duration of a high pulse — a short pulse (26-28µs) is a 0, a long pulse (70µs) is a 1.

/* DHT22 sensor reading - bit-banging single-wire protocol */
#include <stdint.h>

#define DHT_PIN       GPIO_PIN_5
#define DHT_PORT      GPIOA
#define TIMEOUT_US    100

typedef struct {
    float humidity;
    float temperature;
    uint8_t valid;
} DHT22_Data;

static void dht_set_output(void) {
    GPIO_InitTypeDef gpio = {0};
    gpio.Pin = DHT_PIN;
    gpio.Mode = GPIO_MODE_OUTPUT_PP;
    gpio.Pull = GPIO_NOPULL;
    gpio.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DHT_PORT, &gpio);
}

static void dht_set_input(void) {
    GPIO_InitTypeDef gpio = {0};
    gpio.Pin = DHT_PIN;
    gpio.Mode = GPIO_MODE_INPUT;
    gpio.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(DHT_PORT, &gpio);
}

static uint8_t dht_wait_for_level(uint8_t level, uint32_t timeout_us) {
    uint32_t start = DWT->CYCCNT;
    uint32_t timeout_ticks = (SystemCoreClock / 1000000) * timeout_us;
    while (HAL_GPIO_ReadPin(DHT_PORT, DHT_PIN) != level) {
        if ((DWT->CYCCNT - start) > timeout_ticks) return 0;
    }
    return 1;
}

static uint32_t dht_measure_high_us(void) {
    uint32_t start = DWT->CYCCNT;
    uint32_t ticks_per_us = SystemCoreClock / 1000000;
    while (HAL_GPIO_ReadPin(DHT_PORT, DHT_PIN) == GPIO_PIN_SET) {
        if ((DWT->CYCCNT - start) > (TIMEOUT_US * ticks_per_us)) break;
    }
    return (DWT->CYCCNT - start) / ticks_per_us;
}

DHT22_Data DHT22_Read(void) {
    DHT22_Data result = {0.0f, 0.0f, 0};
    uint8_t data[5] = {0};

    /* Send start signal: pull low for 1ms, then release */
    dht_set_output();
    HAL_GPIO_WritePin(DHT_PORT, DHT_PIN, GPIO_PIN_RESET);
    delay_us(1200);
    HAL_GPIO_WritePin(DHT_PORT, DHT_PIN, GPIO_PIN_SET);
    delay_us(30);
    dht_set_input();

    /* Wait for sensor response: low 80us, high 80us */
    if (!dht_wait_for_level(GPIO_PIN_RESET, TIMEOUT_US)) return result;
    if (!dht_wait_for_level(GPIO_PIN_SET, TIMEOUT_US))   return result;
    if (!dht_wait_for_level(GPIO_PIN_RESET, TIMEOUT_US)) return result;

    /* Read 40 bits (5 bytes) */
    for (int i = 0; i < 40; i++) {
        if (!dht_wait_for_level(GPIO_PIN_SET, TIMEOUT_US)) return result;
        uint32_t high_time = dht_measure_high_us();
        data[i / 8] <<= 1;
        if (high_time > 40) {
            data[i / 8] |= 1;  /* Long pulse = bit 1 */
        }
    }

    /* Verify checksum */
    uint8_t checksum = data[0] + data[1] + data[2] + data[3];
    if (checksum != data[4]) return result;

    /* Parse humidity (0.1% resolution) */
    uint16_t raw_hum = (data[0] << 8) | data[1];
    result.humidity = raw_hum / 10.0f;

    /* Parse temperature (0.1C resolution, MSB of data[2] is sign) */
    uint16_t raw_temp = ((data[2] & 0x7F) << 8) | data[3];
    result.temperature = raw_temp / 10.0f;
    if (data[2] & 0x80) result.temperature = -result.temperature;

    result.valid = 1;
    return result;
}

SHT31 I2C Sensor: C Code Example

The SHT31 from Sensirion is a higher-end capacitive humidity sensor with I2C interface, ±1.5% RH accuracy, and a built-in heater for defogging. Its I2C interface makes it much simpler to read than the DHT series — no bit-banging required. The default I2C address is 0x44 (or 0x45 with ADDR pin high).

/* SHT31 I2C humidity/temperature sensor driver */
#include <stdint.h>

#define SHT31_ADDR          0x44
#define SHT31_CMD_MEASURE   0x2C06  /* High repeatability, clock stretching */
#define SHT31_CMD_HEATER_ON 0x306D
#define SHT31_CMD_HEATER_OFF 0x3066
#define SHT31_CMD_SOFT_RESET 0x30A2

typedef struct {
    float humidity;
    float temperature;
    uint8_t valid;
} SHT31_Data;

static uint8_t sht31_crc8(const uint8_t *data, uint8_t len) {
    uint8_t crc = 0xFF;
    for (uint8_t i = 0; i < len; i++) {
        crc ^= data[i];
        for (uint8_t bit = 0; bit < 8; bit++) {
            crc = (crc & 0x80) ? (crc << 1) ^ 0x31 : (crc << 1);
        }
    }
    return crc;
}

static HAL_StatusTypeDef sht31_send_cmd(uint16_t cmd) {
    uint8_t buf[2] = {cmd >> 8, cmd & 0xFF};
    return HAL_I2C_Master_Transmit(&hi2c1, SHT31_ADDR << 1,
                                   buf, 2, 100);
}

SHT31_Data SHT31_Read(void) {
    SHT31_Data result = {0.0f, 0.0f, 0};
    uint8_t buf[6];

    /* Trigger measurement */
    if (sht31_send_cmd(SHT31_CMD_MEASURE) != HAL_OK) return result;
    HAL_Delay(20);  /* Wait for conversion */

    /* Read 6 bytes: temp MSB, temp LSB, temp CRC, hum MSB, hum LSB, hum CRC */
    if (HAL_I2C_Master_Receive(&hi2c1, SHT31_ADDR << 1,
                                buf, 6, 100) != HAL_OK) return result;

    /* Verify CRCs */
    if (sht31_crc8(&buf[0], 2) != buf[2]) return result;
    if (sht31_crc8(&buf[3], 2) != buf[5]) return result;

    /* Convert raw values */
    uint16_t raw_temp = (buf[0] << 8) | buf[1];
    uint16_t raw_hum  = (buf[3] << 8) | buf[4];

    result.temperature = -45.0f + 175.0f * (raw_temp / 65535.0f);
    result.humidity    = 100.0f * (raw_hum / 65535.0f);
    result.valid = 1;
    return result;
}

Calibration Techniques

Humidity sensors drift over time and can arrive from the factory with small offsets. Calibration verifies and corrects the sensor reading against a known reference. The most accessible method for embedded engineers is the saturated salt solution method.

Place the sensor inside a sealed container with a saturated salt solution. Different salts produce different known humidity levels at a given temperature. Lithium chloride (LiCl) produces 11.3% RH at 25°C, magnesium chloride (MgCl2) produces 32.8% RH, sodium chloride (NaCl) produces 75.3% RH, and potassium sulfate (K2SO4) produces 97.3% RH. Allow 24-48 hours for equilibrium, then compare the sensor reading to the expected value.

For a two-point calibration, use NaCl (75.3%) and LiCl (11.3%) solutions. Calculate the offset and gain correction: corrected_RH = gain × measured_RH + offset. Store the calibration coefficients in non-volatile memory so they persist across power cycles.

Common Mistakes and Design Pitfalls

Self-heating errors: Operating a sensor continuously or at high sampling rates causes internal heating, which lowers the local relative humidity around the sensing element. The SHT31 draws only 600µA during measurement, but running it at maximum speed in a poorly ventilated enclosure can add 0.5-1°C of self-heating, translating to a 3-5% RH error. Use the lowest sampling rate your application allows.

Poor sensor placement: Mounting the sensor inside a sealed enclosure without airflow holes means it measures the humidity inside the box, not the environment. Use a vented enclosure or mount the sensor on a breakout that protrudes outside the enclosure. Avoid placing the sensor near heat-generating components like voltage regulators or power resistors.

Condensation damage: While capacitive sensors tolerate brief condensation, prolonged exposure to liquid water can degrade the polymer sensing film. If your application involves near-100% RH conditions (cold rooms, outdoor weather stations), use a PTFE membrane filter over the sensor to block liquid water while allowing water vapor to pass through. The SHT31 has a built-in heater specifically for burning off condensation.

Chemical contamination: Solvents, cleaning agents, adhesives, and conformal coatings can permanently shift the sensor calibration. Never clean a PCB with the humidity sensor already soldered on. Apply conformal coating before soldering the sensor, or mask the sensor area during coating.

Real-World Applications

HVAC systems: Humidity sensors enable demand-controlled ventilation, where fresh air is introduced based on actual moisture levels rather than fixed schedules. This reduces energy consumption by 20-40% in commercial buildings. The sensor controls humidifiers and dehumidifiers to maintain the 40-60% RH comfort range.

Weather stations: Outdoor weather monitoring combines humidity with temperature and pressure data to calculate dew point, heat index, and predict precipitation. Use a radiation shield (Stevenson screen) to protect the sensor from direct sunlight and rain while allowing airflow.

Greenhouse monitoring: Plants require specific humidity ranges — too low causes wilting, too high promotes fungal diseases like powdery mildew. Automated greenhouse systems use humidity sensors to control misting systems, exhaust fans, and shade screens. Multiple sensors at different heights account for humidity stratification within the greenhouse.

Electronics protection: Server rooms, telecommunications cabinets, and outdoor electronics enclosures monitor humidity to prevent condensation-induced failures. When humidity exceeds a threshold, the system activates heaters or ventilation to reduce moisture. A simple hysteresis algorithm prevents the heater from cycling rapidly.

Choosing a Humidity Sensor for Your Project

  • Budget IoT project: DHT22 — ±2% RH, $3-5, easy single-wire interface, but slow (2s between reads)
  • Precision monitoring: SHT31 — ±1.5% RH, I2C, fast response, built-in heater, $5-8
  • Combined weather station: BME280 — temperature + humidity + pressure in one chip, ±3% RH, $3-5
  • Industrial/HVAC: SHT85 or HYT271 — ±1% RH, robust package, long-term stability
  • Outdoor deployment: Use sensors with PTFE membrane filters to protect against dust and splashing

When designing with humidity sensors, remember: rapid temperature changes cause temporary errors as the sensor element equilibrates. Mount the sensor away from heat sources, ensure air circulation around the sensing element, and avoid touching the sensing element during assembly. With proper sensor selection, careful placement, and periodic calibration, humidity measurements in embedded systems can be both accurate and reliable over years of operation.

Related on this site

  • For a worked example of a digital humidity sensor in code, see working of DHT sensor (DHT11 and DHT22) — covers the single-wire protocol and a complete Arduino implementation.
  • Humidity and temperature are usually measured together — temperature sensors explained covers the thermistor, RTD, and IC options that pair well with humidity sensing.
  • Capacitive humidity sensors are prone to drift and contamination — sensor calibration techniques covers the periodic recalibration patterns that keep readings honest.

Going further: For analog humidity sensors (capacitive and resistive), the MCU’s ADC is the bridge between sensor and firmware — see ADC in Microcontrollers for the interfacing details.

Leave a Reply

Your email address will not be published. Required fields are marked *