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

I made it work:

Retrieving information from sensor: Read sensor: Error

	Checksum error
Humidity (%): -1.00
Temperature (oC): -1.00
Temperature (oF): -1.00
Temperature (K): -1.00
Dew Point (oC): -1.00
Dew Point Slow (oC): -1.00
Printing vars:
bits[0]: 2
bits[1]: 92
bits[2]: 80
bits[3]: F1
bits[4]: 85
sum: 517
idx: 5
cnt: 7
--------------

is basically the same, and as you report it has type errors
I'm analyzing the output that you give to me

update: great, now i have two output to see what is happening! Be patient

there is something strange, how do you managed to print the sum, 'cause I realize that sum is a local var. Another thing is that the sum in some cases is bigger than 256 and sum is a uint_8 so just for test purpose I make it class global and set as int and added more info to print. So can you try this new code?

Oh, I added all the numbers together again. That's a good point :slight_smile:

Retrieving information from sensor: Read sensor: Error

	Checksum error
Humidity (%): -1.00
Temperature (oC): -1.00
Temperature (oF): -1.00
Temperature (K): -1.00
Dew Point (oC): -1.00
Dew Point Slow (oC): -1.00
Printing vars:
bist[0]: 0x2 d2
bist[1]: 0xFC dFC
bist[2]: 0x80 d80
bist[3]: 0xF3 dF3
bist[4]: 0x71 d71
sum: 0x271 d625
idx: 5
cnt: 7

It seems that there is a mistake with dec/hex but doesn't matter too much :slight_smile:

OK, apparently the bug in first place was the first 40ms delay in the acquire method. And for the checksum error is that sometimes the sum var can be more than 256, so we have to make an and to 0xFF before compare to bits[4]
I updated the branch so can you test it again, and hopefully work this time.

In a loop:

Retrieving information from sensor: Read sensor: OK
Humidity (%): 65.70
Temperature (oC): -23.20
Temperature (oF): -9.76
Temperature (K): 249.95
Dew Point (oC): -27.81
Dew Point Slow (oC): -27.84
Printing vars:
bist[0]: 0x2 d2
bist[1]: 0x91 d91
bist[2]: 0x80 d80
bist[3]: 0xE8 dE8
bist[4]: 0xFB dFB
sum: 0xFB d251
idx: 5
cnt: 7

Temperature may need to be flipped to be accurate, not sure what normal temperature is, but I have two sensors so I may be able to compare outputs :slight_smile:

Retrieving information from sensor: Read sensor: OK
Humidity (%): 65.20
Temperature (oC): -23.30
Temperature (oF): -9.94
Temperature (K): 249.85
Dew Point (oC): -27.98
Dew Point Slow (oC): -28.01
Printing vars:
bist[0]: 0x2 d2
bist[1]: 0x8C d8C
bist[2]: 0x80 d80
bist[3]: 0xE9 dE9
bist[4]: 0xF7 dF7
sum: 0xF7 d247
idx: 5
cnt: 7
--------------
==============dht2================
40
2, 8F, 0, E2, 73 =? 173
Humidity: 65.50 %	Temperature: 22.60 *C
=================================

But I'm getting checksum errors a lot on the first DHT sensor which I guess indicates the timing might be off still.

this output is for what sensor?, i get confused

The second sensor is the other DHT22 sensor I have on my Arduino board, I am using the Adafruit lib for it. It's showing output for the first sensor and then the second. The first one is using your lib. I hacked the second sensor into the example :slight_smile:

Here is the full output: Paste.ee - View paste wDbxJ

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?