DTH11 gets too short start impulse
arnowa opened this issue · 16 comments
I just tried this library with a DHT11. Did not work. A test with an oscilloscope showed a LOW pulse of just 3.3ms, while the DHT11 needs 18ms.
The problem seems to be calling delayMicroseconds() with a value larger than 16383: https://www.arduino.cc/reference/en/language/functions/time/delaymicroseconds/
A very simple fix is (line 329 in dhtnew.cpp):
delayMicroseconds(_wakeupDelay * 1100UL);
->
delayMicroseconds(_wakeupDelay * 550UL);
delayMicroseconds(_wakeupDelay * 550UL);
Thank you for reporting plus providing a simple solution.
Which processor do you use?
Which IDE version/ develop platform?
Thanks
There is a related issue with the delayMicroseconds(18000).
Some applications using RTOS need to call yield() for context switching, e.g. to handle a Wifi incoming buffer etc.
So the solution will be something more "complicated" than just splitting the call.
@arnowa
Created a Pull Request #73 with a rewrite of the wake-up delay.
Please verify if this fix works for you.
Replaced the delayMicroseconds(_wakeupDelay * 1100UL);
with a loop that calls yield() every iteration.
For a DHT22 alike it will be called only once, for the DHT11 alike it will be called 18 times.
// WAKE UP - add 10% extra for timing inaccuracies in sensor.
uint32_t startWakeup = micros();
do
{
// HANDLE PENDING IRQ
yield();
delayMicroseconds(1100UL);
}
while((micros() - startWakeup) < (_wakeupDelay * 1100UL));
Non-RTOS environments (e.g. UNO) implement yield() as an empty function which will be optimized away.
Good point, could make it 550.
Which board do you use?
Which IDE?
plain cheapduino Uno R3 clone (i.e. ATMega 328) and latest Arduino IDE 1.8.19 on 64 bit Linux.
Thanks.
Did some math and every 360 us would match 18 x 1100 = 19.800 exactly. Given the loop has some overhead it would at most 'overflow' 359 us.
3x better than 1100.
plain cheapduino Uno R3 clone (i.e. ATMega 328) and latest Arduino IDE 1.8.19 on 64 bit Linux.
Ok that allows me to recreate/test a bit
Did some more math/testruns and came to 180.
For DHT11 ==> 19808 us
For DHT22 ==> 1104 us
So quite a perfect (including loop overhead).
// WAKE UP - add 10% extra for timing inaccuracies in sensor.
uint32_t startWakeup = micros();
do
{
// HANDLE PENDING IRQ
yield();
delayMicroseconds(180UL);
}
while((micros() - startWakeup) < (_wakeupDelay * 1100UL));
The problem seems to be calling delayMicroseconds() with a value larger than 16383: https://www.arduino.cc/reference/en/language/functions/time/delaymicroseconds/
The parameter of delayMicros() is unsigned int that implies one could go up to 65535
(it is hand-tuned code, so I stop digging)
parameter us is multiplied by 4 here causing overflow...
// the following loop takes 1/4 of a microsecond (4 cycles)
// per iteration, so execute it four times for each microsecond of
// delay requested.
us <<= 2; // x4 us, = 4 cycles
Solution merged in master