RobTillaart / DHT20

Arduino library for DHT20 I2C temperature and humidity sensor.
MIT License
22 stars 6 forks source link

[ESP8266] Sensor Values are not Updated until resetSensor() is Called #8

Closed r0bc94 closed 1 year ago

r0bc94 commented 1 year ago

Hello,

first, sorry for the premature issue creation without any description. I've accidentally hit the "Create Issue" button.

In order to try out your library, I wrote a fairly simple program based on your examples to gather the temperature values on my DHT20. The code looks like so:

void setup() {
  // put your setup code here, to run once:
  Serial.begin(74880);
  dht20.begin(SERIAL_DATA_PIN, SERIAL_CLOCK_PIN);
}

void loop() {
  // put your main code here, to run repeatedly:

  // dht20.resetSensor(); <-- Without this, the read value would always be the same, even if read() returns 0.
  uint8_t read_status = dht20.read();
  if (read_status != DHT20_OK) {
    Serial.printf("Failed to read from DHT22 - Status: %d", read_status);
  }

  float humid = dht20.getHumidity();
  float temp = dht20.getTemperature();

  Serial.printf("Temperature: %f Humid: %f\n", temp, humid);

  delay(5000);
}

When commenting out the resetSensor() method, the getX() - Methods will always return the same value, even if read() is called before. In order for to get an updated value, I have to call resetSensor() in each iteration.

For me this makes sense, as in the read procedure described in the DHT20 Datasheet, you have to initialize the Sensor before each read by sending the 0x71 command and checking the return value. I've glanced over you code but I could not find such call, neither in the begin() nor in the read() method. Again, I could be wrong here but in my understanding, the calibration of the sensor must be checked before each read.

I am using an ESP8266 micro controller (Wemos D1 Mini). Maybe this behavior is also different on other MCUs.

RobTillaart commented 1 year ago

Thanks for reporting this issue. I need to check the datasheet, might take a few days.

RobTillaart commented 1 year ago

Found a sensor, so did a testrun with an Arduino UNO and example DHT20.ino and library version 0.1.4

image

Breathing against the sensor to change the temperature and humidity, seems to work pretty well.

RobTillaart commented 1 year ago

first, sorry for the premature issue creation without any description. I've accidentally hit the "Create Issue" button.

No problem

Can you try just one the DHT20.ino example?

I notice a fairly strange baudrate in your code, any specific reason? just curious, has nothing to do with the bug.

RobTillaart commented 1 year ago

I ran your test-sketch on an UNO and indeed it hangs ... added 2 lines and it worked.

I modified your sketch to this, please give it a try.


#include "DHT20.h"

DHT20 dht;20;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(74880);
  dht20.begin(SERIAL_DATA_PIN, SERIAL_CLOCK_PIN);

  Wire.setClock(400000);    //  <<<<<<<<<<<<<<<<<<<<<<<<  
  delay(1000);    //  <<<<<<<<<<<<<<<<<<
}

void loop() {
  // put your main code here, to run repeatedly:

  // dht20.resetSensor(); <-- Without this, the read value would always be the same, even if read() returns 0.
  uint8_t read_status = dht20.read();
  if (read_status != DHT20_OK) {
    Serial.printf("Failed to read from DHT22 - Status: %d", read_status);
  }

  float humid = dht20.getHumidity();
  float temp = dht20.getTemperature();

  Serial.printf("Temperature: %f Humid: %f\n", temp, humid);

  delay(5000);
}

give it a try

RobTillaart commented 1 year ago

If I use

Wire.setClock(100000): 

it hangs... so there is something wrong in the I2C communication.

Wire.setClock(200000); works

RobTillaart commented 1 year ago

@r0bc94 if you run your sketch, what does the output looks like?

RobTillaart commented 1 year ago

@r0bc94

For me this makes sense, as in the read procedure described in the DHT20 Datasheet, you have to initialize the Sensor before each read by sending the 0x71 command and checking the return value. I've glanced over you code but I could not find such call,

mmm I do not call it in DHT20.ino and it still works.

