DHT22 checksum error for negative temperatures

DrM

Well-known member
Hi,

I am using the DHTlib with a DHT22 and a Teensy 3.2. The code works okay for temperatures greater than 0C. However, when the temperature drops below 0C, it returns a checksum error. The datasheet for the sensor says it works over the range -40C to 80C.

So, is this a library problem, perhaps already known, or is something wrong with the sensor?

Code follows.

Thank you


Code:
#include <dht.h> 

dht DHT;
#define DHT22_PIN 7
#define DHTPWR 8

 pinMode(DHTPWR,OUTPUT);
 digitalWrite(DHTPWR,HIGH);  // +Vcc to DHT


     int chk = DHT.read22(DHT22_PIN);

      switch (chk)
	{
	case DHTLIB_OK:  
	  // DISPLAY DATA
	  h = DHT.humidity;
	  t = DHT.temperature;
	  sendprintf( (char *)"Temperature %.1f Humidity %.1f ", t, h );
	  break;
	case DHTLIB_ERROR_CHECKSUM: 
	  sendstring( (char *)"Error: DHT Checksum"); 
	  break;
	case DHTLIB_ERROR_TIMEOUT: 
	  sendstring( (char *)"Error: DHT Time out"); 
	  break;
	case DHTLIB_ERROR_CONNECT:
	  sendstring( (char *)"Error: DHT Connect");
	  break;
	case DHTLIB_ERROR_ACK_L:
	  sendstring( (char *)"Error: DHT Ack Low");
	  break;
	case DHTLIB_ERROR_ACK_H:
	  sendstring( (char *)"Error: DHT Ack High");
	  break;
	default: 
	  sendstring( (char *)"Error: DHT Unknown"); 
	  break;
	}
      
      sendstring( (char *)"done" );


For negative temperatures the
 
this DHT lib https://www.arduino.cc/reference/en/libraries/dhtlib/ says it is designed for AVR processors -- Teensy 3.2 is ARM not AVR. lib is using AVR registers for IO
Code:
    // replace digitalRead() with Direct Port Reads.
    // reduces footprint ~100 bytes => portability issue?
    // direct port read is about 3x faster
    uint8_t bit = digitalPinToBitMask(pin);
    uint8_t port = digitalPinToPort(pin);
    volatile uint8_t *PIR = portInputRegister(port);

as Pete suggests, try the adafruit DHT-sensor-library
 
If I thought it was a hardware problem, then trying another library might be a good way to check. But, I have two of these sensors, so maybe I'll just try the other one first.

I suspect it is not hardware. Hence the question, is this a known bug in the library? Maybe the author can answer.
 
@manitou and @el_supremoe Thank you, that makes sense now, I'll try it. It raises another question, why the incompatibility isnt flagged in the development environment.
 
@manitou and @el_supremo So, still not working.

The Adafruit DHT-sensor-library reports a temperature of -3272.4C.

An impressive and stunning repudiation of the third law of thermodynamics.

(Temperatures above 0C seem to be correct to reasonable accuracy).


Here are the relevant lines from the code:

Code:
#include "DHT.h

// DHT sensor
#define DHTPIN 7
#define DHTPWR 8
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);

/* I/O support
*/
int sendbuffer( void *p, size_t nlen ) {
  size_t written = 0;
  while( written != nlen ) {
    written += Serial.write( (char *)p+written, nlen-written);
  }
  return written;
}

int sendprintf( char *fmt, ... ) {
  va_list ap;
  char sbuf[128];
  int nlen;
  va_start(ap, fmt);
  nlen = vsnprintf(sbuf, sizeof(sbuf), fmt, ap);
  va_end(ap);
  sendbuffer(sbuf,nlen+1);
  return nlen;
}


void setup() {

  // ...

  pinMode(DHTPWR,OUTPUT);
  digitalWrite(DHTPWR,HIGH);  // +Vcc for DHT

  dht.begin();

  // ...
}

void loop() {

    // other stuff

   if ( commandmatch( command, 'temperature' ) ) {

      float h, t;

      h = dht.readHumidity();
      t = dht.readTemperature();
      
      if ( isnan(h) || isnan(t) ) {
	sendstring( (char *)"Error: Failed to read from DHT sensor");
      }
      else {
	sendprintf( (char *)"Temperature %.1f Humidity %.1f ", t, h );
      }
      
      sendstring( (char *)"done" );      

   }


  // more other stuff
}
 
Last edited:
Try this:
Code:
DHT dht(DHTPIN, DHTTYPE, 27);

