/* DHT library MIT license written by Adafruit Industries */ // Modified by Ziver Koc // #include "SensorDHT.h" void SensorDHT::setup() { // set up the pins! pinMode(_pin, INPUT_PULLUP); #ifdef __AVR _bit = digitalPinToBitMask(_pin); _port = digitalPinToPort(_pin); #endif _maxcycles = microsecondsToClockCycles(1000); // 1 millisecond timeout for // reading pulses from DHT sensor. } // 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 SensorDHT::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. } } // 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 return count; } void SensorDHT::read(TemperatureData& retData) { // Reset 40 bits of received data to zero. static uint8_t data[5]; data[0] = data[1] = data[2] = data[3] = data[4] = 0; // 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); // First set data line low for 20 milliseconds. pinMode(_pin, OUTPUT); 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(); // 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("DHT:Timeout waiting for start signal low pulse."); interrupts(); return; } if (expectPulse(HIGH) == 0) { DEBUG("DHT:Timeout waiting for start signal high pulse."); interrupts(); return; } // 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); } interrupts(); } // 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("DHT:Timeout waiting for pulse."); return; } 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. } // Check we read 40 bits and that the checksum matches. if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) { switch (_type) { case DHT11: retData.temperature = data[2]; retData.humidity = data[0]; break; case DHT22: case DHT21: retData.temperature = data[2] & 0x7F; retData.temperature *= 256; retData.temperature += data[3]; retData.temperature *= 0.1; if (data[2] & 0x80) { retData.temperature *= -1; } retData.humidity = data[0]; retData.humidity *= 256; retData.humidity += data[1]; retData.humidity *= 0.1; break; } } else { DEBUG("DHT:Checksum failure!"); } }