It is in line 238 in readStatus()

uint8_t DHT20::readStatus()
{
  _wire->beginTransmission(DHT20_ADDRESS);
  _wire->write(0x71);
  _wire->endTransmission();
  delay(1);  //  needed to stabilize timing
  _wire->requestFrom(DHT20_ADDRESS, (uint8_t)1);
  delay(1);  //  needed to stabilize timing
  return (uint8_t) _wire->read();
}
RobTillaart commented 1 year ago

No clue yet, the Wire.setClock() does somehow tickle the sensor, but even from the low level code I got no clue.

There should be at least some notes added in the readme.md file.

RobTillaart commented 1 year ago

For me this makes sense, as in the read procedure described in the DHT20 Datasheet, you have to initialize the Sensor before each read by sending the 0x71 command and checking the return value.

Datasheet is only referring to power-on process, not to every read (or I missed it)

7.4 Sensor Reading Process 1.After power-on, wait no less than 100ms. Before reading the temperature and humidity value, get a byte of status word by sending 0x71. If the status word and 0x18 are not equal to 0x18, initialize the 0x1B, 0x1C, 0x1E registers, details ... Note: The calibration status check in the first step only needs to be checked when the power is turned on. No operation is required during the acquisition process.

r0bc94 commented 1 year ago

Thank you for your response. Unfortunately, I'm currently away and will be back home to test this in a few days.

I notice a fairly strange baudrate in your code, any specific reason? just curious, has nothing to do with the bug.

I've set this baudrate to be able to see the debug messages and stack traces which are generated by the eps8266. Those information are only send with the given baudrate. I don't really know why its such a "strange" Baudrate. This Stackoverflow reply suggest that it has something to do with the crystal oscillator used for the esp: https://stackoverflow.com/a/41011637 (Please note that I'm not very experienced).

Again, I've I'm back home I also try out the different i2c speeds.

Datasheet is only referring to power-on process, not to every read (or I missed it)

Its possible that I got this wrong and the issue I'm seeing has a totally different cause.

~However I'm wondering where such initial call (aka after powering everything on) is executed in your Library. In my understanding, what happens when generating a measurement is the following:~ ~1. When initially calling begin() the i2c Bus is set up and the start sequence is executed

  1. When calling read(), the read - Command 0xAC together with both fixed parameters is send to the sensor
  2. After the sensor is ready, the results are read from the sensor~

~However, I dont't see the initial execution of this mentioned calibration sequence (sending 0x71 and comparing the return value) anywhere except in the dedicated resetSensor() method. Again, I'm not really experienced and might have missed this.~

Sorry, I've missed your reply and the part, where 0x71 is basically send to the sensor in the isMeasuring() method. However, the Status command is only queried after the measurement has started. In regards to the Datasheet, I still did not find that 0x71 is executed before the read - command.

RobTillaart commented 1 year ago

You ask good questions, and you analyze the code quite well. I will try to find some answers tomorrow as it is unclear what causes the hanging sensor. And why the i2c speed makes things work.

need to create a test (or more) to see why the sensor gives one meaningful fixed value if frozen. A fixed random value would be less unexpected.

To be continued tomorrow.

RobTillaart commented 1 year ago

@r0bc94 Did several tests with following results

I will create a 0.2.0 version which embeds resetSensor() in every requestData() so it is checked before every read, both synchronous and asynchronous.

RobTillaart commented 1 year ago

Created a new branch - https://github.com/RobTillaart/DHT20/tree/develop Will be merged later today ==> new version 0.2.0

r0bc94 commented 1 year ago

Hello, thank you. I will probably be able to test this in todays evening when I'm back home. But I'm confident that this will fix the issue.

RobTillaart commented 1 year ago

But I'm confident that this will fix the issue.

Me too, that's why I ask someone else to verify ...

r0bc94 commented 1 year ago

I've again tried out your new version on the develop branch and this seems to have fixed this issue. Now the sensor readings are changing after each read() as expected :smile: .

RobTillaart commented 1 year ago

Super, will merge after my current task Thanks for testing!

