niesteszeck / idDHTLib

DHT11 & DHT22 interrupt driven library for arduino
GNU Lesser General Public License v3.0
18 stars 10 forks source link

DHT11 code assumes no decimal part for Temp but is not correct #14

Open naylom opened 6 years ago

naylom commented 6 years ago

The code in the acquiring function ignores two of the 5 bytes returned by a DHT11 on the assumption neither temperature nor humidity results will have a decimal component. This is not correct for the DHT11 part I have (for Temperature anyway) and also contradicts the spec to be found here http://www.micropik.com/PDF/dht11.pdf. Maybe later models are better implementing the spec? Either way ignoring the decimal component in the Temp field creates an incorrect checksum error.

Not an error, but the sum field in the acquiring function is declared as an unsigned 8 bit field so the instruction to mask it using & 0xFF has no effect. Effectively this is just wasting processing cycles.

niesteszeck commented 6 years ago

Hi @naylom, as you can see, this issue was already reported on the base lib idDHT11 and I suppose it will be reported also on the base IDHT11 library (the original not interrupt driven). As I mention at the issue from iDHT11, this behaviour is new on DHT11. Actually I discovered that this special or new version of the DHT11 has more accuracy in temp, it pass from 1° to 0.1 accuracy (maybe wrong in the number, fragile memory. but at least from decimal to float), so it need the extra byte. Also I suggest to add a new type of sensor to this lib that make the correct calculations. I hope someone can give as some code (pr) that add this new sensor model capability as a new sensor.

naylom commented 6 years ago

Hi @niesteszeck, I see the earlier issue - thanks. I am new to GitHub and not sure the best way to help. I can supply amended code to resolve the issue based on this library if wanted. I am not clear why a new sensor type (model) would be needed as it would be possible to change the acquiring function to use the 'decimal' bytes. On original models of DHT11 these are zero (based on the comments in the code) so will have no impact but the code will now support both variants of this sensor. Given how hard it is to detect the different sensor from the packaging especially when it has a protective cover this approach will make the code agnostic to the variant and easier to use.

niesteszeck commented 6 years ago

Hi. All help is welcome (report issues, translations, corrections, pr, etc). One way you could suggest a change in a project, is making a PR (fork a repo, make the modifications, and create a pull request to tell the owners/maintainers of a project to accept your changes).

I'm not sure how much it will impact the code (talking about time of execution), test will be needed to be sure. But as a premise, I avoid making some calculations with floats, module and others expensive work on microprocessor when can, as they have limited resources and time is always a concern.

this should work, please try it on .cpp

    if (sensorType == DHT22) {
        hum = word(bits[0], bits[1]) * 0.1;
        temp = (bits[2] & 0x80 ?
                -word(bits[2] & 0x7F, bits[3]) :
                word(bits[2], bits[3]))
               * 0.1;
        sum = bits[0] + bits[1] + bits[2] + bits[3];
      } else if (sensorType == DHT11b) {
        hum = bits[0];
        // as bits[1] is always zero, is omitted in formulas.
        temp = (bits[2] & 0x80 ?
                -word(bits[2] & 0x7F, bits[3]) :
                word(bits[2], bits[3]))
               * 0.1;
        sum = bits[0] + bits[2] + bits[3];
      } else {
        hum    = bits[0];
        // as bits[1] and bits[3] are always zero they are omitted in formulas.
        temp = bits[2];
        sum = bits[0] + bits[2];
      }

on .h enum DHTType {DHT11, DHT11b, DHT22};

naylom commented 6 years ago

Hi,

I tried the code, the calculation for temp in DHT11b produces incorrect results; I found the following code worked. There may be better implementations but this does produce the correct result. temp = (float) bits [ 2 ] + ( (float) bits [ 3 ] * 0.1f ); the casting is not required by the compiler but I wanted to be explicit to show where it was being done.

That said, I am not sure why you would want a new sensorType to fix this issue. The code above would work for both DHT11 and DHT11b variants as bits[3] is zero on the original DHT11. In the original case this would be less efficient but if the processor can handle this for a DHT11b sensor it has capacity to handle it for a DHT11 sensor. Finally since it is very hard to visually detect the difference between DHT11 and DHT11b sensors the end user of the library might not know which to variant to select anyway.

niesteszeck commented 6 years ago

Hi,

Have you tried your code with temps < 0°?

Regarding your question about why to define a new sensor, the answer is the same to the question why to have defined DH11 and DHT22 as sensors. They are similar but not the same, and every microsecond you can save is welcome, a lot of times when making projects that are considerably big in size, required that you save processor/memory/resources every time you can. Even sometimes you hace to cut some code apart that isn't being using. You are working with very limited resources. Also, you can identify which model you have, looking at the datasheet or specs. If you see 1° accuracy, with 0..50° range, you are against the old DHT11, but if your sensor have 0.1° accuracy, with -20..60° you are against the new model, that requires the decimal part.

if with <0° you have some problems, try:

temp = (float) (bits[2] & 0x7F) + ( (float) bits[3] * 0.1f );
if (bits[2] & 0x80) { 
  temp *=-1;
}
naylom commented 6 years ago

Glad you asked about below zero. I hadn't tried that and indeed got some strange results. With this sensor model when it goes below it sets the MSB on the fourth byte to 1 i.e. bit [3] not bit [2]. Furthermore the decimal value in the last 4 bits of bit [3] is a weird sort of decimal complement.

So for example when it gets to 0 Celsius, bit [2]=0x0, bit[3] = 0x0, at -0.2C you get bit[2]=0x0, bit[3]=0x88! for -0.4C you get bit[2]=0x0, bit[3]=0x86, so to get the correct negative temp you do a logical AND of bit[3] with 0x0f and then the decimal part of a negative result is (10 - (bit[3] & 0x0f) )* 0.1f.

Don't shoot the messenger :-)

niesteszeck commented 6 years ago

Wow. so is really different sensor, do you have the datasheet? any part number references (upload some good quality fotos)??

We are walking blind here without a datasheet, so please find it so I can help you work your sensor in all the range.

naylom commented 6 years ago

The sensor came as part of a kit from elegoo; it is described as a DHT11 sensor and unfortunately there is no datasheet. Here is a link to a photo. Not sure its much help in seeing the embedded sensor.

https://photos.app.goo.gl/4PCvQWlJrwEfjzDy1

niesteszeck commented 6 years ago

Hi, bad luck you can find any reference. Can you try (carefully) to see if there are some numbers in the back of the sensor and on back of the board the sensor is attached.

PD: you can upload pictures here to.

naylom commented 6 years ago

Got some info from back of sensor (https://photos.app.goo.gl/iJNSGdzpacH1HTls2) Seems to be a model DHT11 from ASAIR ?

niesteszeck commented 6 years ago

Effectively is the same I have previously found here. There I asked @daniel-123 if he can try this lib and set up the sensor as a DHT22, can you try this, and see the temps readings you get on -2 to 0 and on positive side to?

niesteszeck commented 6 years ago

I found the company, but unfortunately they only provide a not English version of the datasheet.

On the English version of the site, the is no download for this sensor. Tried to contact the manufacturer, I'll keep you informed.

naylom commented 6 years ago

I also found the company through http://www.aosong.com/en/products/details.asp?id=109 Not quite the same named product but it has an email address at the end. I have contacted this person as well. I will try the lib and let you know