17 Commits
1.0.0 ... 1.2.0

Author SHA1 Message Date
6c0c723907 Merge branch 'matthijskooijman-fixes' 2015-09-15 12:26:54 -07:00
232ad0cd70 Bump version to 1.2.0 after integrating optimizations from matthijskooijman. 2015-09-15 12:26:38 -07:00
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
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
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
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
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
5cd78aead6 Fix merge conflict with interrupt disable lock. 2015-07-22 12:22:35 -07:00
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
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
a2208eb813 Cause interrupts to be reenabled if a timeout occurs while waiting for the sensor. 2015-07-01 17:58:17 -07:00
a1393fc0ff Merge branch 'MyIgel-master' 2015-06-26 15:56:28 -07:00
ef9590ad96 Fix merge conflicts, make compute heat index default to Fahrenheit to not break old code that assumes default is Fahrenheit. 2015-06-26 15:56:04 -07:00
b6925ee001 Merge branch 'dynamic_timing' 2015-06-26 15:17:28 -07:00
729895339c Integrate keywords.txt from pull #31 2015-06-26 15:15:45 -07:00
9d7a9da8ae Refactor algorithm to dynamically adjust to faster/slower processors. Fix #35 #30. 2015-06-26 15:14:17 -07:00
25942ac8b9 Added support for Celsius in computeHeatIndex 2014-11-01 12:27:16 +01:00
5 changed files with 296 additions and 171 deletions

292
DHT.cpp
View File