shuyuan-liu commented 1 year ago

Just found this issue today when looking for a driver for the DHT20. I'd like to add that the 0x71 referred to in the datasheet is really the sensor's I2C address + the read bit (0x38 << 1) | 0x1 == 0x71, and is not a command to be written after the address is sent. When the datasheet says:

Before reading the temperature and humidity value, get a byte of status word by sending 0x71. If the status word & 0x18 are not equal to 0x18, ...

what they meant is most probably to just read a status byte before triggering each measurement (and set up some registers if needed; see datasheet). Therefore line 229 below is in fact sending an invalid command:

https://github.com/RobTillaart/DHT20/blob/bf043d8b9e52c31e81e97e67f147a1d5b9b20b36/DHT20.cpp#L226-L235

This might be why the sensor hangs, but I still need to probe the I2C wires to see what's really going on. I'll add an update if I find anything.

RobTillaart commented 1 year ago

what they meant is most probably to just read a status byte before triggering each measurement (and set up some registers if needed; see datasheet). Therefore line 229 below is in fact sending an invalid command:

OK that would mean that it would be enough to just call requestFrom() to read the data.

uint8_t DHT20::readStatus()
{
  _wire->requestFrom(DHT20_ADDRESS, (uint8_t)1);
  delay(1);  //  needed to stabilize timing
  return (uint8_t) _wire->read();
}

I'll try to verify this asap.


This might be why the sensor hangs, but I still need to probe the I2C wires to see what's really going on. I'll add an update if I find anything.

Thanks for diving into this issue, always interested in new insights.

RobTillaart commented 1 year ago

@shuyuan-liu Testrun with DHT20_I2C_speed.ino on an UNO

DHT20_I2C_speed.ino
DHT20 LIBRARY VERSION: 0.2.0

NOTE: datasheet states 400 KHz as maximum.

50000   0       56.5    20.2
100000  0       56.2    20.3
150000  0       55.9    20.3
200000  0       55.7    20.2
250000  0       55.6    20.2
300000  0       55.5    20.3
350000  0       56.8    20.3
400000  0       63.4    20.3
450000  0       65.2    20.3
500000  0       64.6    20.3
550000  0       63.5    20.3
600000  0       65.4    20.6
650000  0       77.4    21.2  <<<<  breathing towards the sensor
700000  0       82.8    21.2
750000  0       85.5    21.3
800000  0       87.0    21.3

done...
RobTillaart commented 1 year ago

@shuyuan-liu So apparently your interpretation is better. The four lines of code are not needed.

I'll make a PR for this a.s.a.p.

RobTillaart commented 1 year ago

image

(page 11 datasheet)

The white byte = I2C address + read == 0x71. The first byte is the status byte followed by hum + temp etc.

RobTillaart commented 1 year ago

@shuyuan-liu

PR created here - https://github.com/RobTillaart/DHT20/pull/10 Please verify if the develop branch works for you.

shuyuan-liu commented 1 year ago

@RobTillaart latest develop branch works with esp8266, thanks! I also tested various clock speeds mentioned in the Arduino Wire documentation and they all work, for both master and develop:

Set Clock Speed Measured Clock Speed Works?
10000 (10 k) 7.14 k :heavy_check_mark:
100000 (100 k) 76 k :heavy_check_mark:
40000 (400 k) 358 k :heavy_check_mark:

This is different from your results where 100 k or below didn't work, would you mind testing the different speeds again?

RobTillaart commented 1 year ago

his is different from your results where 100 k or below didn't work, would you mind testing the different speeds again?

I did just an hour ago see a few posts back. FIrst column is the I2C speed.

shuyuan-liu commented 1 year ago

Oops sorry I missed that!

RobTillaart commented 1 year ago

No problem, happens to me all the time :)

Do you think the develop can be merged? Besides the removed lines there is no big change (getAddress() which is a no brainer + some minor edits)

shuyuan-liu commented 1 year ago

The code looks OK to me. As you said no big changes so probably can be merged.

RobTillaart commented 1 year ago

Merged, build is running, released as 0.2.1