[LIB] Interrupt driven DHTLib (DHT11 & DHT22 = idDHTLib)

i don't understand why the second byte in the first sensor is 0x80 and on the second is 0x00.
if this byte[2]&0x80==0x80 means that is a negative temp, so I got why in the second one the byte is 0x00, but not why in the first is 0x80

can you change the order of the sensors?

I make another mod, but I don't have any hope that it will repar the - sing in temp. Can you try it?

if not work, i have my brain cooked for today, maybe tomorrow I get a new aproach

by

The sensors are getting data one after the other in the main loop -- I can change the order in the code, but not sure it will make a difference? I already applied all modifications -- the latest output is coming from the latest commit to dht22_bug_detect (#8374114) with some modifications to the example to support the second sensor.

I swapped the two sensors on the breadboard. Here is the output now:

Retrieving information from sensor: Read sensor: OK
Humidity (%): 65.00
Temperature (oC): -38.90
Temperature (oF): -38.02
Temperature (K): 234.25
Dew Point (oC): -42.96
Dew Point Slow (oC): -42.97
Printing vars:
bist[0]: 0x2 d2
bist[1]: 0x8A d8A
bist[2]: 0x81 d81
bist[3]: 0x85 d85
bist[4]: 0x92 d92
sum: 0x92 d146
idx: 5
cnt: 7
--------------
==============dht2================
40
2, 36, 0, FD, 35 =? 135
Humidity: 56.60 %	Temperature: 25.30 *C
=================================

Here is full output after I let it run a little while: Paste.ee - View paste fEpVh

Here's something to wrap your chops around: both sensors and both libs used in the same program :slight_smile: With proper delays.

Source code:

/*
  Board	          int.0	  int.1	  int.2	  int.3	  int.4	  int.5
 Uno, Ethernet	  2	  3
 Mega2560	  2	  3	  21	  20	  19	  18
 Leonardo	  3	  2	  0	  1
 Due	          (any pin, more info http://arduino.cc/en/Reference/AttachInterrupt)
 
 This example, as difference to the other, make use of the new method acquireAndWait()
 */

#include <idDHTLib.h>
#include <DHT.h>

#define DHTTYPE DHT22   // DHT 22  (AM2302)

//declaration
void dhtLib1_wrapper(); // must be declared before the lib initialization
void dhtLib2_wrapper(); // must be declared before the lib initialization

// Lib instantiate
idDHTLib DHTLib1(2,0,dhtLib1_wrapper);
idDHTLib DHTLib2(3,1,dhtLib2_wrapper);
DHT dht1(2, DHTTYPE);
DHT dht2(3, DHTTYPE);

void setup()
{
  Serial.begin(9600);
  Serial.println("idDHTLib Example program");
  Serial.print("LIB version: ");
  Serial.println(IDDHTLIB_VERSION);
  Serial.println("---------------");
  dht1.begin();
  dht2.begin();
  delay(3000); // The sensor need like 2 sec to initialize, if you have some code before this that make a delay, you can eliminate this delay
}
// This wrapper is in charge of calling 
// mus be defined like this for the lib work
void dhtLib1_wrapper() {
  DHTLib1.dht22Callback(); // Change dht11Callback() for a dht22Callback() if you have a DHT22 sensor
}
void dhtLib2_wrapper() {
  DHTLib2.dht22Callback(); // Change dht11Callback() for a dht22Callback() if you have a DHT22 sensor
}
void loop()
{ 
  {
  Serial.println("============= DHTLib DHT 1 =============");
  Serial.print("\nRetrieving information from sensor: ");
  Serial.print("Read sensor: ");
  //delay(100);
  
  int result = DHTLib1.acquireAndWait();
  switch (result)
  {
  case IDDHTLIB_OK: 
    Serial.println("OK"); 
    break;
  case IDDHTLIB_ERROR_CHECKSUM: 
    Serial.println("Error\n\r\tChecksum error"); 
    break;
  case IDDHTLIB_ERROR_TIMEOUT: 
    Serial.println("Error\n\r\tTime out error"); 
    break;
  case IDDHTLIB_ERROR_TIMEOUT_2: 
    Serial.println("Error\n\r\tTime out error 2"); 
    break;
  case IDDHTLIB_ERROR_TIMEOUT_3: 
    Serial.println("Error\n\r\tTime out error 3"); 
    break;
  case IDDHTLIB_ERROR_ACQUIRING: 
    Serial.println("Error\n\r\tAcquiring"); 
    break;
  case IDDHTLIB_ERROR_DELTA: 
    Serial.println("Error\n\r\tDelta time to small"); 
    break;
  case IDDHTLIB_ERROR_NOTSTARTED: 
    Serial.println("Error\n\r\tNot started"); 
    break;
  default: 
    Serial.println("Unknown error"); 
    break;
  }
  Serial.print("Humidity (%): ");
  Serial.println(DHTLib1.getHumidity(), 2);

  Serial.print("Temperature (oC): ");
  Serial.println(DHTLib1.getCelsius(), 2);

  Serial.print("Temperature (oF): ");
  Serial.println(DHTLib1.getFahrenheit(), 2);

  Serial.print("Temperature (K): ");
  Serial.println(DHTLib1.getKelvin(), 2);

  Serial.print("Dew Point (oC): ");
  Serial.println(DHTLib1.getDewPoint());

  Serial.print("Dew Point Slow (oC): ");
  Serial.println(DHTLib1.getDewPointSlow());

  DHTLib1.printVars();
  
  Serial.println("==========================================");
  }
  Serial.println();
  {
  Serial.println("============= DHTLib DHT 2 =============");
  Serial.print("\nRetrieving information from sensor: ");
  Serial.print("Read sensor: ");
  //delay(100);
  
  int result = DHTLib2.acquireAndWait();
  switch (result)
  {
  case IDDHTLIB_OK: 
    Serial.println("OK"); 
    break;
  case IDDHTLIB_ERROR_CHECKSUM: 
    Serial.println("Error\n\r\tChecksum error"); 
    break;
  case IDDHTLIB_ERROR_TIMEOUT: 
    Serial.println("Error\n\r\tTime out error"); 
    break;
  case IDDHTLIB_ERROR_TIMEOUT_2: 
    Serial.println("Error\n\r\tTime out error 2"); 
    break;
  case IDDHTLIB_ERROR_TIMEOUT_3: 
    Serial.println("Error\n\r\tTime out error 3"); 
    break;
  case IDDHTLIB_ERROR_ACQUIRING: 
    Serial.println("Error\n\r\tAcquiring"); 
    break;
  case IDDHTLIB_ERROR_DELTA: 
    Serial.println("Error\n\r\tDelta time to small"); 
    break;
  case IDDHTLIB_ERROR_NOTSTARTED: 
    Serial.println("Error\n\r\tNot started"); 
    break;
  default: 
    Serial.println("Unknown error"); 
    break;
  }
  Serial.print("Humidity (%): ");
  Serial.println(DHTLib2.getHumidity(), 2);

  Serial.print("Temperature (oC): ");
  Serial.println(DHTLib2.getCelsius(), 2);

  Serial.print("Temperature (oF): ");
  Serial.println(DHTLib2.getFahrenheit(), 2);

  Serial.print("Temperature (K): ");
  Serial.println(DHTLib2.getKelvin(), 2);

  Serial.print("Dew Point (oC): ");
  Serial.println(DHTLib2.getDewPoint());

  Serial.print("Dew Point Slow (oC): ");
  Serial.println(DHTLib2.getDewPointSlow());

  DHTLib2.printVars();
  
  Serial.println("==========================================");
  dht1.begin();
  dht2.begin();
  delay(2500);
  }
  Serial.println();
  {
  Serial.println("============= adafruit dht #1 ============");
  
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht1.readHumidity();
  float t = dht1.readTemperature();

  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (isnan(t) || isnan(h)) {
    Serial.println("Failed to read from DHT");
  } else {
    Serial.print("Humidity: "); 
    Serial.print(h);
    Serial.print(" %\t");
    Serial.print("Temperature: "); 
    Serial.print(t);
    Serial.println(" *C");
    Serial.println("==========================================");
  }
  
  }
  Serial.println();
  {
  Serial.println("============= adafruit dht #2 ============");
  
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht2.readHumidity();
  float t = dht2.readTemperature();

  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (isnan(t) || isnan(h)) {
    Serial.println("Failed to read from DHT");
  } else {
    Serial.print("Humidity: "); 
    Serial.print(h);
    Serial.print(" %\t");
    Serial.print("Temperature: "); 
    Serial.print(t);
    Serial.println(" *C");
    Serial.println("==========================================");
  }
  
  Serial.println();
  }
  
  delay(2500);
}

Looks like the temp is calculated right and only the negative is wrong.
Is strange 'cause if we received a 0x00 on byte 2, then the checksum is going to fail, so we can assume that the bits are interpreted in the right way, but maybe we are in some rarely and not probably case that the interpretation of bits get a good checksum not matter the error, maybe the error is repeated in some bits so the checksum compare get right.

I made some mods, but still not hope to get a solution, sorry. Can you try it, there are 3 new commits

Yeah, the checksum seems nearly useless, considering it is letting invalid values through somehow :slight_smile: I'll test the new commits when I get home.

Fresh output for ya: Paste.ee - View paste EBsnD

on line 181 and 484 there is a good reading, and now there is a lot more checksum errors, so I suspect that is a small timing issue. It'll be a good think to do as next step to see the signal with a logic analyzer or an oscilloscope( if you have one, send me an screenshot and the serial output to analyse it, the output generated when you take the screenshot), to see the exact timing and which bit is interpreted in a wrong way.

If you don't have this kind of tools the only thing that we can do is to play with the timing numbers, If I make a change it take some time to you to get it, so I recommend you to try different timing numbers to always get all bits right. The important numbers are the ones on lines:

line 98 } if(125<delta && delta<190) {
The start signal from the sensor takes 80us down and 80us up, so this range should be good, and I don't think this part is failing, 'cause we are not getting an timeout error.

line 113 if(delta>95) //is a one
for a 0 the sensor put down the signal for 50us and then up for 22-28us and for a 1 it puts the signal low for the same 50us and then up for 70 more us. So I think 95us of delta should be enough to discriminate between a 1 an a 0, but apparently isn't (that's why I recommend to see the signal in an oscilloscope) (or try with an 100)