@ -1,4 +1,4 @@
/* DHT library
/* DHT library
MIT license
written by Adafruit Industries
@ -6,174 +6,250 @@ 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;
_count = count;
firstreading = true;
_bit = digitalPinToBitMask(pin);
_port = digitalPinToPort(pin);
_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 == Farenheit; False == Celcius
float DHT::readTemperature(bool S) {
float f;
//boolean S == Scale. True == Fahrenheit; False == Celcius
float DHT::readTemperature(bool S, bool force) {
float f = NAN;
if (read()) {
if (read(force)) {
switch (_type) {
case DHT11:
f = data[2];
if(S)
f = convertCtoF(f);
return f;
if(S) {
f = convertCtoF(f);
}
break;
case DHT22:
case DHT21:
f = data[2] & 0x7F;
f *= 256;
f += data[3];
f /= 10;
if (data[2] & 0x80)
f *= -1;
if(S)
f = convertCtoF(f);
return f;
if (data[2] & 0x80) {
f *= -1;
}
if(S) {
f = convertCtoF(f);
}
break;
}
}
return NAN;
return f;
}
float DHT::convertCtoF(float c) {
return c * 9 / 5 + 32;
return c * 9 / 5 + 32;
}
float DHT::convertFtoC(float f) {
return (f - 32) * 5 / 9;
return (f - 32) * 5 / 9;
}
float DHT::readHumidity(void) {
float f;
float DHT::readHumidity(bool force) {
float f = NAN;
if (read()) {
switch (_type) {
case DHT11:
f = data[0];
return f;
break;
case DHT22:
case DHT21:
f = data[0];
f *= 256;
f += data[1];
f /= 10;
return f;
break;
}
}
return NAN;
return f;
}
float DHT::computeHeatIndex(float tempFahrenheit, float percentHumidity) {
//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
return -42.379 +
2.04901523 * tempFahrenheit +
10.14333127 * percentHumidity +
-0.22475541 * tempFahrenheit*percentHumidity +
-0.00683783 * pow(tempFahrenheit, 2) +
-0.05481717 * pow(percentHumidity, 2) +
0.00122874 * pow(tempFahrenheit, 2) * percentHumidity +
0.00085282 * tempFahrenheit*pow(percentHumidity, 2) +
-0.00000199 * pow(tempFahrenheit, 2) * pow(percentHumidity, 2);
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 +
2.04901523 * temperature +
10.14333127 * percentHumidity +
-0.22475541 * temperature*percentHumidity +
-0.00683783 * pow(temperature, 2) +
-0.05481717 * pow(percentHumidity, 2) +
0.00122874 * pow(temperature, 2) * percentHumidity +
0.00085282 * temperature*pow(percentHumidity, 2) +
-0.00000199 * pow(temperature, 2) * pow(percentHumidity, 2);
}
}
boolean DHT::read(void) {
uint8_t laststate = HIGH;
uint8_t counter = 0;
uint8_t j = 0, i;
unsigned long currenttime;
boolean DHT::read(bool force) {
// Check if sensor was read less than two seconds ago and return early
// to use last reading.
currenttime = millis();
if (currenttime < _lastreadtime) {
// ie there was a rollover
_lastreadtime = 0;
uint32_t currenttime = millis();
if (!force && ((currenttime - _lastreadtime) < 2000)) {
return _lastresult; // return last correct measurement
}
if (!firstreading && ((currenttime - _lastreadtime) < 2000)) {
return true; // return last correct measurement
//delay(2000 - (currenttime - _lastreadtime));
}
firstreading = false;
/*
Serial.print("Currtime: "); Serial.print(currenttime);
Serial.print(" Lasttime: "); Serial.print(_lastreadtime);
*/
_lastreadtime = millis();
_lastreadtime = currenttime;
// Reset 40 bits of received data to zero.
data[0] = data[1] = data[2] = data[3] = data[4] = 0;
// pull the pin high and wait 250 milliseconds
// 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);
// now pull it low for ~20 milliseconds
// First set data line low for 20 milliseconds.
pinMode(_pin, OUTPUT);
digitalWrite(_pin, LOW);
delay(20);
noInterrupts();
digitalWrite(_pin, HIGH);
delayMicroseconds(40);
pinMode(_pin, INPUT);
// read in timings
for ( i=0; i< MAXTIMINGS; i++) {
counter = 0;
while (digitalRead(_pin) == laststate) {
counter++;
delayMicroseconds(1);
if (counter == 255) {
break;
uint32_t cycles[80];
{
// Turn off interrupts temporarily because the next sections are timing critical
// and we don't want any interruptions.
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_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
// for ~80 microseconds again.
if (expectPulse(LOW) == 0) {
DEBUG_PRINTLN(F("Timeout waiting for start signal low pulse."));
_lastresult = false;
return _lastresult;
}
if (expectPulse(HIGH) == 0) {
DEBUG_PRINTLN(F("Timeout waiting for start signal high pulse."));
_lastresult = false;
return _lastresult;
}
// Now read the 40 bits sent by the sensor. Each bit is sent as a 50
// microsecond low pulse followed by a variable length high pulse. If the
// high pulse is ~28 microseconds then it's a 0 and if it's ~70 microseconds
// 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). 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);
}
} // 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;
}
data[i/8] <<= 1;
// Now compare the low and high cycle times to see if the bit is a 0 or 1.
if (highCycles > lowCycles) {
// High cycles are greater than 50us low cycle count, must be a 1.
data[i/8] |= 1;
}
// Else high cycles are less than (or equal to, a weird case) the 50us low
// cycle count so this must be a zero. Nothing needs to be changed in the
// stored data.
}
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]) & 0xFF, HEX);
// Check we read 40 bits and that the checksum matches.
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
_lastresult = true;
return _lastresult;
}
else {
DEBUG_PRINTLN(F("Checksum failure!"));
_lastresult = false;
return _lastresult;
}
}
// Expect the signal line to be at the specified level for a period of time and
// 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;
// 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.
}
}
laststate = digitalRead(_pin);
if (counter == 255) break;
// ignore first 3 transitions
if ((i >= 4) && (i%2 == 0)) {
// shove each bit into the storage bytes
data[j/8] <<= 1;
if (counter > _count)
data[j/8] |= 1;
j++;
// 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) {
if (count++ >= _maxcycles) {
return 0; // Exceeded timeout, fail.
}
}
#endif
}
interrupts();
/*
Serial.println(j, DEC);
Serial.print(data[0], HEX); Serial.print(", ");
Serial.print(data[1], HEX); Serial.print(", ");
Serial.print(data[2], HEX); Serial.print(", ");
Serial.print(data[3], HEX); Serial.print(", ");
Serial.print(data[4], HEX); Serial.print(" =? ");
Serial.println(data[0] + data[1] + data[2] + data[3], HEX);
*/
// check we read 40 bits and that the checksum matches
if ((j >= 40) &&
(data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
return true;
}
return false;
return count;
}

111
DHT.h
View File