and see my old thread about problems with the DHT22 on Teensy 3.

If that doesn't help, let's try adding a debugging print in the library. Near the end of the read() function in DHT.cpp is this comment:
Code:
  // check we read 40 bits and that the checksum matches
Put this print statement immediately before the comment:
Code:
  Serial.printf("DEBUG: %02X %02X %02X %02X : %02X\n",
				data[0],data[1],data[2],data[3] ,data[4]);

Pete
 
@el_supremo no luck, still shows -3272C.

DEBUG: 02 43 FF CF : 13
 
Last edited:
What is the actual temperature?

I'm suspicious that the device actually represents the temperature as twos-complement, whereas both libraries treat it as sign-magnitude.
If it is twos-complement, FFCF would represent a temperature of -4.9C (23.2F).
If that is correct, I'll work out a fix for the library.

Pete
 
Replace the debug printf with this which will add my interpretation of the temperature (I hope - untested):
Code:
  Serial.printf("DEBUG: %02X %02X %02X %02X : %02X (%6.2f)\n",
				data[0],data[1],data[2],data[3] ,data[4],
				((int16_t)((data[2]<<8) | data[3]))/10.;

Pete
 
Two thread on this?
As I mentioned in the other one there are several open issues on the Adafruit library about this as well as a Pull Request
 
@el_supremo I have to get the experiment started now, its getting late and i need it to finish by a certain time. But, fortunately, I do have another cold stage with another DHT22, so i'll get that started and continue working on this after the launch.
 
DEBUG: 03 E7 00 50 : 3A ( 8.00)
Temperature 8.0 Humidity 99.9


Unfortunately that cold stage is not going below 0C
 
@el_supremo, That is actually correct!!! (twos complement vs sign magnitude)

-4.9C is what I read previously with a thermistor and DVM.

I apologize (and regret) that I didnt parse the fine print sooner. I was in a hurry to get the run started (it's running with a thermistor).

Thank you for working on this, please do let me know when it is fixed.
 
@el_supremo

Here is a revision for your DHT.cpp to fix the problem for the DHT22. I tested it just now, it seems to work.

Aside, I read the data sheet, it does seem confusing on this point.


Code:
float DHT::readTemperature(bool S, bool force) {
  float f = NAN;

  int16_t i16temp;
  
  if (read(force)) {
    switch (_type) {
    case DHT11:
      f = data[2];
      if (data[3] & 0x80) {
        f = -1 - f;
      }
      f += (data[3] & 0x0f) * 0.1;
      if (S) {
        f = convertCtoF(f);
      }
      break;
    case DHT12:
      f = data[2];
      f += (data[3] & 0x0f) * 0.1;
      if (data[2] & 0x80) {
        f *= -1;
      }
      if (S) {
        f = convertCtoF(f);
      }
      break;
    case DHT22:
    case DHT21:
      i16temp = data[3] | (data[2] <<8) ;
      f = i16temp/10.;

      /*
      f = ((word)(data[2] & 0x7F)) << 8 | data[3];
      f *= 0.1;
      if (data[2] & 0x80) {
        f *= -1;
      }
      */
      if (S) {
        f = convertCtoF(f);
      }
      break;
    }
  }
  return f;
}
 
Yep. and it turns out to be very useful. How do we (or do we), get this into the code for the library? Also, I notice there are a few other cases where it assumes sign-magnitude. I can fix the other cold stage and check the DHT11 that I have here, but support for the other devices would seem to remain open. Perhaps a good solution would be to provide a switch in the API for 2s-complement vs sign-magnitude.
 
I see one potential problem with your fix. The DHT21 might use sign-magnitude in which case you would need to split the DHT21 and DHT22 cases so that they handle the negative numbers correctly for that device.

Pete
 
Of course, and perhaps that goes for any of them. Hence it seems like a good idea to add a parameter (perhaps in the class intializer) to select it manually.
 
Last edited:
I don't think that would be useful. Having an option of using sign-magnitude for the DHT22 is pointless and potentially confusing because it only uses twos-complement. Similarly, there's not much point having an option to read a DHT11 as twos-complement when it (apparently) uses sign-magnitude.

Pete
 
Well, it depends. Are the DHT22 reliably all twos-complement? And converse for the DHT11? Etc. And, besides number of bytes and sign versus 2's, are the devices different in any other way?

It seems like the error in the DHT22 perhaps was not picked up because it wasn't tested. So, we might not know what is going on with the others.
 
Back
Top