2 * FILE: PietteTech_DHT.cpp
4 * PURPOSE: Spark Interrupt driven lib for DHT sensors
5 * LICENSE: GPL v3 (http://www.gnu.org/licenses/gpl.html)
7 * S Piette (Piette Technologies) scott.piette@gmail.com
8 * January 2014 Original Spark Port
9 * October 2014 Added support for DHT21/22 sensors
10 * Improved timing, moved FP math out of ISR
12 * Based on adaptation by niesteszeck (github/niesteszeck)
13 * Based on original DHT11 library (http://playgroudn.adruino.cc/Main/DHT11Lib)
16 * This library supports the DHT sensor on the following pins
17 * D0, D1, D2, D3, D4, A0, A1, A3, A5, A6, A7
18 * http://docs.spark.io/firmware/#interrupts-attachinterrupt
23 Timing of DHT22 SDA signal line after MCU pulls low for 1ms
24 https://github.com/mtnscott/Spark_DHT/AM2302.pdf
26 - - - - ----- -- - - -- ------- - -
30 ------ ----- -- - --------
34 Ts : Start time from MCU changing SDA from Output High to Tri-State (Hi-Z)
35 Spec: 20-200us Tested: < 65us
36 Tr : DHT response to MCU controlling SDA and pulling Low and High to
37 start of first data bit
38 Spec: 150-170us Tested: 125 - 200us
39 Td : DHT data bit, falling edge to falling edge
40 Spec: '0' 70us - 85us Tested: 60 - 110us
41 Spec: '1' 116us - 130us Tested: 111 - 155us
42 Te : DHT releases SDA to Tri-State (Hi-Z)
43 Spec: 45-55us Not Tested
46 #include "application.h"
48 #include "PietteTech_DHT.h"
50 // Thanks to Paul Kourany for this word type conversion function
51 uint16_t word(uint8_t high, uint8_t low) {
52 uint16_t ret_val = low;
53 ret_val += (high << 8);
57 PietteTech_DHT::PietteTech_DHT(uint8_t sigPin, uint8_t dht_type, void (*callback_wrapper)()) {
58 begin(sigPin, dht_type, callback_wrapper);
62 void PietteTech_DHT::begin(uint8_t sigPin, uint8_t dht_type, void (*callback_wrapper) ()) {
65 isrCallback_wrapper = callback_wrapper;
67 pinMode(sigPin, OUTPUT);
68 digitalWrite(sigPin, HIGH);
71 _status = DHTLIB_ERROR_NOTSTARTED;
74 int PietteTech_DHT::acquire() {
75 // Check if sensor was read less than two seconds ago and return early
76 // to use last reading
77 unsigned long currenttime = millis();
78 if (currenttime < _lastreadtime) {
79 // there was a rollover
82 if (!_firstreading && ((currenttime - _lastreadtime) < 2000 )) {
83 // return last correct measurement, (this read time - last read time) < device limit
84 return DHTLIB_ACQUIRED;
87 if (_state == STOPPED || _state == ACQUIRED) {
89 * Setup the initial state machine
91 _firstreading = false;
92 _lastreadtime = currenttime;
95 #if defined(DHT_DEBUG_TIMING)
97 * Clear the debug timings array
99 for (int i = 0; i < 41; i++) _edges[i] = 0;
104 * Set the initial values in the buffer and variables
106 for (int i = 0; i < 5; i++) _bits[i] = 0;
113 * Toggle the digital output to trigger the DHT device
114 * to send us temperature and humidity data
116 pinMode(_sigPin, OUTPUT);
117 digitalWrite(_sigPin, LOW);
119 delay(18); // DHT11 Spec: 18ms min
121 delayMicroseconds(1500); // DHT22 Spec: 0.8-20ms, 1ms typ
122 pinMode(_sigPin, INPUT); // Note Hi-Z mode with pullup resistor
123 // will keep this high until the DHT responds.
125 * Attach the interrupt handler to receive the data once the DHT
126 * starts to send us data
129 attachInterrupt(_sigPin, isrCallback_wrapper, FALLING);
131 return DHTLIB_ACQUIRING;
133 return DHTLIB_ERROR_ACQUIRING;
136 int PietteTech_DHT::acquireAndWait() {
142 void PietteTech_DHT::isrCallback() {
143 unsigned long newUs = micros();
144 unsigned long delta = (newUs - _us);
148 _status = DHTLIB_ERROR_ISR_TIMEOUT;
150 detachInterrupt(_sigPin);
154 case RESPONSE: // Spec: 80us LOW followed by 80us HIGH
155 if(delta < 65) { // Spec: 20-200us to first falling edge of response
157 break; //do nothing, it started the response signal
158 } if(125 < delta && delta < 200) {
159 #if defined(DHT_DEBUG_TIMING)
160 *_e++ = delta; // record the edge -> edge time
164 detachInterrupt(_sigPin);
165 _status = DHTLIB_ERROR_RESPONSE_TIMEOUT;
167 #if defined(DHT_DEBUG_TIMING)
168 *_e++ = delta; // record the edge -> edge time
172 case DATA: // Spec: 50us low followed by high of 26-28us = 0, 70us = 1
173 if(60 < delta && delta < 155) { //valid in timing
174 _bits[_idx] <<= 1; // shift the data
175 if(delta > 110) //is a one
177 #if defined(DHT_DEBUG_TIMING)
178 *_e++ = delta; // record the edge -> edge time
180 if (_cnt == 0) { // we have completed the byte, go to next
181 _cnt = 7; // restart at MSB
182 if(++_idx == 5) { // go to next byte, if we have got 5 bytes stop.
183 detachInterrupt(_sigPin);
185 uint8_t sum = _bits[0] + _bits[1] + _bits[2] + _bits[3];
186 if (_bits[4] != sum) {
187 _status = DHTLIB_ERROR_CHECKSUM;
197 } else if(delta < 10) {
198 detachInterrupt(_sigPin);
199 _status = DHTLIB_ERROR_DELTA;
202 detachInterrupt(_sigPin);
203 _status = DHTLIB_ERROR_DATA_TIMEOUT;
212 void PietteTech_DHT::convert() {
213 // Calculate the temperature and humidity based on the sensor type
221 _hum = word(_bits[0], _bits[1]) * 0.1;
222 _temp = (_bits[2] & 0x80 ?
223 -word(_bits[2] & 0x7F, _bits[3]) :
224 word(_bits[2], _bits[3])) * 0.1;
230 bool PietteTech_DHT::acquiring() {
231 if (_state != ACQUIRED && _state != STOPPED)
236 int PietteTech_DHT::getStatus() {
240 float PietteTech_DHT::getCelsius() {
245 float PietteTech_DHT::getHumidity() {
250 float PietteTech_DHT::getFahrenheit() {
252 return _temp * 9 / 5 + 32;
255 float PietteTech_DHT::getKelvin() {
257 return _temp + 273.15;
261 * Added methods for supporting Adafruit Unified Sensor framework
263 float PietteTech_DHT::readTemperature() {
268 float PietteTech_DHT::readHumidity() {
270 return getHumidity();
273 // delta max = 0.6544 wrt dewPoint()
274 // 5x faster than dewPoint()
275 // reference: http://en.wikipedia.org/wiki/Dew_point
276 double PietteTech_DHT::getDewPoint() {
280 double temp_ = (a * (double) _temp) / (b + (double) _temp) + log( (double) _hum/100);
281 double Td = (b * temp_) / (a - temp_);
285 // dewPoint function NOAA
286 // reference: http://wahiduddin.net/calc/density_algorithms.htm
287 double PietteTech_DHT::getDewPointSlow() {
289 double a0 = (double) 373.15 / (273.15 + (double) _temp);
290 double SUM = (double) -7.90298 * (a0-1.0);
291 SUM += 5.02808 * log10(a0);
292 SUM += -1.3816e-7 * (pow(10, (11.344*(1-1/a0)))-1) ;
293 SUM += 8.1328e-3 * (pow(10,(-3.49149*(a0-1)))-1) ;
294 SUM += log10(1013.246);
295 double VP = pow(10, SUM-3) * (double) _hum;
296 double T = log(VP/0.61078); // temp var
297 return (241.88 * T) / (17.558-T);