libraries / DHT-sensor-library-master / DHT.cppon commit Added link to project report (97a3ba0)
   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
  24void DHT::begin(void) {
  25  // set up the pins!
  26  pinMode(_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;
  31  DEBUG_PRINT("Max clock cycles: "); DEBUG_PRINTLN(_maxcycles, DEC);
  32}
  33
  34//boolean S == Scale.  True == Fahrenheit; False == Celcius
  35float DHT::readTemperature(bool S, bool force) {
  36  float f = NAN;
  37
  38  if (read(force)) {
  39    switch (_type) {
  40    case DHT11:
  41      f = data[2];
  42      if(S) {
  43        f = convertCtoF(f);
  44      }
  45      break;
  46    case DHT22:
  47    case DHT21:
  48      f = data[2] & 0x7F;
  49      f *= 256;
  50      f += data[3];
  51      f *= 0.1;
  52      if (data[2] & 0x80) {
  53        f *= -1;
  54      }
  55      if(S) {
  56        f = convertCtoF(f);
  57      }
  58      break;
  59    }
  60  }
  61  return f;
  62}
  63
  64float DHT::convertCtoF(float c) {
  65  return c * 1.8 + 32;
  66}
  67
  68float DHT::convertFtoC(float f) {
  69  return (f - 32) * 0.55555;
  70}
  71
  72float DHT::readHumidity(bool force) {
  73  float f = NAN;
  74  if (read()) {
  75    switch (_type) {
  76    case DHT11:
  77      f = data[0];
  78      break;
  79    case DHT22:
  80    case DHT21:
  81      f = data[0];
  82      f *= 256;
  83      f += data[1];
  84      f *= 0.1;
  85      break;
  86    }
  87  }
  88  return f;
  89}
  90
  91//boolean isFahrenheit: True == Fahrenheit; False == Celcius
  92float DHT::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
  95  float hi;
  96
  97  if (!isFahrenheit)
  98    temperature = convertCtoF(temperature);
  99
 100  hi = 0.5 * (temperature + 61.0 + ((temperature - 68.0) * 1.2) + (percentHumidity * 0.094));
 101
 102  if (hi > 79) {
 103    hi = -42.379 +
 104             2.04901523 * temperature +
 105            10.14333127 * percentHumidity +
 106            -0.22475541 * temperature*percentHumidity +
 107            -0.00683783 * pow(temperature, 2) +
 108            -0.05481717 * pow(percentHumidity, 2) +
 109             0.00122874 * pow(temperature, 2) * percentHumidity +
 110             0.00085282 * temperature*pow(percentHumidity, 2) +
 111            -0.00000199 * pow(temperature, 2) * pow(percentHumidity, 2);
 112
 113    if((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
 116    else if((percentHumidity > 85.0) && (temperature >= 80.0) && (temperature <= 87.0))
 117      hi += ((percentHumidity - 85.0) * 0.1) * ((87.0 - temperature) * 0.2);
 118  }
 119
 120  return 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.
 126  uint32_t currenttime = millis();
 127  if (!force && ((currenttime - _lastreadtime) < 2000)) {
 128    return _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.
 140  digitalWrite(_pin, HIGH);
 141  delay(250);
 142
 143  // First set data line low for 20 milliseconds.
 144  pinMode(_pin, OUTPUT);
 145  digitalWrite(_pin, LOW);
 146  delay(20);
 147
 148  uint32_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.
 155    digitalWrite(_pin, HIGH);
 156    delayMicroseconds(40);
 157
 158    // Now start reading the data line to get the value from the DHT sensor.
 159    pinMode(_pin, INPUT_PULLUP);
 160    delayMicroseconds(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.
 164    if (expectPulse(LOW) == 0) {
 165      DEBUG_PRINTLN(F("Timeout waiting for start signal low pulse."));
 166      _lastresult = false;
 167      return _lastresult;
 168    }
 169    if (expectPulse(HIGH) == 0) {
 170      DEBUG_PRINTLN(F("Timeout waiting for start signal high pulse."));
 171      _lastresult = false;
 172      return _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.
 183    for (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).
 191  for (int i=0; i<40; ++i) {
 192    uint32_t lowCycles  = cycles[2*i];
 193    uint32_t highCycles = cycles[2*i+1];
 194    if ((lowCycles == 0) || (highCycles == 0)) {
 195      DEBUG_PRINTLN(F("Timeout waiting for pulse."));
 196      _lastresult = false;
 197      return _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.
 201    if (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
 210  DEBUG_PRINTLN(F("Received:"));
 211  DEBUG_PRINT(data[0], HEX); DEBUG_PRINT(F(", "));
 212  DEBUG_PRINT(data[1], HEX); DEBUG_PRINT(F(", "));
 213  DEBUG_PRINT(data[2], HEX); DEBUG_PRINT(F(", "));
 214  DEBUG_PRINT(data[3], HEX); DEBUG_PRINT(F(", "));
 215  DEBUG_PRINT(data[4], HEX); DEBUG_PRINT(F(" =? "));
 216  DEBUG_PRINTLN((data[0] + data[1] + data[2] + data[3]) & 0xFF, HEX);
 217
 218  // Check we read 40 bits and that the checksum matches.
 219  if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
 220    _lastresult = true;
 221    return _lastresult;
 222  }
 223  else {
 224    DEBUG_PRINTLN(F("Checksum failure!"));
 225    _lastresult = false;
 226    return _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_t DHT::expectPulse(bool level) {
 238  uint32_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
 242    uint8_t portState = level ? _bit : 0;
 243    while ((*portInputRegister(_port) & _bit) == portState) {
 244      if (count++ >= _maxcycles) {
 245        return 0; // 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
 251    while (digitalRead(_pin) == level) {
 252      if (count++ >= _maxcycles) {
 253        return 0; // Exceeded timeout, fail.
 254      }
 255    }
 256  #endif
 257
 258  return count;
 259}