1/* DHT library 2 3MIT license 4written by Adafruit Industries 5*/ 6 7#include"DHT.h" 8 9#define MIN_INTERVAL 2000 10 11DHT::DHT(uint8_t pin,uint8_t type,uint8_t count) { 12 _pin = pin; 13 _type = type; 14#ifdef __AVR 15 _bit =digitalPinToBitMask(pin); 16 _port =digitalPinToPort(pin); 17#endif 18 _maxcycles =microsecondsToClockCycles(1000);// 1 millisecond timeout for 19// reading pulses from DHT sensor. 20// Note that count is now ignored as the DHT reading algorithm adjusts itself 21// basd on the speed of the processor. 22} 23 24voidDHT::begin(void) { 25// set up the pins! 26pinMode(_pin, INPUT_PULLUP); 27// Using this value makes sure that millis() - lastreadtime will be 28// >= MIN_INTERVAL right away. Note that this assignment wraps around, 29// but so will the subtraction. 30 _lastreadtime = -MIN_INTERVAL; 31DEBUG_PRINT("Max clock cycles: ");DEBUG_PRINTLN(_maxcycles, DEC); 32} 33 34//boolean S == Scale. True == Fahrenheit; False == Celcius 35floatDHT::readTemperature(bool S,bool force) { 36float f = NAN; 37 38if(read(force)) { 39switch(_type) { 40case DHT11: 41 f = data[2]; 42if(S) { 43 f =convertCtoF(f); 44} 45break; 46case DHT22: 47case DHT21: 48 f = data[2] &0x7F; 49 f *=256; 50 f += data[3]; 51 f *=0.1; 52if(data[2] &0x80) { 53 f *= -1; 54} 55if(S) { 56 f =convertCtoF(f); 57} 58break; 59} 60} 61return f; 62} 63 64floatDHT::convertCtoF(float c) { 65return c *1.8+32; 66} 67 68floatDHT::convertFtoC(float f) { 69return(f -32) *0.55555; 70} 71 72floatDHT::readHumidity(bool force) { 73float f = NAN; 74if(read()) { 75switch(_type) { 76case DHT11: 77 f = data[0]; 78break; 79case DHT22: 80case DHT21: 81 f = data[0]; 82 f *=256; 83 f += data[1]; 84 f *=0.1; 85break; 86} 87} 88return f; 89} 90 91//boolean isFahrenheit: True == Fahrenheit; False == Celcius 92floatDHT::computeHeatIndex(float temperature,float percentHumidity,bool isFahrenheit) { 93// Using both Rothfusz and Steadman's equations 94// http://www.wpc.ncep.noaa.gov/html/heatindex_equation.shtml 95float hi; 96 97if(!isFahrenheit) 98 temperature =convertCtoF(temperature); 99 100 hi =0.5* (temperature +61.0+ ((temperature -68.0) *1.2) + (percentHumidity *0.094)); 101 102if(hi >79) { 103 hi = -42.379+ 1042.04901523* temperature + 10510.14333127* percentHumidity + 106-0.22475541* temperature*percentHumidity + 107-0.00683783*pow(temperature,2) + 108-0.05481717*pow(percentHumidity,2) + 1090.00122874*pow(temperature,2) * percentHumidity + 1100.00085282* temperature*pow(percentHumidity,2) + 111-0.00000199*pow(temperature,2) *pow(percentHumidity,2); 112 113if((percentHumidity <13) && (temperature >=80.0) && (temperature <=112.0)) 114 hi -= ((13.0- percentHumidity) *0.25) *sqrt((17.0-abs(temperature -95.0)) *0.05882); 115 116else if((percentHumidity >85.0) && (temperature >=80.0) && (temperature <=87.0)) 117 hi += ((percentHumidity -85.0) *0.1) * ((87.0- temperature) *0.2); 118} 119 120return isFahrenheit ? hi :convertFtoC(hi); 121} 122 123boolean DHT::read(bool force) { 124// Check if sensor was read less than two seconds ago and return early 125// to use last reading. 126uint32_t currenttime =millis(); 127if(!force && ((currenttime - _lastreadtime) <2000)) { 128return _lastresult;// return last correct measurement 129} 130 _lastreadtime = currenttime; 131 132// Reset 40 bits of received data to zero. 133 data[0] = data[1] = data[2] = data[3] = data[4] =0; 134 135// Send start signal. See DHT datasheet for full signal diagram: 136// http://www.adafruit.com/datasheets/Digital%20humidity%20and%20temperature%20sensor%20AM2302.pdf 137 138// Go into high impedence state to let pull-up raise data line level and 139// start the reading process. 140digitalWrite(_pin, HIGH); 141delay(250); 142 143// First set data line low for 20 milliseconds. 144pinMode(_pin, OUTPUT); 145digitalWrite(_pin, LOW); 146delay(20); 147 148uint32_t cycles[80]; 149{ 150// Turn off interrupts temporarily because the next sections are timing critical 151// and we don't want any interruptions. 152 InterruptLock lock; 153 154// End the start signal by setting data line high for 40 microseconds. 155digitalWrite(_pin, HIGH); 156delayMicroseconds(40); 157 158// Now start reading the data line to get the value from the DHT sensor. 159pinMode(_pin, INPUT_PULLUP); 160delayMicroseconds(10);// Delay a bit to let sensor pull data line low. 161 162// First expect a low signal for ~80 microseconds followed by a high signal 163// for ~80 microseconds again. 164if(expectPulse(LOW) ==0) { 165DEBUG_PRINTLN(F("Timeout waiting for start signal low pulse.")); 166 _lastresult =false; 167return _lastresult; 168} 169if(expectPulse(HIGH) ==0) { 170DEBUG_PRINTLN(F("Timeout waiting for start signal high pulse.")); 171 _lastresult =false; 172return _lastresult; 173} 174 175// Now read the 40 bits sent by the sensor. Each bit is sent as a 50 176// microsecond low pulse followed by a variable length high pulse. If the 177// high pulse is ~28 microseconds then it's a 0 and if it's ~70 microseconds 178// then it's a 1. We measure the cycle count of the initial 50us low pulse 179// and use that to compare to the cycle count of the high pulse to determine 180// if the bit is a 0 (high state cycle count < low state cycle count), or a 181// 1 (high state cycle count > low state cycle count). Note that for speed all 182// the pulses are read into a array and then examined in a later step. 183for(int i=0; i<80; i+=2) { 184 cycles[i] =expectPulse(LOW); 185 cycles[i+1] =expectPulse(HIGH); 186} 187}// Timing critical code is now complete. 188 189// Inspect pulses and determine which ones are 0 (high state cycle count < low 190// state cycle count), or 1 (high state cycle count > low state cycle count). 191for(int i=0; i<40; ++i) { 192uint32_t lowCycles = cycles[2*i]; 193uint32_t highCycles = cycles[2*i+1]; 194if((lowCycles ==0) || (highCycles ==0)) { 195DEBUG_PRINTLN(F("Timeout waiting for pulse.")); 196 _lastresult =false; 197return _lastresult; 198} 199 data[i/8] <<=1; 200// Now compare the low and high cycle times to see if the bit is a 0 or 1. 201if(highCycles > lowCycles) { 202// High cycles are greater than 50us low cycle count, must be a 1. 203 data[i/8] |=1; 204} 205// Else high cycles are less than (or equal to, a weird case) the 50us low 206// cycle count so this must be a zero. Nothing needs to be changed in the 207// stored data. 208} 209 210DEBUG_PRINTLN(F("Received:")); 211DEBUG_PRINT(data[0], HEX);DEBUG_PRINT(F(", ")); 212DEBUG_PRINT(data[1], HEX);DEBUG_PRINT(F(", ")); 213DEBUG_PRINT(data[2], HEX);DEBUG_PRINT(F(", ")); 214DEBUG_PRINT(data[3], HEX);DEBUG_PRINT(F(", ")); 215DEBUG_PRINT(data[4], HEX);DEBUG_PRINT(F(" =? ")); 216DEBUG_PRINTLN((data[0] + data[1] + data[2] + data[3]) &0xFF, HEX); 217 218// Check we read 40 bits and that the checksum matches. 219if(data[4] == ((data[0] + data[1] + data[2] + data[3]) &0xFF)) { 220 _lastresult =true; 221return _lastresult; 222} 223else{ 224DEBUG_PRINTLN(F("Checksum failure!")); 225 _lastresult =false; 226return _lastresult; 227} 228} 229 230// Expect the signal line to be at the specified level for a period of time and 231// return a count of loop cycles spent at that level (this cycle count can be 232// used to compare the relative time of two pulses). If more than a millisecond 233// ellapses without the level changing then the call fails with a 0 response. 234// This is adapted from Arduino's pulseInLong function (which is only available 235// in the very latest IDE versions): 236// https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/wiring_pulse.c 237uint32_tDHT::expectPulse(bool level) { 238uint32_t count =0; 239// On AVR platforms use direct GPIO port access as it's much faster and better 240// for catching pulses that are 10's of microseconds in length: 241#ifdef __AVR 242uint8_t portState = level ? _bit :0; 243while((*portInputRegister(_port) & _bit) == portState) { 244if(count++ >= _maxcycles) { 245return0;// Exceeded timeout, fail. 246} 247} 248// Otherwise fall back to using digitalRead (this seems to be necessary on ESP8266 249// right now, perhaps bugs in direct port access functions?). 250#else 251while(digitalRead(_pin) == level) { 252if(count++ >= _maxcycles) { 253return0;// Exceeded timeout, fail. 254} 255} 256#endif 257 258return count; 259}