line 111 } else if(60<delta && delta<145) { //valid in timing
In this line we check that the timing is between an acceptable range, that can be a 0 or a 1.

So you can play with this numbers and make a try and error test to get good values for the sensor. Just remember that the lib use the falling edge to call the interrupt and that's why it checks the timing adding the low signal time plus the high signal time.

An optimization that you can try to, is to pass the if on line 107 if(delta<10) { after the if in line 111 } else if(60<delta && delta<145) { //valid in timing so the error if (line 107) will be checked only if there is an error in timing, saving us a little bit of time. I'll do this on the main branch so you can look at it if you don't understand this proposal.

more info

I don't have an oscilloscope sorry :frowning: But wouldn't it be possible to query the Arduino using interrupts to work out where the signal is high and output all that, including delays between those signals?

With delta > 100 I seem to be receiving entirely correct data:

So it looks like everything is good now? Please check it over just to be sure :smiley:

Edit: it's also working perfectly in my 'big' app where I switched over to the interrupt version of the lib initially, it has LCD output :slight_smile: There are no CPU holdups.

SO NICE!!!!! Now I need to try it with my DH11 sensors, reorder the code to b pretty (not messy and for test purpose) and if my DHT11 is still working, we can say that the entire lib is working, really good news!!!!

you just change the 95 for a 100?
This means that the sensor is taking between 90 and 100 us to send a 0. With all the ping pong conversation that we had, I thing the DHT22 (or maybe just yours) is taking like 10us more in signaling.
really strange behavior and against the datasheet, but Arduino and a cheap sensor doesn't guaranties accurate in timing, so I suppose is a expected behavior.

if you use github, you can push the code with the last mods you make to get it working, so in the history will be your effort!

Ok :slight_smile: Will do!

Before you do it, let me make a branch for that, so is clean and not with all the not making difference commits

Finally is ready. Thanks All for the testig

Sorry it took so long to get the changes in there :slight_smile:

Is it worth implementing more robustness if the sensors are removed (i.e., some interrupt timeouts) -- experiment with disconnecting/reconnecting sensors and you'll see what I mean -- the Arduino seems to freeze. Could be my code though.

Can you report on github please, with the structure:

  • How to reproduce
  • What do you espect
  • What really happens

Dessimat0r:
I am using both the pull up resistor and cap :slight_smile: Like I say, no checksum errors or anything with the Adafruit lib, if the constructor is initialised in front of all the constructors (I removed parts of my code to find out which bit was causing the issues, and the two codes looked the same, except for the constructor order, and I thought 'hmmm, it couldn't be this, could it? that really makes no sense..'. But to rule out any memory issues I'll try it with the simple example.

Could you provide a schema of the pullup and cap ?

Thanks.