@ -1,41 +1,70 @@
#ifndef DHT_H
#define DHT_H
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
/* DHT library
MIT license
written by Adafruit Industries
*/
// how many timing transitions we need to keep track of. 2 * number bits + extra
#define MAXTIMINGS 85
#define DHT11 11
#define DHT22 22
#define DHT21 21
#define AM2301 21
class DHT {
private:
uint8_t data[6];
uint8_t _pin, _type, _count;
unsigned long _lastreadtime;
boolean firstreading;
public:
DHT(uint8_t pin, uint8_t type, uint8_t count=6);
void begin(void);
float readTemperature(bool S=false);
float convertCtoF(float);
float convertFtoC(float);
float computeHeatIndex(float tempFahrenheit, float percentHumidity);
float readHumidity(void);
boolean read(void);
};
#endif
/* DHT library
MIT license
written by Adafruit Industries
*/
#ifndef DHT_H
#define DHT_H
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
// Uncomment to enable printing out nice debug messages.
//#define DHT_DEBUG
// Define where debug output will be printed.
#define DEBUG_PRINTER Serial
// Setup debug printing macros.
#ifdef DHT_DEBUG
#define DEBUG_PRINT(...) { DEBUG_PRINTER.print(__VA_ARGS__); }
#define DEBUG_PRINTLN(...) { DEBUG_PRINTER.println(__VA_ARGS__); }
#else
#define DEBUG_PRINT(...) {}
#define DEBUG_PRINTLN(...) {}
#endif
// Define types of sensors.
#define DHT11 11
#define DHT22 22
#define DHT21 21
#define AM2301 21
class DHT {
public:
DHT(uint8_t pin, uint8_t type, uint8_t count=6);
void begin(void);
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(bool force=false);
boolean read(bool force=false);
private:
uint8_t data[5];
uint8_t _pin, _type, _bit, _port;
uint32_t _lastreadtime, _maxcycles;
bool _lastresult;
uint32_t expectPulse(bool level);
};
class InterruptLock {
public:
InterruptLock() {
noInterrupts();
}
~InterruptLock() {
interrupts();
}
};
#endif

View File

@ -6,7 +6,7 @@
#define DHTPIN 2 // what pin we're connected to
// Uncomment whatever type you're using!
//#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT11 // DHT 11
#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
@ -17,21 +17,16 @@
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor
// Initialize DHT sensor for normal 16mhz Arduino
// Initialize DHT sensor.
// Note that older versions of this library took an optional third parameter to
// tweak the timings for faster processors. This parameter is no longer needed
// as the current DHT reading algorithm adjusts itself to work on faster procs.
DHT dht(DHTPIN, DHTTYPE);
// NOTE: For working with a faster chip, like an Arduino Due or Teensy, you
// might need to increase the threshold for cycle counts considered a 1 or 0.
// You can do this by passing a 3rd parameter for this threshold. It's a bit
// of fiddling to find the right value, but in general the faster the CPU the
// higher the value. The default for a 16mhz AVR is a value of 6. For an
// Arduino Due that runs at 84mhz a value of 30 works.
// Example to initialize DHT sensor for Arduino Due:
//DHT dht(DHTPIN, DHTTYPE, 30);
void setup() {
Serial.begin(9600);
Serial.begin(9600);
Serial.println("DHTxx test!");
dht.begin();
}
@ -42,30 +37,33 @@ void loop() {
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
// Read temperature as Celsius
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Read temperature as Fahrenheit
// Read temperature as Fahrenheit (isFahrenheit = true)
float f = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t) || isnan(f)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
// Compute heat index
// Must send in temp in Fahrenheit!
float hi = dht.computeHeatIndex(f, h);
// Compute heat index in Fahrenheit (the default)
float hif = dht.computeHeatIndex(f, h);
// Compute heat index in Celsius (isFahreheit = false)
float hic = dht.computeHeatIndex(t, h, false);
Serial.print("Humidity: ");
Serial.print("Humidity: ");
Serial.print(h);
Serial.print(" %\t");
Serial.print("Temperature: ");
Serial.print("Temperature: ");
Serial.print(t);
Serial.print(" *C ");
Serial.print(f);
Serial.print(" *F\t");
Serial.print("Heat index: ");
Serial.print(hi);
Serial.print(hic);
Serial.print(" *C ");
Serial.print(hif);
Serial.println(" *F");
}

22
keywords.txt Normal file
View File

@ -0,0 +1,22 @@
###########################################
# Syntax Coloring Map For DHT-sensor-library
###########################################
###########################################
# Datatypes (KEYWORD1)
###########################################
DHT KEYWORD1
###########################################
# Methods and Functions (KEYWORD2)
###########################################
begin KEYWORD2
readTemperature KEYWORD2
convertCtoF KEYWORD2
convertFtoC KEYWORD2
computeHeatIndex KEYWORD2
readHumidity KEYWORD2
read KEYWORD2

View File

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