Tenths and the sign bit
The DHT22 sends each number as one 16-bit word counting tenths: 51.2 % is 512, 23.4 °C is 234. Below freezing, the top bit of the temperature word turns on and the other fifteen still count up from zero, so −0.1 °C is 0x8001. Adafruit's library reads that correctly; a decoder written by hand can print −3276.7.
Two words of tenths
The frame is the same forty bits as a DHT11's: humidity high and low, temperature high and low, and a checksum, which forty bits and a checksum in the DHT11 book takes apart. What the DHT22 changes is what the pairs of bytes mean.
A DHT11 puts whole units in the first byte of each pair and, nearly always,
zero in the second. A DHT22 uses each pair as one 16-bit number counting
tenths, high byte first. So 51.2 % arrives as 0x02 0x00, which is 512, and
23.4 °C as 0x00 0xEA, which is 234. Adafruit's library shifts the high
byte up eight places, adds the low one, and multiplies by 0.1.
The datasheet's own §6 describes the bytes as "integral" and "decimal", which is how the DHT11 packs them and not how the DHT22 does. Trust the arithmetic: two bytes, one number, tenths.
The minus sign
Slide the temperature below zero and watch the top bit.
The temperature word is sign and magnitude. Bit 15 is the minus sign and
bits 0 to 14 are the size, in tenths, counting up from zero whichever side
of zero you are. So +0.1 °C is 0x0001 and −0.1 °C is 0x8001, one bit
apart.
That is not how a microcontroller stores a negative number. An int16_t
uses two's complement, where −0.1 would be 0xFFFF. Read the DHT22's word
straight into an int16_t and −0.1 °C becomes −32767 tenths, which prints
as −3276.7. Read it as unsigned and it prints 3276.9. Both show up the first
night the sensor goes below zero, and never in testing indoors.
Adafruit's library gets it right: it masks bit 15 off, reads the other fifteen as tenths, and negates the result if bit 15 was set. The fault only appears in code that decodes the bytes itself, such as a sketch ported from another sensor or a decoder written for a different platform.
The range, in words
The DHT22 is specified from −40.0 to 80.0 °C. That is words from 0x8190
(−400 tenths) through 0x0000 to 0x0320 (800 tenths). Humidity runs
from 0x0000 to 0x03E8, 0 to 1000 tenths. Anything outside those in a
frame whose checksum passes points at the decoder before the sensor.
When it does not work
Something read the temperature word as an ordinary signed 16-bit integer. The DHT22 uses sign and magnitude, not two's complement, so −0.1 °C, which is 0x8001, becomes −32767 tenths. Mask off bit 15, divide the rest by ten, and negate if bit 15 was set, as Adafruit's library does.
The decoder ignored the sign bit and read the whole word as a positive number of tenths. Anything from 3276.8 up means bit 15 was set: the real temperature is below zero. Adafruit's library handles it; a hand-written decoder has to.
That is a DHT11's frame read by the DHT22 decoder: 51 % in the first byte becomes 51 × 256 tenths. Either the sensor is a DHT11 or the sketch says DHT22 on a TK38. The white cage is the DHT22.
It does, in §6, and for the DHT22 that description is wrong. 51.2 % arrives as 0x02 0x00, which is 512 tenths, not as 51 and 2. Read each pair of bytes as one 16-bit number and divide by ten.
The DHT22's floor, the library's cache at the same number, and a loop timed so every line is a new reading.
Every two seconds →Edit this page — content/books/dht22/tenths-and-the-sign-bit.mdx
Questions about this product
See what other owners have asked, and read their solutions.
This page covers several products. Choose yours to see the right discussions.
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.