0

The following code reads the DHT22 temperature and humidity values, assuming the pin value as the sensor's host pin.

When the temperature drops below 0°C, this code returns inadequate values in the range from -3200 to -3300 (most often the values range around -3275). When using a popular Adafruit library, the values are also incorrect. The code was not written by me, it originates from here, but the comments in the source are in Russian.

The problem is quite common, but there was no adequate solution provided in any case. It was mentioned in the Adafruit library issues quite a few times (here, here and here (related)), and on other websites. People even reported this issue on DHT11 and DHT21 sensors.

// "DHTLif.h"

#pragma once #include <Arduino.h> #include <Firmata.h>

uint64_t readingTime;

void DHTt(const uint8_t pin) { if ((millis() - readingTime) > 2000) { unsigned char receivedDHTData[5]; float temperature, humidity;

#define DHT_PORT PORTD
#define DHT_DDR DDRD
#define DHT_PIN PIND
#define DHT_BIT pin
int count = 32;
unsigned char i, j;

ReLoad: // Restarting point for error handling
//=============MCU send START
DHT_DDR |= (1 &lt;&lt; DHT_BIT); // exit
DHT_PORT &amp;= ~(1 &lt;&lt; DHT_BIT); // the pin's level is low, set it to high and wake up the sensor
delay(18); // 18 ms delay from the docs
DHT_PORT |= (1 &lt;&lt; DHT_BIT); // set the pin's level to low
DHT_DDR &amp;= ~(1 &lt;&lt; DHT_BIT); // the pin as exit

//=============Initialize DHT
delayMicroseconds(50); // delay from the docs
if (DHT_PIN &amp; (1 &lt;&lt; DHT_BIT)) { // DHT must return 0
  if (count != 0) {
    goto ReLoad;
    count--;
  } else {
    // send initialization error message
    Firmata.sendString(&quot;ERR;DHTt;INIT&quot;);
    return;
  }
}

delayMicroseconds(80);
if (!(DHT_PIN &amp; (1 &lt;&lt; DHT_BIT))) { // the bus must be set to 0 after 80 ms
  if (count != 0) {
    goto ReLoad;
    count--;
  } else {
    // send weird behaviour error message
    Firmata.sendString(&quot;ERR;DHTt;BHVR&quot;);
    return;
  }
}

//===============Receive 40 bits of data
while (DHT_PIN &amp; (1 &lt;&lt; DHT_BIT)); // wait until the bus is set to 1
for (j = 0; j &lt; 5; j++) { // loop for 0-4 bytes
  receivedDHTData[j] = 0;
  for (i = 0; i &lt; 8; i++) { // receive bits and pack them into bytes
    while (!(DHT_PIN &amp; (1 &lt;&lt; DHT_BIT))); // wait until the bus is set to 0
    delayMicroseconds(30); // 30 ms delay from the docs
    if (DHT_PIN &amp; (1 &lt;&lt; DHT_BIT)) // if the pin is 1 after the delay,
      receivedDHTData[j] |= 1 &lt;&lt; (7 - i); //set the i'th bit to 1
    while (DHT_PIN &amp; (1 &lt;&lt; DHT_BIT)); // wait until the bus is set to 0
  }
}

if ((unsigned char)(receivedDHTData[0] + receivedDHTData[1] + receivedDHTData[2] + receivedDHTData[3]) != receivedDHTData[4]) { // checksum
  Firmata.sendString(&quot;ERR;DHTt;CHSM&quot;);
  return;
}

temperature = (receivedDHTData[3] * 0.1) + ((receivedDHTData[2] &amp; 0b01111111) * 25.6); // calculating temperature for DHT22
if (receivedDHTData[2] &amp; 0b10000000) temperature *= -1; // if the temperature is negative
humidity = (receivedDHTData[1] * 0.1) + (receivedDHTData[0] * 25.6); //calculating humidity for DHT22

// form the final message
char result[32], catres[8];
readingTime = millis();
strcpy(result, &quot;OK;DHTt;&quot;);

dtostrf(temperature, 5, 2, catres);
strcat(result, catres);
strcat(result, &quot;;&quot;);
dtostrf(humidity, 5, 2, catres);
strcat(result, catres);
Firmata.sendString(result);
return;

} }

The only fix I found looks really silly and it does not work, the values don't drop below zero.

// The temperature is a 16 bit signed integer, 10 times the actual value in degrees Celsius
int16_t temperatureTimesTen = (int16_t)((receivedDHTData[2] << 8) | receivedDHTData[3]);
float temperature = (float)(temperatureTimesTen) * 0.1f;

// The maximum possible temperature for an DHT22 is 80 degrees Celsius if (temperature > 80) temperature = temperature - 3276.7f;

ocrdu
  • 1,795
  • 3
  • 12
  • 24
Starter
  • 153
  • 1
  • 13

2 Answers2

0

Looking at the data sheet (Page 3), the DHT22 uses, unlike the DHT11 and unlike the implementation in many libraries, a standard Base-2 format for the temperature. So converting the temperature should be as easy as:

// The temperature is a 16 bit signed integer, 10 times the actual value in degrees Celsius
int16_t temperatureTimesTen = (int16_t)((receivedDHTData[2] << 8) | receivedDHTData[3]);
float temperature = (float)(temperatureTimesTen) * 0.1;

I was not able to confirm this yet (couldn't get my sensor cold enough), but your observation that the wrong values report as being in the order of -3300 point to the same conclusion.

EDIT

I need to correct myself. The documentation is misleading, therefore my understanding of it was incorrect. After I finally got the possibility to really test my DHT22 in negative temperatures (it's snowing outside now), I found the correct formula to be:

int temp = ((receivedDHTData[2] & 0x7F) << 8 | receivedDHTData[3]) * 0.1;
// if MSB = 1 we have negative temperature
temp = ((receivedDHTData[2] & 0x80) == 0 ? temp : -temp);

return temp; // in degrees celsius

EDIT 2

For this particular sensor, decoding seems to be as follows. It appears that on negative temperatures, the resolution is only 1 degree, not 0.1 degrees.

float temperature = 0;
int32_t temp = ((receivedDHTData[2]) << 8 | receivedDHTData[3]);
// if MSB = 1 we have negative temperature
if (temp & 0x8000)
{
    temp = temp | 0xFFFF0000; // sign-extend
    temperature = temp; // Convert to negative whole-degrees
}
else
{
    temperature = (float)temp / 10.0f;
}
PMF
  • 1,306
  • 5
  • 24
0

I ran into this issue of getting -3200 values. I swapped the sensor with another one from the same vendor (Tenstar Robot on aliexpress.com), and the values for the 2nd sensor were normal. I put a regular thermometer next to the sensor and the reading are within a couple of degree of each other at -15 °C. I am supplying my sensors with 3.3 volts which in some cases can also cause issues. Might be worth trying 5 volts to see it that makes any difference.

Greenonline
  • 3,152
  • 7
  • 36
  • 48