From f8f941ca0bbf4355e501493dd6c1e4df0a84b722 Mon Sep 17 00:00:00 2001
From: Jens Geisler <jens.geisler@web.de>
Date: Sat, 24 May 2014 22:12:51 +0200
Subject: [PATCH 1/4] corrected timing protocol

---
 DHT22.cpp                          |  85 +++++++++++-----------
 DHT22.h                            |  12 ++--
 README                             |  10 +++
 examples/TestTiming/TestTiming.ino | 110 +++++++++++++++++++++++++++++
 4 files changed, 166 insertions(+), 51 deletions(-)
 create mode 100644 examples/TestTiming/TestTiming.ino

diff --git a/DHT22.cpp b/DHT22.cpp
index f0e36cd..bf8910f 100644
--- a/DHT22.cpp
+++ b/DHT22.cpp
@@ -60,8 +60,7 @@ extern "C" {
 #define DIRECT_WRITE_LOW(base, mask)	((*(base+2)) &= ~(mask))
 //#define DIRECT_WRITE_HIGH(base, mask)	((*(base+2)) |= (mask))
 
-// This should be 40, but the sensor is adding an extra bit at the start
-#define DHT22_DATA_BIT_COUNT 41
+#define DHT22_DATA_BIT_COUNT (40)
 
 DHT22::DHT22(uint8_t pin)
 {
@@ -127,53 +126,63 @@ DHT22_ERROR_t DHT22::readData()
   cli();
   DIRECT_MODE_INPUT(reg, bitmask);	// Switch back to input so pin can float
   sei();
-  // Find the start of the ACK Pulse
+  
+  // Wait for hi level
   retryCount = 0;
-  do
-  {
+  do {
+    if (retryCount > 5) 
+      return DHT_BUS_HUNG;
+    retryCount++;
+    delayMicroseconds(2);
+  } while(!DIRECT_READ(reg, bitmask)); // while lo
+
+  // Wait for response
+  retryCount = 0;
+  do {
     if (retryCount > 25) //(Spec is 20 to 40 us, 25*2 == 50 us)
-    {
       return DHT_ERROR_NOT_PRESENT;
-    }
     retryCount++;
     delayMicroseconds(2);
-  } while(!DIRECT_READ(reg, bitmask));
-  // Find the end of the ACK Pulse
+  } while(DIRECT_READ(reg, bitmask)); // while hi
+
+  // ACK Pulse lo
   retryCount = 0;
-  do
-  {
+  do {
+    if (retryCount > 50) //(Spec is 80 us, 50*2 == 100 us)
+      return DHT_ERROR_ACK_TOO_LONG;
+    retryCount++;
+    delayMicroseconds(2);
+  } while(!DIRECT_READ(reg, bitmask)); // while lo
+
+  // ACK Pulse hi
+  retryCount = 0;
+  do {
     if (retryCount > 50) //(Spec is 80 us, 50*2 == 100 us)
-    {
       return DHT_ERROR_ACK_TOO_LONG;
-    }
     retryCount++;
     delayMicroseconds(2);
-  } while(DIRECT_READ(reg, bitmask));
+  } while(DIRECT_READ(reg, bitmask)); // while hi
+
   // Read the 40 bit data stream
   for(i = 0; i < DHT22_DATA_BIT_COUNT; i++)
   {
     // Find the start of the sync pulse
     retryCount = 0;
-    do
-    {
+    do {
       if (retryCount > 35) //(Spec is 50 us, 35*2 == 70 us)
-      {
         return DHT_ERROR_SYNC_TIMEOUT;
-      }
       retryCount++;
       delayMicroseconds(2);
-    } while(!DIRECT_READ(reg, bitmask));
+    } while(!DIRECT_READ(reg, bitmask)); // while lo
+    
     // Measure the width of the data pulse
     retryCount = 0;
-    do
-    {
+    do {
       if (retryCount > 50) //(Spec is 80 us, 50*2 == 100 us)
-      {
         return DHT_ERROR_DATA_TIMEOUT;
-      }
       retryCount++;
       delayMicroseconds(2);
-    } while(DIRECT_READ(reg, bitmask));
+    } while(DIRECT_READ(reg, bitmask)); // while hi
     bitTimes[i] = retryCount;
   }
   // Now bitTimes have the number of retries (us *2)
@@ -183,26 +192,17 @@ DHT22_ERROR_t DHT22::readData()
   // bitTimes[x] <= 11 is a 0
   // bitTimes[x] >  11 is a 1
   // Note: the bits are offset by one from the data sheet, not sure why
-  for(i = 0; i < 16; i++)
-  {
-    if(bitTimes[i + 1] > 11)
-    {
+  for(i = 0; i < 16; i++) {
+    if(bitTimes[i] > 11)
       currentHumidity |= (1 << (15 - i));
-    }
   }
-  for(i = 0; i < 16; i++)
-  {
-    if(bitTimes[i + 17] > 11)
-    {
+  for(i = 0; i < 16; i++) {
+    if(bitTimes[i + 16] > 11)
       currentTemperature |= (1 << (15 - i));
-    }
   }
-  for(i = 0; i < 8; i++)
-  {
-    if(bitTimes[i + 33] > 11)
-    {
+  for(i = 0; i < 8; i++) {
+    if(bitTimes[i + 32] > 11)
       checkSum |= (1 << (7 - i));
-    }
   }
 
   _lastHumidity = currentHumidity & 0x7FFF;
@@ -211,9 +211,7 @@ DHT22_ERROR_t DHT22::readData()
     // Below zero, non standard way of encoding negative numbers!
     // Convert to native negative format.
     _lastTemperature = -(currentTemperature & 0x7FFF);
-  }
-  else
-  {
+  } else {
     _lastTemperature = currentTemperature;
   }
 
@@ -222,9 +220,8 @@ DHT22_ERROR_t DHT22::readData()
   csPart3 = currentTemperature >> 8;
   csPart4 = currentTemperature & 0xFF;
   if(checkSum == ((csPart1 + csPart2 + csPart3 + csPart4) & 0xFF))
-  {
     return DHT_ERROR_NONE;
-  }
+
   return DHT_ERROR_CHECKSUM;
 }
 
diff --git a/DHT22.h b/DHT22.h
index 6981be7..b245b3e 100644
--- a/DHT22.h
+++ b/DHT22.h
@@ -40,9 +40,6 @@ class DHT22
 };
 
 // Report the humidity in .1 percent increments, such that 635 means 63.5% relative humidity
-//
-// Converts from the internal integer format on demand, so you might want
-// to cache the result.
 inline short int DHT22::getHumidityInt()
 {
   return _lastHumidity;
@@ -57,25 +54,26 @@ inline short int DHT22::getTemperatureCInt()
 
 #if !defined(DHT22_NO_FLOAT)
 // Return the percentage relative humidity in decimal form
+// Converts from the internal integer format on demand, so you might want
+// to cache the result.
 inline float DHT22::getHumidity()
 {
-  return float(_lastHumidity)/10;
+  return float(_lastHumidity) * (float)0.1;
 }
 #endif
 
 #if !defined(DHT22_NO_FLOAT)
 // Return the percentage relative humidity in decimal form
-//
 // Converts from the internal integer format on demand, so you might want
 // to cache the result.
 inline float DHT22::getTemperatureC()
 {
-  return float(_lastTemperature)/10;
+  return float(_lastTemperature) * (float)0.1;
 }
 
 inline float DHT22::getTemperatureF()
 {
-  return float(_lastTemperature) / 10 * 9 / 5 + 32;
+  return float(_lastTemperature) * (float)0.1 * 9.0 / 5.0 + 32.0;
 }
 #endif //DHT22_SUPPORT_FLOAT
 
diff --git a/README b/README
index a336841..4838d0f 100644
--- a/README
+++ b/README
@@ -1,5 +1,6 @@
   DHT22.cpp - DHT22 sensor library
   Developed by Ben Adams - 2011
+  Protocol Fix by Jens Geisler - 2014
 
 Humidity and Temperature Sensor DHT22 info found at
   http://www.sparkfun.com/products/10167
@@ -11,6 +12,15 @@ To install this library for use with the Arduino IDE, copy it
 to the `libraries' folder and restart the IDE. For an example of
 how to use it, see File->Examples->DHT22->Serial .
 
+The original library, after sending the sensor read-out initiation signal, waited 20us to 40us on a LOW signal, when it should have been looking for a 20us to 40 us sensor "setup time" HIGH signal. Then the original library expected a 80us HIGH "ACK pulse" when it should have been looking for a 80us LOW "ACK pulse" and a second 80us HIGH "ACK pulse". Thus the original library "saw" an extra pair of low and hi signals which it interpreted as a first invalid data-bit.
+Somehow the original worked quite well for me (and apparently for many others aswell) for a long time. Only on sensors connected via very long (>20m) twisted pair cable I sometimes didn't get a sensors to communicate. Interestingly when this happened it happened right at the first read and continued to persist. But after resetting my arduino a couple of times it started to work again and didn't go bad ever after (until - maybe - the next reset). So, I always thought it had something to do with the line being in a bad state at startup.
+But then I wanted to read six sensors and was not able to get of them working at the same time, no matter how often I resetted. So, I wrote a sketch to see what is going on on the sensor line and found out that the original library must have misinterpreted the spec.
+So, here is a corrected version, in the hope it will prevent others from the frustration I suffered.
+
+Version 0.6: 24-May-2014 by Jens Geisler
+Fixed the protocol according to https://www.sparkfun.com/datasheets/Sensors/Temperature/DHT22.pdf
+Added test sketch to analyse the timing of the sensor
+
 Version 0.5: 15-Jan-2012 by Craig Ringer
 Update to support Arduino 1.0
 Make accessors inlineable so they can be optimised away
diff --git a/examples/TestTiming/TestTiming.ino b/examples/TestTiming/TestTiming.ino
new file mode 100644
index 0000000..6fb864e
--- /dev/null
+++ b/examples/TestTiming/TestTiming.ino
@@ -0,0 +1,110 @@
+#include <DHT22.h>
+ 
+ 
+#define DIRECT_READ(base, mask)		(((*(base)) & (mask)) ? 1 : 0)
+#define DIRECT_MODE_INPUT(base, mask)	((*(base+1)) &= ~(mask))
+#define DIRECT_MODE_OUTPUT(base, mask)	((*(base+1)) |= (mask))
+#define DIRECT_WRITE_LOW(base, mask)	((*(base+2)) &= ~(mask))
+
+const byte pin= 7;
+uint8_t _bitmask;
+volatile uint8_t * _baseReg;
+uint8_t timesHi[45];
+uint8_t timesLo[45];
+DHT22 dht22;
+
+void setup() {
+  // initialize serial communication at 9600 bits per second:
+  Serial.begin(9600);
+}
+
+void loop() {
+  Serial.println("Start");
+  uint8_t res= sense();
+  Serial.print("Times Read: ");
+  Serial.println(res);
+  for(byte i= 0; i<45; i++ ) {
+    Serial.print("# ");
+    Serial.print(i);
+    Serial.print("Time Lo: ");
+    Serial.print(timesLo[i]*2);
+    Serial.print(" Time Hi: ");
+    Serial.println(timesHi[i]*2);
+  }
+  
+  
+  delay(3000);
+  dht22.setPin(pin);
+  DHT22_ERROR_t e= dht22.readData();
+  if (e==DHT_ERROR_NONE) {
+    Serial.print("T: ");
+    Serial.print(dht22.getTemperatureC());
+    Serial.print(", H: ");
+    Serial.println(dht22.getHumidity());
+  } else {
+    Serial.print("E: ");
+    Serial.println(e);    
+  }
+  while(1);
+}
+
+uint8_t sense() {
+  _bitmask = digitalPinToBitMask(pin);
+  _baseReg = portInputRegister(digitalPinToPort(pin));
+  uint8_t bitmask = _bitmask;
+  volatile uint8_t *reg asm("r30") = _baseReg;
+
+  uint8_t retryCount;
+  for(byte i= 0; i<45; i++ ) {
+    timesHi[i]= 0;
+    timesLo[i]= 0;
+  }
+  
+  cli();
+  DIRECT_MODE_INPUT(reg, bitmask);
+  sei();
+  retryCount = 0;
+  do {
+    if (retryCount > 125)
+    {
+      return 0;
+    }
+    retryCount++;
+    delayMicroseconds(2);
+  } while(!DIRECT_READ(reg, bitmask)); // while low
+  
+  // Send the activate pulse
+  cli();
+  DIRECT_WRITE_LOW(reg, bitmask);
+  DIRECT_MODE_OUTPUT(reg, bitmask); // Output Low
+  sei();
+  delayMicroseconds(1100); // 1.1 ms
+  cli();
+  DIRECT_MODE_INPUT(reg, bitmask);	// Switch back to input so pin can float
+  sei();
+  
+  for(byte i= 0; i<45; i++ ) {
+    retryCount = 0;
+    do {
+      if (retryCount > 100) {
+        return i+1;
+      }
+      
+      retryCount++;
+      delayMicroseconds(2);
+    } while(!DIRECT_READ(reg, bitmask)); // while lo
+    timesLo[i]= retryCount;
+
+    retryCount = 0;
+    do {
+      if (retryCount > 100) {
+        return i+1;
+      }
+      
+      retryCount++;
+      delayMicroseconds(2);
+    } while(DIRECT_READ(reg, bitmask)); // while hi
+    timesHi[i]= retryCount;
+  }
+  return 46;
+}

From bc7233636d38528812430656e4cfff3c907b19bb Mon Sep 17 00:00:00 2001
From: Jens Geisler <jens.geisler@web.de>
Date: Sat, 24 May 2014 22:30:11 +0200
Subject: [PATCH 2/4] added methods setPin and readDataNow

---
 DHT22.cpp | 52 ++++++++++++++++++++++++++++++++--------------------
 DHT22.h   |  8 ++++++--
 README    |  2 ++
 3 files changed, 40 insertions(+), 22 deletions(-)

diff --git a/DHT22.cpp b/DHT22.cpp
index bf8910f..0c8614c 100644
--- a/DHT22.cpp
+++ b/DHT22.cpp
@@ -62,21 +62,41 @@ extern "C" {
 
 #define DHT22_DATA_BIT_COUNT (40)
 
-DHT22::DHT22(uint8_t pin)
-{
-    _bitmask = digitalPinToBitMask(pin);
-    _baseReg = portInputRegister(digitalPinToPort(pin));
+DHT22::DHT22() {
+    _bitmask= 0;
+    init();
+}
+
+DHT22::DHT22(uint8_t pin) {
+    setPin(pin);
+}
+
+void DHT22::init() {
     _lastReadTime = millis();
     _lastHumidity = DHT22_ERROR_VALUE;
     _lastTemperature = DHT22_ERROR_VALUE;
 }
 
-//
-// Read the 40 bit data stream from the DHT 22
-// Store the results in private member data to be read by public member functions
-//
-DHT22_ERROR_t DHT22::readData()
-{
+void DHT22::setPin(uint8_t pin) {
+    _bitmask = digitalPinToBitMask(pin);
+    _baseReg = portInputRegister(digitalPinToPort(pin));
+    init();
+}
+
+DHT22_ERROR_t DHT22::readData() {
+  unsigned long currentTime= millis();
+  
+  if(currentTime - _lastReadTime < 2000) {
+    // Caller needs to wait 2 seconds between each call to readData
+    return DHT_ERROR_TOOQUICK;
+  }
+  _lastReadTime = currentTime;
+  
+  return readDataNow();
+}  
+  
+// Read the sensor without checking the last read time
+DHT22_ERROR_t DHT22::readDataNow() {
   uint8_t bitmask = _bitmask;
   volatile uint8_t *reg asm("r30") = _baseReg;
   uint8_t retryCount;
@@ -84,25 +104,17 @@ DHT22_ERROR_t DHT22::readData()
   int currentHumidity;
   int currentTemperature;
   uint8_t checkSum, csPart1, csPart2, csPart3, csPart4;
-  unsigned long currentTime;
   int i;
-
+  
+  if(bitmask==0) return DHT_ERROR_NOT_PRESENT;
   currentHumidity = 0;
   currentTemperature = 0;
   checkSum = 0;
-  currentTime = millis();
   for(i = 0; i < DHT22_DATA_BIT_COUNT; i++)
   {
     bitTimes[i] = 0;
   }
 
-  if(currentTime - _lastReadTime < 2000)
-  {
-    // Caller needs to wait 2 seconds between each call to readData
-    return DHT_ERROR_TOOQUICK;
-  }
-  _lastReadTime = currentTime;
-
   // Pin needs to start HIGH, wait until it is HIGH with a timeout
   cli();
   DIRECT_MODE_INPUT(reg, bitmask);
diff --git a/DHT22.h b/DHT22.h
index b245b3e..baee4e3 100644
--- a/DHT22.h
+++ b/DHT22.h
@@ -20,6 +20,7 @@ typedef enum
 class DHT22
 {
   private:
+    void init();
     uint8_t _bitmask;
     volatile uint8_t *_baseReg;
     unsigned long _lastReadTime;
@@ -27,10 +28,13 @@ class DHT22
     short int _lastTemperature;
 
   public:
+    DHT22();
     DHT22(uint8_t pin);
+    void setPin(uint8_t pin);
     DHT22_ERROR_t readData();
-	short int getHumidityInt();
-	short int getTemperatureCInt();
+    DHT22_ERROR_t readDataNow();
+    short int getHumidityInt();
+    short int getTemperatureCInt();
     void clockReset();
 #if !defined(DHT22_NO_FLOAT)
     float getHumidity();
diff --git a/README b/README
index 4838d0f..67eeb9c 100644
--- a/README
+++ b/README
@@ -20,6 +20,8 @@ So, here is a corrected version, in the hope it will prevent others from the fru
 Version 0.6: 24-May-2014 by Jens Geisler
 Fixed the protocol according to https://www.sparkfun.com/datasheets/Sensors/Temperature/DHT22.pdf
 Added test sketch to analyse the timing of the sensor
+Added method setPin to change the sensor pin and thus reuse one DHT22 object for reading several sensors
+Added method readDataNow to read a sensor without the 2s time limit.
 
 Version 0.5: 15-Jan-2012 by Craig Ringer
 Update to support Arduino 1.0

From 5219f31ca0781f31dda6fbbc6edb301c03733bba Mon Sep 17 00:00:00 2001
From: Jens Geisler <jens.geisler@web.de>
Date: Wed, 11 Feb 2015 20:53:14 +0100
Subject: [PATCH 3/4] Changed detection limit for 1 bits to 50us

---
 DHT22.cpp | 11 ++++++-----
 README    |  1 +
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/DHT22.cpp b/DHT22.cpp
index 0c8614c..61791f8 100644
--- a/DHT22.cpp
+++ b/DHT22.cpp
@@ -64,15 +64,16 @@ extern "C" {
 
 DHT22::DHT22() {
     _bitmask= 0;
+    _lastReadTime= 0;
     init();
 }
 
 DHT22::DHT22(uint8_t pin) {
+    _lastReadTime = 0;
     setPin(pin);
 }
 
 void DHT22::init() {
-    _lastReadTime = millis();
     _lastHumidity = DHT22_ERROR_VALUE;
     _lastTemperature = DHT22_ERROR_VALUE;
 }
@@ -86,7 +87,7 @@ void DHT22::setPin(uint8_t pin) {
 DHT22_ERROR_t DHT22::readData() {
   unsigned long currentTime= millis();
   
-  if(currentTime - _lastReadTime < 2000) {
+  if((long)(currentTime - _lastReadTime) < 2000) {
     // Caller needs to wait 2 seconds between each call to readData
     return DHT_ERROR_TOOQUICK;
   }
@@ -205,15 +206,15 @@ DHT22_ERROR_t DHT22::readDataNow() {
   // bitTimes[x] >  11 is a 1
   // Note: the bits are offset by one from the data sheet, not sure why
   for(i = 0; i < 16; i++) {
-    if(bitTimes[i] > 11)
+    if(bitTimes[i] > 25)
       currentHumidity |= (1 << (15 - i));
   }
   for(i = 0; i < 16; i++) {
-    if(bitTimes[i + 16] > 11)
+    if(bitTimes[i + 16] > 25)
       currentTemperature |= (1 << (15 - i));
   }
   for(i = 0; i < 8; i++) {
-    if(bitTimes[i + 32] > 11)
+    if(bitTimes[i + 32] > 25)
       checkSum |= (1 << (7 - i));
   }
 
diff --git a/README b/README
index 67eeb9c..686a192 100644
--- a/README
+++ b/README
@@ -22,6 +22,7 @@ Fixed the protocol according to https://www.sparkfun.com/datasheets/Sensors/Temp
 Added test sketch to analyse the timing of the sensor
 Added method setPin to change the sensor pin and thus reuse one DHT22 object for reading several sensors
 Added method readDataNow to read a sensor without the 2s time limit.
+Changed detection limit for "1" bits to 50us
 
 Version 0.5: 15-Jan-2012 by Craig Ringer
 Update to support Arduino 1.0

From f6fee2f886acb294ccba627caa0b951293849ce6 Mon Sep 17 00:00:00 2001
From: Jens Geisler <jens.geisler@web.de>
Date: Sat, 10 Jul 2021 19:37:10 +0200
Subject: [PATCH 4/4] new improved timing

---
 DHT22.cpp    | 131 ++++++++++++++++++---------------------------------
 DHT22.h      |  24 +++++++++-
 keywords.txt |   1 +
 3 files changed, 69 insertions(+), 87 deletions(-)

diff --git a/DHT22.cpp b/DHT22.cpp
index 61791f8..9575b49 100644
--- a/DHT22.cpp
+++ b/DHT22.cpp
@@ -45,7 +45,6 @@ The Arduino OneWire lib
 */
 
 #include "DHT22.h"
-#include <Arduino.h>
 #include <pins_arduino.h>
 
 extern "C" {
@@ -54,11 +53,10 @@ extern "C" {
 #include <avr/pgmspace.h>
 }
 
-#define DIRECT_READ(base, mask)		(((*(base)) & (mask)) ? 1 : 0)
 #define DIRECT_MODE_INPUT(base, mask)	((*(base+1)) &= ~(mask))
 #define DIRECT_MODE_OUTPUT(base, mask)	((*(base+1)) |= (mask))
 #define DIRECT_WRITE_LOW(base, mask)	((*(base+2)) &= ~(mask))
-//#define DIRECT_WRITE_HIGH(base, mask)	((*(base+2)) |= (mask))
+#define DIRECT_WRITE_HIGH(base, mask)	((*(base+2)) |= (mask))
 
 #define DHT22_DATA_BIT_COUNT (40)
 
@@ -95,126 +93,87 @@ DHT22_ERROR_t DHT22::readData() {
   
   return readDataNow();
 }  
+
   
 // Read the sensor without checking the last read time
 DHT22_ERROR_t DHT22::readDataNow() {
-  uint8_t bitmask = _bitmask;
-  volatile uint8_t *reg asm("r30") = _baseReg;
-  uint8_t retryCount;
-  uint8_t bitTimes[DHT22_DATA_BIT_COUNT];
+    volatile uint8_t *reg asm("r30") = _baseReg;
+  bool bitTimes[DHT22_DATA_BIT_COUNT];
   int currentHumidity;
   int currentTemperature;
   uint8_t checkSum, csPart1, csPart2, csPart3, csPart4;
-  int i;
   
-  if(bitmask==0) return DHT_ERROR_NOT_PRESENT;
+  if(_bitmask==0) return DHT_ERROR_NOT_PRESENT;
   currentHumidity = 0;
   currentTemperature = 0;
   checkSum = 0;
-  for(i = 0; i < DHT22_DATA_BIT_COUNT; i++)
-  {
-    bitTimes[i] = 0;
-  }
 
   // Pin needs to start HIGH, wait until it is HIGH with a timeout
   cli();
-  DIRECT_MODE_INPUT(reg, bitmask);
+  DIRECT_WRITE_HIGH(reg, _bitmask);
+  DIRECT_MODE_INPUT(reg, _bitmask);
   sei();
-  retryCount = 0;
-  do
-  {
-    if (retryCount > 125)
-    {
+  if(!levelTime(LOW, 0, 80))      
       return DHT_BUS_HUNG;
-    }
-    retryCount++;
-    delayMicroseconds(2);
-  } while(!DIRECT_READ(reg, bitmask));
+  
   // Send the activate pulse
   cli();
-  DIRECT_WRITE_LOW(reg, bitmask);
-  DIRECT_MODE_OUTPUT(reg, bitmask); // Output Low
+  DIRECT_WRITE_LOW(reg, _bitmask);
+  DIRECT_MODE_OUTPUT(reg, _bitmask); // Output Low
   sei();
-  delayMicroseconds(1100); // 1.1 ms
+  delayMicroseconds(1000); // 1.1 ms
   cli();
-  DIRECT_MODE_INPUT(reg, bitmask);	// Switch back to input so pin can float
+  DIRECT_WRITE_HIGH(reg, _bitmask);
+  DIRECT_MODE_INPUT(reg, _bitmask);	// Switch back to input so pin can float
   sei();
   
-  // Wait for hi level
-  retryCount = 0;
-  do {
-    if (retryCount > 5) 
-      return DHT_BUS_HUNG;
-    retryCount++;
-    delayMicroseconds(2);
-  } while(!DIRECT_READ(reg, bitmask)); // while lo
-
-  // Wait for response
-  retryCount = 0;
-  do {
-    if (retryCount > 25) //(Spec is 20 to 40 us, 25*2 == 50 us)
-      return DHT_ERROR_NOT_PRESENT;
-    retryCount++;
-    delayMicroseconds(2);
-  } while(DIRECT_READ(reg, bitmask)); // while hi
-
+//   Wait for hi level
+    if(!levelTime(LOW, 0, 80))      
+        return DHT_BUS_HUNG;
+ 
+//   Wait for response, should be 40us hi
+    if(!levelTime(HIGH, 0, 60))      
+        return DHT_ERROR_NOT_PRESENT;
+  
   // ACK Pulse lo
-  retryCount = 0;
-  do {
-    if (retryCount > 50) //(Spec is 80 us, 50*2 == 100 us)
+  if(!levelTime(LOW, 50, 90))      
       return DHT_ERROR_ACK_TOO_LONG;
-    retryCount++;
-    delayMicroseconds(2);
-  } while(!DIRECT_READ(reg, bitmask)); // while lo
-
+  
   // ACK Pulse hi
-  retryCount = 0;
-  do {
-    if (retryCount > 50) //(Spec is 80 us, 50*2 == 100 us)
+  if(!levelTime(HIGH, 50, 90))      
       return DHT_ERROR_ACK_TOO_LONG;
-    retryCount++;
-    delayMicroseconds(2);
-  } while(DIRECT_READ(reg, bitmask)); // while hi
-
+  
   // Read the 40 bit data stream
-  for(i = 0; i < DHT22_DATA_BIT_COUNT; i++)
+  for(int i = 0; i < DHT22_DATA_BIT_COUNT; i++)
   {
     // Find the start of the sync pulse
-    retryCount = 0;
-    do {
-      if (retryCount > 35) //(Spec is 50 us, 35*2 == 70 us)
+    if(!levelTime(LOW, 16, 70))      
         return DHT_ERROR_SYNC_TIMEOUT;
-      retryCount++;
-      delayMicroseconds(2);
-    } while(!DIRECT_READ(reg, bitmask)); // while lo
     
     // Measure the width of the data pulse
-    retryCount = 0;
-    do {
-      if (retryCount > 50) //(Spec is 80 us, 50*2 == 100 us)
+    if(!levelTime(HIGH, 0, 100))      
         return DHT_ERROR_DATA_TIMEOUT;
-      retryCount++;
-      delayMicroseconds(2);
-    } while(DIRECT_READ(reg, bitmask)); // while hi
-    bitTimes[i] = retryCount;
+    
+    // Spec: 0 is 26 to 28 us
+    // Spec: 1 is 70 us
+    bitTimes[i] = wrongTiming>40;
   }
-  // Now bitTimes have the number of retries (us *2)
-  // that were needed to find the end of each data bit
-  // Spec: 0 is 26 to 28 us
-  // Spec: 1 is 70 us
-  // bitTimes[x] <= 11 is a 0
-  // bitTimes[x] >  11 is a 1
-  // Note: the bits are offset by one from the data sheet, not sure why
-  for(i = 0; i < 16; i++) {
-    if(bitTimes[i] > 25)
+
+  // EOF Pulse lo
+  if(!levelTime(LOW, 16, 75))      
+      return DHT_ERROR_SYNC_TIMEOUT;
+
+  
+  for(int i = 0; i < 16; i++) {
+    if(bitTimes[i])
       currentHumidity |= (1 << (15 - i));
   }
-  for(i = 0; i < 16; i++) {
-    if(bitTimes[i + 16] > 25)
+  for(int i = 0; i < 16; i++) {
+    if(bitTimes[i + 16])
       currentTemperature |= (1 << (15 - i));
   }
-  for(i = 0; i < 8; i++) {
-    if(bitTimes[i + 32] > 25)
+  for(int i = 0; i < 8; i++) {
+    if(bitTimes[i + 32])
       checkSum |= (1 << (7 - i));
   }
 
diff --git a/DHT22.h b/DHT22.h
index baee4e3..4df62c7 100644
--- a/DHT22.h
+++ b/DHT22.h
@@ -2,6 +2,7 @@
 #define _DHT22_H_
 
 #include <inttypes.h>
+#include <Arduino.h>
 
 #define DHT22_ERROR_VALUE -995
 
@@ -26,8 +27,23 @@ class DHT22
     unsigned long _lastReadTime;
     short int _lastHumidity;
     short int _lastTemperature;
-
+    
+    inline bool levelTime(uint8_t level, unsigned long min, unsigned long max) {
+        volatile uint8_t *reg asm("r30") = _baseReg;
+        long t;
+        
+        t= micros();
+        for(uint8_t i= 0;  (((*reg) & _bitmask) ? 1 : 0)==level && i<100; i++)
+            delayMicroseconds(6);
+        
+        wrongTiming= micros() - t;
+        
+        return wrongTiming>min && wrongTiming<max;
+    };
+    
+    
   public:
+    unsigned long wrongTiming;
     DHT22();
     DHT22(uint8_t pin);
     void setPin(uint8_t pin);
@@ -36,6 +52,7 @@ class DHT22
     short int getHumidityInt();
     short int getTemperatureCInt();
     void clockReset();
+    // unsigned long getWrongTiming();
 #if !defined(DHT22_NO_FLOAT)
     float getHumidity();
     float getTemperatureC();
@@ -56,6 +73,11 @@ inline short int DHT22::getTemperatureCInt()
   return _lastTemperature;
 }
 
+// unsigned long DHT22::getWrongTiming() {
+//     return wrongTiming;
+// }
+
+
 #if !defined(DHT22_NO_FLOAT)
 // Return the percentage relative humidity in decimal form
 // Converts from the internal integer format on demand, so you might want
diff --git a/keywords.txt b/keywords.txt
index 5a1297f..7991572 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -17,6 +17,7 @@ getHumidity	KEYWORD2
 getHumidityInt	KEYWORD2
 getTemperatureC	KEYWORD2
 getTemperatureCInt KEYWORD2
+getWrongTiming KEYWORD2
 clockReset	KEYWORD2
 
 #######################################