23 Commits
1.1.0 ... 1.2.3

Author SHA1 Message Date
Tony DiCola
edcd0e06e6 Merge branch 'master' of https://github.com/adafruit/DHT-sensor-library 2015-10-12 21:30:18 -07:00
Tony DiCola
15020aa891 Fix #44 by conditionally excluding unused port and bitmask state on non-AVR platforms. 2015-10-12 21:30:01 -07:00
Tony DiCola
572347f137 Merge comment update from pull #43 2015-10-12 21:09:17 -07:00
Tony DiCola
e9daf69083 Merge README.md change from pull #43 2015-10-12 21:08:31 -07:00
Tony DiCola
56058fecc5 Bump library to 1.2.2 version. 2015-10-12 18:39:28 -07:00
Tony DiCola
d71288af17 Merge branch 'jmdana-master' 2015-10-12 18:38:58 -07:00
Tony DiCola
ce3190f65c Switch back to integer division in array indexing. 2015-10-12 18:37:54 -07:00
J.M. Dana
5bc0a5c796 Divisions turned into multiplications
As correctly stated by Mausy5043, the division is quite slow in most
microcontrollers, so I have replaced them with multiplications.
2015-10-06 23:42:19 +01:00
Tony DiCola
5fb1668822 Merge branch 'jmdana-master' 2015-10-05 17:55:14 -07:00
Tony DiCola
c57f0c8c29 Bump version to 1.2.1 2015-10-05 17:54:59 -07:00
J.M. Dana
51a8b814ac Divisions have been replaced by multiplications. 2015-10-03 13:42:09 +01:00
J.M. Dana
36fb16274b DHT::computeHeatIndex has been modified so it uses both Rothfusz and
Steadman's equations. As a result, it allows a larger range of
temperatures and more accurate results for extreme conditions.
2015-10-02 21:50:43 +01:00
Tony DiCola
6c0c723907 Merge branch 'matthijskooijman-fixes' 2015-09-15 12:26:54 -07:00
Tony DiCola
232ad0cd70 Bump version to 1.2.0 after integrating optimizations from matthijskooijman. 2015-09-15 12:26:38 -07:00
Matthijs Kooijman
f9c3f323e3 Use INPUT_PULLUP
Previously, the mode was configured to INPUT and then written HIGH,
which works on AVR but isn't very portable. Instead, this uses the
INPUT_PULLUP pin mode (available since Arduino 1.0.1) which is portable.
2015-07-24 21:44:41 +02:00
Matthijs Kooijman
45a20da301 Shrink DHT::data to 5 bytes
There's only 5 bytes of data being transferred (2x2 bytes of data, 1
byte checksum), so no need to keep a useless byte.
2015-07-24 21:43:52 +02:00
Matthijs Kooijman
5973929e63 Remove the firstreading variable
By cleverly setting _lastreadtime in begin() to make sure that it looks
like the last read was alrady 2000 ms ago, even on startup when millis()
still returns 0, there is no longer a need to keep a separate
firstreading variable, saving a byte of memory and a bit of code.
2015-07-24 21:42:58 +02:00
Matthijs Kooijman
f1b79028ea Clean up two-second interval check
There was some handling of millis() overflow that is not needed.
Standard unsigned subtraction and wraparound already works as expected,
so this extra check can be removed (it even hurts, since it introduces 2
seconds after a wraparound where no new data will be read, even if it
could otherwise happen).

Also, this prevents calling millis() a second time, since its value is
already known.
2015-07-24 21:41:19 +02:00
Matthijs Kooijman
04905bc5cd Add force parameter to read methods
This allows forcing a read, even if the previous read was less than 2
seconds ago. This is useful in cases where the millis() timer is not
reliable, such as when sleeping. In this case, it is up to the caller to
ensure that at least 2 seconds elapse between calls with force set to
true.
2015-07-24 21:40:22 +02:00
Tony DiCola
5cd78aead6 Fix merge conflict with interrupt disable lock. 2015-07-22 12:22:35 -07:00
Tony DiCola
85d85170bd Fix #37 by optimizing pulse read to use direct port access on AVR, stops checksum failures from missed signals. 2015-07-22 12:13:56 -07:00
Tony DiCola
9419315c50 Merge pull request #36 from Zirientis/master
Cause interrupts to be reenabled if a timeout occurs while waiting for the sensor
2015-07-01 22:16:10 -07:00
Zirientis
a2208eb813 Cause interrupts to be reenabled if a timeout occurs while waiting for the sensor. 2015-07-01 17:58:17 -07:00
5 changed files with 134 additions and 94 deletions

