diff --git a/DHT.cpp b/DHT.cpp index 86ad91c..3641eac 100644 --- a/DHT.cpp +++ b/DHT.cpp @@ -134,38 +134,61 @@ boolean DHT::read(bool force) { // Send start signal. See DHT datasheet for full signal diagram: // http://www.adafruit.com/datasheets/Digital%20humidity%20and%20temperature%20sensor%20AM2302.pdf - - // Go into high impedence state to let pull-up raise data line level and - // start the reading process. - digitalWrite(_pin, HIGH); - delay(250); - - // First set data line low for 20 milliseconds. + // First set data line low to send start signal. pinMode(_pin, OUTPUT); digitalWrite(_pin, LOW); - delay(20); + // set wait time according to sensor type. + switch (_type) { + case DHT22: + case DHT21: + delayMicroseconds(1100); //data sheet says at least 1ms, 1.1ms should be ok + break; + case DHT11: + default: + delay(20); //data sheet says at least 18ms, 20ms just to be safe + break; + } uint32_t cycles[80]; { // Turn off interrupts temporarily because the next sections are timing critical // and we don't want any interruptions. + // NOTE: From this point we cannot use function such as delay(), delayMicroseconds(), + // Those functions among others rely on interrupts. InterruptLock lock; - // End the start signal by setting data line high for 40 microseconds. - digitalWrite(_pin, HIGH); - delayMicroseconds(40); - + // End of the start signal. // Now start reading the data line to get the value from the DHT sensor. pinMode(_pin, INPUT_PULLUP); - delayMicroseconds(10); // Delay a bit to let sensor pull data line low. + // from this point we listen, it's sensor's turn to talk. + + + // The following step is a busy-wait loop to resume processing only + // when the data line has been pulled LOW by the sensor. + // + // To avoid infinite loops here, we use a counter as a timeout. + // 700 iterations is about 4 ms on a 16Mhz processor. The sensor should + // set the pin LOW within 20 to 40 microseconds. + // The (F_CPU / 16000000.0) is a ratio to keep the timeout to approximately + // the same period if processor used runs at a different frequency. + unsigned long timesup = (F_CPU / 16000000.0) * 700; + unsigned long count = 0; + while (digitalRead(_pin) == HIGH && ++count < timesup) + ; + if (count == timesup) { + DEBUG_PRINTLN(F("Timeout waiting sensor to pull the data line LOW.")); + _lastresult = false; + return _lastresult; + } - // First expect a low signal for ~80 microseconds followed by a high signal - // for ~80 microseconds again. + // expect a low signal for ~80 microseconds. if (expectPulse(LOW) == 0) { DEBUG_PRINTLN(F("Timeout waiting for start signal low pulse.")); _lastresult = false; return _lastresult; } + + // followed by a high signal for ~80 microseconds. if (expectPulse(HIGH) == 0) { DEBUG_PRINTLN(F("Timeout waiting for start signal high pulse.")); _lastresult = false; @@ -184,7 +207,8 @@ boolean DHT::read(bool force) { cycles[i] = expectPulse(LOW); cycles[i+1] = expectPulse(HIGH); } - } // Timing critical code is now complete. + // Interrupts will turn back on when exiting this scope. + } // Timing critical code is now complete. // Inspect pulses and determine which ones are 0 (high state cycle count < low // state cycle count), or 1 (high state cycle count > low state cycle count).