/* DHT library MIT license written by Adafruit Industries */ #include #include "DHT.h" //#define NAN 0 #ifdef DEBUG #define DEBUG_PRINT(...) Serial.println(__VA_ARGS__) #else #define DEBUG_PRINT(...) #endif DHT::DHT(uint8_t pin, uint8_t type, uint8_t count) { _pin = pin; _type = type; _count = count; firstreading = true; } DHT::DHT(uint8_t type) { _pin = 0; _type = type; _count = COUNT; firstreading = true; if (_type != DHT10){ DEBUG_PRINT("Error : No pins are defined\n"); } } void DHT::begin(void) { if (_type == DHT10) { if (DHT10Init()) { SERIALPRINT.println("Error : Failed to init DHT 11\n"); while (1); } } else { // set up the pins! pinMode(_pin, INPUT); digitalWrite(_pin, HIGH); _lastreadtime = 0; } } /** Common interface to get temp&humi value.support all DHT device. @return 0 for calibrated failed,1 for succeed. **/ int DHT::readTempAndHumidity(float* data) { uint32_t target_val[2] = {0}; uint32_t cnt = 0; if (_type == DHT10) { while (DHT10ReadStatus() == 0) { DHT10Init(); delay(30); cnt++; if (cnt > 3) { return -1; } } //wait for data ready。 while (readTargetData(target_val)) { cnt++; delay(50); if (cnt > 5) { return -1; } } data[0] = target_val[0] * 100.0 / 1024 / 1024; data[1] = target_val[1] * 200.0 / 1024 / 1024 - 50; } else { data[0] = readHumidity(); data[1] = readTemperature(); if (isnan(data[0]) || isnan(data[1])) { return -1; } } return 0; } //boolean S == Scale. True == Farenheit; False == Celcius float DHT::readTemperature(bool S) { if(_type == DHT10){ float temp[2]; readTempAndHumidity(temp); if (S) { temp[1] = convertCtoF(temp[1]); } return temp[1]; } else{ float f; if (read()) { switch (_type) { case DHT11: f = data[2]; if(data[3]%128<10){ f += data[3]%128/10.0f; }else if(data[3]%128<100){ f += data[3]%128/100.0f; }else{ f += data[3]%128/1000.0f; } if(data[3]>=128){ // The left-most digit indicate the negative sign. f = -f; } if (S) { f = convertCtoF(f); } return f; 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; } } } DEBUG_PRINT("Read fail"); return NAN; } float DHT::convertCtoF(float c) { return c * 9 / 5 + 32; } float DHT::readHumidity(void) { if(_type == DHT10){ float temp[2]; readTempAndHumidity(temp); return temp[0]; } else{ float f; if (read()) { switch (_type) { case DHT11: f = data[0]; return f; case DHT22: case DHT21: f = data[0]; f *= 256; f += data[1]; f /= 10; return f; } } } DEBUG_PRINT("Read fail"); return NAN; } boolean DHT::read(void) { uint8_t laststate = HIGH; uint8_t counter = 0; uint8_t j = 0, i; unsigned long currenttime; // pull the pin high and wait 250 milliseconds digitalWrite(_pin, HIGH); delay(250); currenttime = millis(); if (currenttime < _lastreadtime) { // ie there was a rollover _lastreadtime = 0; } if (!firstreading && ((currenttime - _lastreadtime) < 2000)) { return true; // return last correct measurement //delay(2000 - (currenttime - _lastreadtime)); } firstreading = false; /* DEBUG_PRINT("Currtime: "); DEBUG_PRINT(currenttime); DEBUG_PRINT(" Lasttime: "); DEBUG_PRINT(_lastreadtime); */ _lastreadtime = millis(); data[0] = data[1] = data[2] = data[3] = data[4] = 0; // now pull it low for ~20 milliseconds pinMode(_pin, OUTPUT); digitalWrite(_pin, LOW); delay(20); //cli(); digitalWrite(_pin, HIGH); delayMicroseconds(20); 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; } } 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++; } } //sei(); /* DEBUG_PRINTln(j, DEC); DEBUG_PRINT(data[0], HEX); DEBUG_PRINT(", "); DEBUG_PRINT(data[1], HEX); DEBUG_PRINT(", "); DEBUG_PRINT(data[2], HEX); DEBUG_PRINT(", "); DEBUG_PRINT(data[3], HEX); DEBUG_PRINT(", "); DEBUG_PRINT(data[4], HEX); DEBUG_PRINT(" =? "); DEBUG_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; } /*****************************************************************************/ /*****************************************************************************/ /** Reset sensor. @return 0 for calibrated failed,1 for succeed. **/ int DHT::DHT10Reset(void) { if (_type == DHT10) { return i2cWriteByte(RESET_REG_ADDR); } else { return 0; SERIALPRINT.println("This function only support for DHT10"); } } /** Read status register.check the calibration flag - bit[3]: 1- calibrated ok ,0 - Not calibrated. @return 0 for calibrated failed,1 for succeed. **/ int DHT::DHT10ReadStatus(void) { int ret = 0; uint8_t statu = 0; if (_type == DHT10) { ret = i2cReadByte(statu); if (ret) { SERIALPRINT.println("Failed to read byte\n"); } if ((statu & 0x8) == 0x8) { return 1; } else { return 0; } } else { SERIALPRINT.println("This function only support for DHT10"); return 0; } } /** Init sensor,send 0x08,0x00 to register 0xe1. @ return : 0 if success, non-zero if failed. **/ int DHT::setSystemCfg(void) { uint8_t cfg_param[] = {0xe1, 0x08, 0x00}; if (_type == DHT10) { return i2cWriteBytes(cfg_param, sizeof(cfg_param)); } else { SERIALPRINT.println("This function only support for DHT10"); return 0; } } /** Read temp & humi result buf from sensor. total 6 bytes,the first byte for status register,other 5 bytes for temp & humidity data. @ return : 0 if success, non-zero if failed. **/ int DHT::readTargetData(uint32_t* data) { uint8_t statu = 0; uint8_t bytes[6] = {0}; uint8_t cfg_params[] = {0xac, 0x33, 0x00}; //int ret = 0; if (_type == DHT10) { if (i2cWriteBytes(cfg_params, sizeof(cfg_params))) { return -1; } delay(75); // check device busy flag, bit[7]:1 for busy, 0 for idle. while ((statu & 0x80) == 0x80) { SERIALPRINT.println("Device busy!"); delay(200); if (i2cReadByte(statu)) { return -1; } } if (i2cReadBytes(bytes, sizeof(bytes))) { return -1; } data[HUMIDITY_INDEX] = (data[HUMIDITY_INDEX] | bytes[1]) << 8; data[HUMIDITY_INDEX] = (data[HUMIDITY_INDEX] | bytes[2]) << 8; data[HUMIDITY_INDEX] = (data[HUMIDITY_INDEX] | bytes[3]); data[HUMIDITY_INDEX] = data[HUMIDITY_INDEX] >> 4; data[TEMPRATURE_INDEX] = (data[TEMPRATURE_INDEX] | bytes[3]) << 8; data[TEMPRATURE_INDEX] = (data[TEMPRATURE_INDEX] | bytes[4]) << 8; data[TEMPRATURE_INDEX] = (data[TEMPRATURE_INDEX] | bytes[5]); data[TEMPRATURE_INDEX] &= 0xfffff; return 0; } else { SERIALPRINT.println("This function only support for DHT10"); return 0; } } /** DHT10 Init function. Reset sensor and wait for calibration complete. @ return : 0 if success, non-zero if failed. **/ int DHT::DHT10Init(void) { int ret = 0; int cnt = 0; if (_type == DHT10) { delay(500); DHT10Reset(); delay(300); ret = setSystemCfg(); if (ret) { SERIALPRINT.println("Failed to set system conf reg \n"); } //SERIALPRINT.println("Set system cfg OK!"); delay(500); while (DHT10ReadStatus() == 0) { SERIALPRINT.println("get status error!"); DHT10Reset(); delay(500); if (setSystemCfg()) { SERIALPRINT.println("Failed to set system conf reg \n"); } delay(500); cnt++; if (cnt > 5) { return -1; } } return 0; } else { SERIALPRINT.println("This function only support for DHT10"); return 0; } } /*****************************************************************************/ /*****************************************************************************/ int DHT::i2cReadByte(uint8_t& byte) { int cnt = 0; Wire.requestFrom(DEFAULT_IIC_ADDR, 1); while (1 != Wire.available()) { cnt++; if (cnt >= 10) { return -1; } delay(1); } byte = Wire.read(); return 0; } int DHT::i2cReadBytes(uint8_t* bytes, uint32_t len) { int cnt = 0; Wire.requestFrom(DEFAULT_IIC_ADDR, len); while (len != (uint32_t) Wire.available()) { cnt++; if (cnt >= 10) { return -1; } delay(1); } for (uint32_t i = 0; i < len; i++) { bytes[i] = Wire.read(); } return 0; } int DHT::i2cWriteBytes(uint8_t* bytes, uint32_t len) { Wire.beginTransmission(DEFAULT_IIC_ADDR); for (uint32_t i = 0; i < len; i++) { Wire.write(bytes[i]); } return Wire.endTransmission(); } int DHT::i2cWriteByte(uint8_t byte) { Wire.beginTransmission(DEFAULT_IIC_ADDR); Wire.write(byte); return Wire.endTransmission(); }