adafruit/DHT-sensor-library

Improvement: Not lock / hangs when DHT22 is still not ready.

Anyeos opened this issue · 3 comments

  • Arduino board: Bluepill STM32F103

  • Arduino IDE version (found in Arduino -> About Arduino menu): 1.8.13

  • List the steps to reproduce the problem below (if possible attach a sketch or
    copy the sketch code in too):

If I try to read the sensor before the two seconds delay after powering up the board, the library locks the entire program.
It may be of use if the library simply ignores the reading and do not lock the program flow.
The unlocking behaviour can help in situations where the sensors can get disconnected or can lost power or data conection randomly (or in a hot plug manner).
The actual behaviour of get locked on the read call can sometimes difficult debuging more complex applications. That was my situation where my applitacion worked while developing / programming but not on production (because I just powered the board some seconds before uploading the sketch, giving enouth time for the DHT being ready. But on production the program starts inmediately and don't give enough time for DHT being ready).

Of course, I must actually use a delay of two seconds before reading something from the sensor and it works for now.

Code example:

#include "DHT.h"

DHT dht(PA3, DHT22);

void setup() {
  Serial.begin(115200);
  Serial.println(F("DHTxx test!"));

  dht.begin();
}

void loop() {
  // Wait a few seconds between measurements.
  // Try without the delay and with the delay to test it
  // Don't forget to turn on the board and the sensor at the same time.
  //delay(2000);

  // 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 = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }

  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);

  Serial.print(F("Humidity: "));
  Serial.print(h);
  Serial.print(F("%  Temperature: "));
  Serial.print(t);
  Serial.print(F("°C "));
  Serial.print(f);
  Serial.print(F("°F  Heat index: "));
  Serial.print(hic);
  Serial.print(F("°C "));
  Serial.print(hif);
  Serial.println(F("°F"));
}

i think this is important, i was working on my program using dht22 and i try to see what happen if sensor is not connected, to create an error condition and programs gets lock. it would be appreciated if it returned value -1 for humidity when there is no reading and avoid any possible lock. i tried to follow this program to manually correct it but can't find where the lockdown happens.

After experimenting a bit more i get to the problem.
so the problem is in:
uint32_t DHT::expectPulse(bool level)
in DHT.cpp
the variable maxcycles gets the value 72000.
The count variable is an uint16_t (for slower cpu) so the value goes to 65536 ant it resets, and the while condition is count<maxcycles, that means that would never occur, and makes the program locks.
in normal functions the average cycles i'm getting is 38-39.

maxcycles gets its value in:
DHT::DHT(uint8_t pin, uint8_t type, uint8_t count)
and it is:
_maxcycles = microsecondsToClockCycles(1000);
So i get 72000 for max cycles as i'm using a 72Mhz clock board.
my board takes an average of 140ms to do a full 0-65535 cycle. so 1 cycle takes aprox 2.142 microseconds.
after reading the documentation of DHT22 the maximum time the sensor would hold a levle is 80 microseconds, aprox 38 cycles.
So its safe to assume that you can put 40 as the max cycles for this microcontroller. but to be safe, i'll just put 100.
So the change to the library should be in function:
DHT::DHT(uint8_t pin, uint8_t type, uint8_t count)
to the variable:
_maxcycles = microsecondsToClockCycles(1000); --> _maxcycles = 100; (The value depends on the micro)

To check cycle time in my microcontroller i use the same function the library use -->

`
unsigned long timer = millis();
_maxcycles = 72000;
uint16_t count = 0;

while (true)
{
if(count == 0)
{
unsigned long data = millis()-timer;
Serial.println(data);
timer=millis();
}
if (count++ >= _maxcycles)
{
return TIMEOUT; // Exceeded timeout, fail.
}
}
`
As there are 2^16 cycles before it reset, the value it would print would be cycleTime*2^16, so you just have to divide by 2^16.
Then you can calculate how many cycles it 80us would take and thats is your minimum _maxcycles value.
Don't know if there is a function that can get you the cycle time of each microcontroller. Also in this kind of time sensitive measures i put at least 2ble the minimum value as timeout.
I hope more people can benefit from my analisis.

just to add to the preview comment, now when i got no lecture it return float value nan, so i create de function:
`float h = dht.readHumidity(); //Leemos la Humedad
float t = dht.readTemperature(); //Leemos la temperatura en grados Celsius

if(isnan(h) || isnan(t)) 
{
    ErrorNoSensor = true;

}`

To check if i have sensor readings or not.