HTS221 Humidity and Temperature Sensor
Environmental Sensing in Rust
ST Micro’s HTS221 is a “capacitive digital sensor for relative humidity and temperature” that can be used over either I²C or SPI. It is factory-calibrated, so there is no end-user calibration to incorporate into your application.
The driver provides a simple, high-level API to configure the chip once on startup, then read the temperature and humidity. It also provides type-safe access to configuration registers to support more complex applications (such as turning the chip off to save power, or running the integrated heating element to eliminate condensation).
hts221, you need a implementation of
embedded-hal; I’ve been using
stm32f30x-hal, though you could use any concrete HAL that provides I²C support (specifically just
WriteRead support). There is a
Builder that provides an easy way to configure the chip on creation, after which you can read simply the humidity and temperature from the sensor.
The relative humidity is reported from the chip at a resolution of 0.5%, and temperature is reported at a resolution of 0.125 °C, which is reflected in the
x8 suffixes, respectively. That is, the results are fixed precision, where the exponent for humidity is -1, and the exponent for temperature is -3. For example, if
humidity_x2 returns 97, then the relative humidity is 46.5%. And if
temperature_x8 returns 171, then the temperature is 21.375 °C. These resolutions were chosen because they are the resolution of the calibration values that are stored on the chip. While these resolutions are significantly higher than the stated sensitivity of the chip (0.004 rH% and 0.016 °C, respectively), they are well within the stated accuracy (3.5 rH% and 0.5 °C).
HTS221 value, you can read the relative humidity and temperature using
temperature_x8. These calls are blocking:
// given hts221
let rel_humidity = hts221.humidity_x2() / 2;
let temperature = hts221.temperature_x8() / 8;
You can also access most registers from the
To create an
HTS221 value, you need to use the
Builder to set up the chip. The builder handles the low-level details you will need to initialize the chip for simple applications. Once you have an
HTS221, you can read the humidity and temperature directly. The builder reads and stores all of the calibration registers, so there is no need to read them after initialization.
let hts221 = hts221::Builder::new(i2c)
.powered_up() // default
.with_update_mode(hts221::UpdateMode::Block) // default
.with_data_ready_disabled() // default
The Builder provides an option for every field of every configuration register on the chip.
- Number of temperature samples averaged. The chip will average a number of internal samples to produce one output sample. The more samples averaged, the more power the chip draws.
with_avg_tsets this value. If
with_avg_tis not called on the builder, this value is unchanged. This register is persistent across power loss. I would recommend setting this explicitly anyway.
- Number of humidity samples averaged.
with_avg_hsets this value. Similarly, if this is not called on the Builder, the value is unchanged.
- Power-down. This bit is set by calling
powered_downon the Builder. By default, the chip is powered on.
- Block data update mode. This bit is set by calling
UpdateMode::Continuous. Block mode is the default. The humidity and temperature ADC values are 16-bits, which are stored in 2 separate 8-bit registers each. Block update mode ensures that the chip does not update the high byte after the low byte is read until the high byte is read, so the two bytes are always from the same sample.
- Output data rate. This is set by calling
with_data_rateon the builder. It defaults to one-shot mode.
- Boot mode. This is set by calling
without_boot. Without is the default. Setting this bit resets the internal registers to the factory defaults.
- Heating element. This is not exposed by the Builder.
- One-shot enable. This is not exposed by the Builder.
- Data-ready polarity. This is set by calling
with_data_ready_polarity. By default, this value is not changed.
- Data-ready output mode.
with_data_ready_modeselects either Open-drain or push-pull mode on the output pin. By default, the value is not changed.
- Data-ready interrupt enable.
with_data_ready_enabledenables the external interrupt line (pin 3).
with_data_ready_disableddisables it. By default, it is disabled.
HTS221 object, you can access all of the read-write registers as well as some important read-only registers. Accessing any of the registers performs a blocking read to get the current register value. All of the read-write registers also provide a
modify method (similar to a
RegisterBlock created by svd2rust) that runs a function (that should modify the register value) then writes the value back to the chip for that register.
let cr2 = hts221.cr2()?;
Note that the register types are not as type-safe as those created by svd2rust, and that
w above is the same type (even the same object) as
cr2. So the following will compile, but will not turn the heater on:
You can access registers that are not available from the
HTS221 struct in the same way that hts221 does internally, through the structs in the device module:
let h_out = hts221::device::HumidityOut::new(i2c)?;
let adc_value: i16 = h_out.value();
let calibration = hts221::device::Calibration::new(i2c)?;
The crate does not provide separate access to the high or low bytes of the humidity or temperature reading, or to any of the calibration registers, all of which are returned as part of the Calibration struct.
- Increase the precision of the returned humidity. Within the operating range, we only have 8 bits of sensitivity on the humidity, though the chip provides up to 16 bits, depending on calibration values. The two examples I have on hand both support about 14 bits of precision. For temperature, the API currently supports 11 bits of precision within the operating range, which is sufficient for the two chips I have on hand, which only actually support about 10 bits of precision, based on their calibration values.
- Add errors for saturation conditions. The driver currently silently clamps readings outside the operating range for both temperature and humidity.
- Add SPI support. embedded-hal has traits that should support both blocking and non-blocking SPI communication. The board that my HTS221 is mounted on has VDD tied to CS, which puts the chip into I²C mode, so I am currently unable to test SPI.