Skip to content

Improve reliability, especially at low clock speed #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 32 additions & 56 deletions DHT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ void DHT::setup(uint8_t pin, DHT_MODEL_t model)
{
DHT::pin = pin;
DHT::model = model;
DHT::resetTimer(); // Make sure we do read the sensor in the next readSensor()

if ( model == AUTO_DETECT) {
DHT::model = DHT22;
Expand All @@ -45,23 +44,6 @@ void DHT::setup(uint8_t pin, DHT_MODEL_t model)
}
}

void DHT::resetTimer()
{
DHT::lastReadTime = millis() - 3000;
}

float DHT::getHumidity()
{
readSensor();
return humidity;
}

float DHT::getTemperature()
{
readSensor();
return temperature;
}

#ifndef OPTIMIZE_SRAM_SIZE

const char* DHT::getStatusString()
Expand Down Expand Up @@ -110,15 +92,6 @@ const char *DHT::getStatusString() {

void DHT::readSensor()
{
// Make sure we don't poll the sensor too often
// - Max sample rate DHT11 is 1 Hz (duty cicle 1000 ms)
// - Max sample rate DHT22 is 0.5 Hz (duty cicle 2000 ms)
unsigned long startTime = millis();
if ( (unsigned long)(startTime - lastReadTime) < (model == DHT11 ? 999L : 1999L) ) {
return;
}
lastReadTime = startTime;

temperature = NAN;
humidity = NAN;

Expand All @@ -134,51 +107,54 @@ void DHT::readSensor()
delayMicroseconds(800);
}

pinMode(pin, INPUT);
digitalWrite(pin, HIGH); // Switch bus to receive data
pinMode(pin, INPUT_PULLUP); // Switch bus to receive data

// We're going to read 83 edges:
// - First a FALLING, RISING, and FALLING edge for the start bit
// - Then 40 bits: RISING and then a FALLING edge per bit
// To keep our code simple, we accept any HIGH or LOW reading if it's max 85 usecs long
// We're going to read 41 pulses, which each consist of a transition to HIGH
// and then back to LOW again. The first pulse is the start bit and goes for
// ~80us. Then after that, a 26-28us pulse is a 0, and a 70us pulse is a 1.
//
// It's helpful to disable interrupts for the whole duration of capture, since
// at 8 MHz a timer interrupt takes ~10us, long enough to cause a short "0"
// pulse to be missed. However, this will cause millis() and micros() to give
// an inaccurate result.

noInterrupts();

word rawHumidity;
word rawTemperature;
word data;

for ( int8_t i = -3 ; i < 2 * 40; i++ ) {
byte age;
startTime = micros();
unsigned calibration = 0;

do {
age = (unsigned long)(micros() - startTime);
if ( age > 90 ) {
error = ERROR_TIMEOUT;
return;
}
}
while ( digitalRead(pin) == (i & 1) ? HIGH : LOW );
for ( int8_t i = -1 ; i < 40; i++ ) {
byte width = (byte)pulseIn(pin, HIGH, 150);

if (width == 0) {
error = ERROR_TIMEOUT;
interrupts();
return;
}

if ( i >= 0 && (i & 1) ) {
if ( i >= 0 ) {
// Now we are being fed our 40 bits
data <<= 1;

// A zero max 30 usecs, a one at least 68 usecs.
if ( age > 30 ) {
if ( width > 45 ) {
data |= 1; // we got a one
}
}

switch ( i ) {
case 31:
rawHumidity = data;
break;
case 63:
rawTemperature = data;
data = 0;
break;
switch ( i ) {
case 15:
rawHumidity = data;
break;
case 31:
rawTemperature = data;
data = 0;
break;
}
}
}
interrupts();

// Verify checksum

Expand Down
22 changes: 16 additions & 6 deletions DHT.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@
2013-06-10: Initial version
2013-06-12: Refactored code
2013-07-01: Add a resetTimer method
2015-04-25: Remove resetTimer(). Require readSensor() to be called before
getTemperature()/getHumidity() and remove the sampling rate
check, so that we don't need to rely on millis() being accurate.
This means that we can support sleep mode. Improve reliability
on 8MHz devices by disabling interrupts and using pulseIn()
instead of our own busy loop.

******************************************************************/

#ifndef dht_h
Expand Down Expand Up @@ -56,10 +63,16 @@ class DHT
DHT_ERROR_t;

void setup(uint8_t pin, DHT_MODEL_t model=AUTO_DETECT);
void resetTimer();

float getTemperature();
float getHumidity();
void readSensor();

float getTemperature() {
return temperature;
}

float getHumidity() {
return humidity;
}

DHT_ERROR_t getStatus() { return error; };
const char* getStatusString();
Expand All @@ -80,8 +93,6 @@ class DHT
static float toCelsius(float fromFahrenheit) { return (fromFahrenheit - 32.0) / 1.8; };

protected:
void readSensor();

float temperature;
float humidity;

Expand All @@ -90,7 +101,6 @@ class DHT
private:
DHT_MODEL_t model;
DHT_ERROR_t error;
unsigned long lastReadTime;
};

#endif /*dht_h*/
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ void loop()
{
delay(dht.getMinimumSamplingPeriod());

dht.readSensor();
Serial.print(dht.getHumidity());
Serial.print("\t");
Serial.print(dht.getTemperature());
Expand Down