From bytes to degrees
Two bytes become a temperature by one multiplication and one subtraction, with no table and nothing stored in between. The other two bytes are checksums, and they are the reason a damaged reading arrives as no reading rather than as a plausible wrong one.
One straight line
Both conversions are one line of arithmetic, from the datasheet:
temperature (°C) = -45 + 175 × word / 65535
humidity (%) = 100 × word / 65535That is the whole of it. No lookup table, no calibration coefficients to fetch, no interpolation. Every one of the 65,536 possible words maps to exactly one reading, and the map is a straight line.
The calibration is not absent — it is applied inside the sensor, before the word is handed over, and the part reloads it from its own memory before every single measurement. What reaches you has already been linearised and corrected for temperature and supply voltage.
Which is what you are actually paying for. An NTC thermistor's resistance is a curve you have to model; this is a line.
What the numbers reach
Put 0x0000 in and temperature comes out at −45 °C. Put 0xFFFF in and it
comes out at 130 °C. The specified range is −40 to 125 °C, so the scale is
slightly wider than the guarantee at both ends.
Humidity runs 0 to 100 % across the same 65,536 steps, which makes one step worth 0.0015 %RH — far finer than the 0.01 % the datasheet quotes as the resolution, and very far finer than the ±2 % it is accurate to.
Negative temperatures need no special handling at all. The −45 is a subtraction applied to every reading, so a cold day is simply a small word. There is no sign bit, no two's complement, and none of the sign-and-magnitude arithmetic the DHT22 makes you do.
The 65536 in the library
Adafruit's library does not divide by 65535. It computes
((4375 × word) >> 14) - 4500and then divides by 100, which is the same formula with 65536 in the denominator, done in integers. The comment in the source says exactly that.
It matters not at all and is worth knowing about anyway. Across the whole sixteen-bit range the two formulas never disagree by more than 0.013 °C, and at room temperature they differ by under a hundredth — less than the smallest step the sensor reports, and fifteen times less than its accuracy. If you write your own decoder and get numbers a hundredth different from the library's, this is why, and neither of you is wrong.
Why there are two checksums
Four data bytes arrive with two checksum bytes, one per pair. Each is a CRC-8
computed over its own two bytes: polynomial 0x31, starting value 0xFF, no
final inversion.
The point is not to correct anything — a CRC-8 cannot. The point is that a reading either arrives intact or does not arrive at all.
Think about what the alternative would be. A single bit flipped in the high byte of the temperature word is worth 0.68 °C if it is the lowest bit of that byte, and 87 °C if it is the highest. Without a checksum, a bus with marginal wiring produces temperatures that are sometimes slightly wrong and occasionally absurd, and you have no way to tell those apart from a room that is genuinely changing.
With the checksums, the library compares and throws the whole pair away if either fails. That is what "read failed" is, and it is why the correct response to an occasional failure is to try again rather than to go looking for a fault — and why constant failures point at the bus rather than at the sensor.
Sensirion gives a test vector so you can prove your own implementation: the two
bytes 0xBE 0xEF must come out as 0x92.
When it does not work
Because 65535 is the largest value sixteen bits can hold, and the datasheet's formulas scale the full range onto it. Adafruit's library divides by 65536 instead, in integer arithmetic, and says so in a comment: it is faster on an 8-bit microcontroller and it never costs more than 0.013 °C, which is under the sensor's own resolution.
You have read the humidity bytes as temperature, or swapped the two bytes of a word. 0xFFFF through the temperature formula is 130 °C, so a humidity near 100 % decoded as temperature lands almost exactly there. Temperature is the first pair of bytes on the wire, not the second.
The library already does, and rejects the whole reading if either fails — that is what a failed read means. Writing your own decoder with Wire, you should: without it a single corrupted byte becomes a temperature that is wrong by tens of degrees and looks like a real number.
CRC-8 with polynomial 0x31, starting from 0xFF, with no final inversion. Sensirion gives a test vector in the datasheet: the two bytes 0xBE 0xEF must produce 0x92, and any implementation that gets that right will get the rest right.
Yes, and there is no sign bit involved. The formula subtracts 45, so any word below about 16,850 comes out negative — which is how one straightforward multiplication covers −45 °C to 130 °C with no special cases. The specified range is −40 to 125 °C.
Two obvious lines of sketch take two whole measurements, and the numbers they print came from different moments.
One measurement or two →Edit this page — content/books/sht31/from-bytes-to-degrees.mdx
Questions about this product
See what other owners have asked, and read their solutions.
SHT31 Temperature and Humidity Sensor
Loading 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.