139
DHT.cpp
View File

@@ -6,26 +6,36 @@ written by Adafruit Industries
#include "DHT.h"
#define MIN_INTERVAL 2000
DHT::DHT(uint8_t pin, uint8_t type, uint8_t count) {
_pin = pin;
_type = type;
_firstreading = true;
#ifdef __AVR
_bit = digitalPinToBitMask(pin);
_port = digitalPinToPort(pin);
#endif
_maxcycles = microsecondsToClockCycles(1000); // 1 millisecond timeout for
// reading pulses from DHT sensor.
// Note that count is now ignored as the DHT reading algorithm adjusts itself
// basd on the speed of the processor.
}
void DHT::begin(void) {
// set up the pins!
pinMode(_pin, INPUT);
digitalWrite(_pin, HIGH);
_lastreadtime = 0;
pinMode(_pin, INPUT_PULLUP);
// Using this value makes sure that millis() - lastreadtime will be
// >= MIN_INTERVAL right away. Note that this assignment wraps around,
// but so will the subtraction.
_lastreadtime = -MIN_INTERVAL;
DEBUG_PRINT("Max clock cycles: "); DEBUG_PRINTLN(_maxcycles, DEC);
}
//boolean S == Scale. True == Fahrenheit; False == Celcius
float DHT::readTemperature(bool S) {
float DHT::readTemperature(bool S, bool force) {
float f = NAN;
if (read()) {
if (read(force)) {
switch (_type) {
case DHT11:
f = data[2];
@@ -38,7 +48,7 @@ float DHT::readTemperature(bool S) {
f = data[2] & 0x7F;
f *= 256;
f += data[3];
f /= 10;
f *= 0.1;
if (data[2] & 0x80) {
f *= -1;
}
@@ -52,14 +62,14 @@ float DHT::readTemperature(bool S) {
}
float DHT::convertCtoF(float c) {
return c * 9 / 5 + 32;
return c * 1.8 + 32;
}
float DHT::convertFtoC(float f) {
return (f - 32) * 5 / 9;
return (f - 32) * 0.55555;
}
float DHT::readHumidity(void) {
float DHT::readHumidity(bool force) {
float f = NAN;
if (read()) {
switch (_type) {
@@ -71,7 +81,7 @@ float DHT::readHumidity(void) {
f = data[0];
f *= 256;
f += data[1];
f /= 10;
f *= 0.1;
break;
}
}
@@ -80,23 +90,17 @@ float DHT::readHumidity(void) {
//boolean isFahrenheit: True == Fahrenheit; False == Celcius
float DHT::computeHeatIndex(float temperature, float percentHumidity, bool isFahrenheit) {
// Adapted from equation at: https://github.com/adafruit/DHT-sensor-library/issues/9 and
// Wikipedia: http://en.wikipedia.org/wiki/Heat_index
if (!isFahrenheit) {
// Celsius heat index calculation.
return -8.784695 +
1.61139411 * temperature +
2.338549 * percentHumidity +
-0.14611605 * temperature*percentHumidity +
-0.01230809 * pow(temperature, 2) +
-0.01642482 * pow(percentHumidity, 2) +
0.00221173 * pow(temperature, 2) * percentHumidity +
0.00072546 * temperature*pow(percentHumidity, 2) +
-0.00000358 * pow(temperature, 2) * pow(percentHumidity, 2);
}
else {
// Fahrenheit heat index calculation.
return -42.379 +
// Using both Rothfusz and Steadman's equations
// http://www.wpc.ncep.noaa.gov/html/heatindex_equation.shtml
float hi;
if (!isFahrenheit)
temperature = convertCtoF(temperature);
hi = 0.5 * (temperature + 61.0 + ((temperature - 68.0) * 1.2) + (percentHumidity * 0.094));
if (hi > 79) {
hi = -42.379 +
2.04901523 * temperature +
10.14333127 * percentHumidity +
-0.22475541 * temperature*percentHumidity +
@@ -105,22 +109,25 @@ float DHT::computeHeatIndex(float temperature, float percentHumidity, bool isFah
0.00122874 * pow(temperature, 2) * percentHumidity +
0.00085282 * temperature*pow(percentHumidity, 2) +
-0.00000199 * pow(temperature, 2) * pow(percentHumidity, 2);
if((percentHumidity < 13) && (temperature >= 80.0) && (temperature <= 112.0))
hi -= ((13.0 - percentHumidity) * 0.25) * sqrt((17.0 - abs(temperature - 95.0)) * 0.05882);
else if((percentHumidity > 85.0) && (temperature >= 80.0) && (temperature <= 87.0))
hi += ((percentHumidity - 85.0) * 0.1) * ((87.0 - temperature) * 0.2);
}
return isFahrenheit ? hi : convertFtoC(hi);
}
boolean DHT::read(void) {
boolean DHT::read(bool force) {
// Check if sensor was read less than two seconds ago and return early
// to use last reading.
uint32_t currenttime = millis();
if (currenttime < _lastreadtime) {
// ie there was a rollover
_lastreadtime = 0;
}
if (!_firstreading && ((currenttime - _lastreadtime) < 2000)) {
if (!force && ((currenttime - _lastreadtime) < 2000)) {
return _lastresult; // return last correct measurement
}
_firstreading = false;
_lastreadtime = millis();
_lastreadtime = currenttime;
// Reset 40 bits of received data to zero.
data[0] = data[1] = data[2] = data[3] = data[4] = 0;
@@ -138,16 +145,18 @@ boolean DHT::read(void) {
digitalWrite(_pin, LOW);
delay(20);
uint32_t cycles[80];
{
// Turn off interrupts temporarily because the next sections are timing critical
// and we don't want any interruptions.
noInterrupts();
InterruptLock lock;
// End the start signal by setting data line high for 40 microseconds.
digitalWrite(_pin, HIGH);
delayMicroseconds(40);
// Now start reading the data line to get the value from the DHT sensor.
pinMode(_pin, INPUT);
pinMode(_pin, INPUT_PULLUP);
delayMicroseconds(10); // Delay a bit to let sensor pull data line low.
// First expect a low signal for ~80 microseconds followed by a high signal
@@ -169,17 +178,21 @@ boolean DHT::read(void) {
// then it's a 1. We measure the cycle count of the initial 50us low pulse
// and use that to compare to the cycle count of the high pulse to determine
// if the bit is a 0 (high state cycle count < low state cycle count), or a
// 1 (high state cycle count > low state cycle count).
for (int i=0; i<40; ++i) {
uint32_t lowCycles = expectPulse(LOW);
if (lowCycles == 0) {
DEBUG_PRINTLN(F("Timeout waiting for bit low pulse."));
_lastresult = false;
return _lastresult;
// 1 (high state cycle count > low state cycle count). Note that for speed all
// the pulses are read into a array and then examined in a later step.
for (int i=0; i<80; i+=2) {
cycles[i] = expectPulse(LOW);
cycles[i+1] = expectPulse(HIGH);
}
uint32_t highCycles = expectPulse(HIGH);
if (highCycles == 0) {
DEBUG_PRINTLN(F("Timeout waiting for bit high pulse."));
} // 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).
for (int i=0; i<40; ++i) {
uint32_t lowCycles = cycles[2*i];
uint32_t highCycles = cycles[2*i+1];
if ((lowCycles == 0) || (highCycles == 0)) {
DEBUG_PRINTLN(F("Timeout waiting for pulse."));
_lastresult = false;
return _lastresult;
}
@@ -194,16 +207,13 @@ boolean DHT::read(void) {
// stored data.
}
// Re-enable interrupts, timing critical code is complete.
interrupts();
DEBUG_PRINTLN(F("Received:"));
DEBUG_PRINT(data[0], HEX); DEBUG_PRINT(F(", "));
DEBUG_PRINT(data[1], HEX); DEBUG_PRINT(F(", "));
DEBUG_PRINT(data[2], HEX); DEBUG_PRINT(F(", "));
DEBUG_PRINT(data[3], HEX); DEBUG_PRINT(F(", "));
DEBUG_PRINT(data[4], HEX); DEBUG_PRINT(F(" =? "));
DEBUG_PRINTLN(data[0] + data[1] + data[2] + data[3], HEX);
DEBUG_PRINTLN((data[0] + data[1] + data[2] + data[3]) & 0xFF, HEX);
// Check we read 40 bits and that the checksum matches.
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
@@ -221,16 +231,29 @@ boolean DHT::read(void) {
// return a count of loop cycles spent at that level (this cycle count can be
// used to compare the relative time of two pulses). If more than a millisecond
// ellapses without the level changing then the call fails with a 0 response.
// This is adapted from Arduino's pulseInLong function (which is only available
// in the very latest IDE versions):
// https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/wiring_pulse.c
uint32_t DHT::expectPulse(bool level) {
uint32_t count = 0;
uint32_t end = micros() + 1000;
// Loop while counting cycles until the level changes.
// On AVR platforms use direct GPIO port access as it's much faster and better
// for catching pulses that are 10's of microseconds in length:
#ifdef __AVR
uint8_t portState = level ? _bit : 0;
while ((*portInputRegister(_port) & _bit) == portState) {
if (count++ >= _maxcycles) {
return 0; // Exceeded timeout, fail.
}
}
// Otherwise fall back to using digitalRead (this seems to be necessary on ESP8266
// right now, perhaps bugs in direct port access functions?).
#else
while (digitalRead(_pin) == level) {
count++;
if (micros() >= end) {
// Exceeded timeout waiting for level to change, fail.
return 0;
if (count++ >= _maxcycles) {
return 0; // Exceeded timeout, fail.
}
}
#endif
return count;
}

27
DHT.h
View File

@@ -39,22 +39,37 @@ class DHT {
public:
DHT(uint8_t pin, uint8_t type, uint8_t count=6);
void begin(void);
float readTemperature(bool S=false);
float readTemperature(bool S=false, bool force=false);
float convertCtoF(float);
float convertFtoC(float);
float computeHeatIndex(float temperature, float percentHumidity, bool isFahrenheit=true);
float readHumidity(void);
boolean read(void);
float readHumidity(bool force=false);
boolean read(bool force=false);
private:
uint8_t data[6];
uint8_t data[5];
uint8_t _pin, _type;
uint32_t _lastreadtime;
bool _firstreading;
#ifdef __AVR
// Use direct GPIO access on an 8-bit AVR so keep track of the port and bitmask
// for the digital pin connected to the DHT. Other platforms will use digitalRead.
uint8_t _bit, _port;
#endif
uint32_t _lastreadtime, _maxcycles;
bool _lastresult;
uint32_t expectPulse(bool level);
};
class InterruptLock {
public:
InterruptLock() {
noInterrupts();
}
~InterruptLock() {
interrupts();
}
};
#endif

View File

@@ -1,3 +1,5 @@
This is an Arduino library for the DHT series of low cost temperature/humidity sensors.
Tutorial: https://learn.adafruit.com/dht
To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder DHT. Check that the DHT folder contains DHT.cpp and DHT.h. Place the DHT library folder your <arduinosketchfolder>/libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE.

View File

@@ -3,11 +3,11 @@
#include "DHT.h"
#define DHTPIN 2 // what pin we're connected to
#define DHTPIN 2 // what digital pin we're connected to
// Uncomment whatever type you're using!
//#define DHTTYPE DHT11 // DHT 11
#define DHTTYPE DHT22 // DHT 22 (AM2302)
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
// Connect pin 1 (on the left) of the sensor to +5V

View File

@@ -1,5 +1,5 @@
name=DHT sensor library
version=1.1.0
version=1.2.3
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=Arduino library for DHT11, DHT22, etc Temp & Humidity Sensors