Skip to content

Commit b6925ee

Browse files
committed
Merge branch 'dynamic_timing'
2 parents a67e1a7 + 7298953 commit b6925ee

File tree

5 files changed

+216
-139
lines changed

5 files changed

+216
-139
lines changed

DHT.cpp

Lines changed: 123 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* DHT library
1+
/* DHT library
22
33
MIT license
44
written by Adafruit Industries
@@ -9,8 +9,9 @@ written by Adafruit Industries
99
DHT::DHT(uint8_t pin, uint8_t type, uint8_t count) {
1010
_pin = pin;
1111
_type = type;
12-
_count = count;
13-
firstreading = true;
12+
_firstreading = true;
13+
// Note that count is now ignored as the DHT reading algorithm adjusts itself
14+
// basd on the speed of the processor.
1415
}
1516

1617
void DHT::begin(void) {
@@ -22,158 +23,198 @@ void DHT::begin(void) {
2223

2324
//boolean S == Scale. True == Farenheit; False == Celcius
2425
float DHT::readTemperature(bool S) {
25-
float f;
26+
float f = NAN;
2627

2728
if (read()) {
2829
switch (_type) {
2930
case DHT11:
3031
f = data[2];
31-
if(S)
32-
f = convertCtoF(f);
33-
34-
return f;
32+
if(S) {
33+
f = convertCtoF(f);
34+
}
35+
break;
3536
case DHT22:
3637
case DHT21:
3738
f = data[2] & 0x7F;
3839
f *= 256;
3940
f += data[3];
4041
f /= 10;
41-
if (data[2] & 0x80)
42-
f *= -1;
43-
if(S)
44-
f = convertCtoF(f);
45-
46-
return f;
42+
if (data[2] & 0x80) {
43+
f *= -1;
44+
}
45+
if(S) {
46+
f = convertCtoF(f);
47+
}
48+
break;
4749
}
4850
}
49-
return NAN;
51+
return f;
5052
}
5153

5254
float DHT::convertCtoF(float c) {
53-
return c * 9 / 5 + 32;
55+
return c * 9 / 5 + 32;
5456
}
5557

5658
float DHT::convertFtoC(float f) {
57-
return (f - 32) * 5 / 9;
59+
return (f - 32) * 5 / 9;
5860
}
5961

6062
float DHT::readHumidity(void) {
61-
float f;
63+
float f = NAN;
6264
if (read()) {
6365
switch (_type) {
6466
case DHT11:
6567
f = data[0];
66-
return f;
68+
break;
6769
case DHT22:
6870
case DHT21:
6971
f = data[0];
7072
f *= 256;
7173
f += data[1];
7274
f /= 10;
73-
return f;
75+
break;
7476
}
7577
}
76-
return NAN;
78+
return f;
7779
}
7880

7981
float DHT::computeHeatIndex(float tempFahrenheit, float percentHumidity) {
8082
// Adapted from equation at: https://github.com/adafruit/DHT-sensor-library/issues/9 and
8183
// Wikipedia: http://en.wikipedia.org/wiki/Heat_index
82-
return -42.379 +
83-
2.04901523 * tempFahrenheit +
84+
return -42.379 +
85+
2.04901523 * tempFahrenheit +
8486
10.14333127 * percentHumidity +
8587
-0.22475541 * tempFahrenheit*percentHumidity +
8688
-0.00683783 * pow(tempFahrenheit, 2) +
87-
-0.05481717 * pow(percentHumidity, 2) +
88-
0.00122874 * pow(tempFahrenheit, 2) * percentHumidity +
89+
-0.05481717 * pow(percentHumidity, 2) +
90+
0.00122874 * pow(tempFahrenheit, 2) * percentHumidity +
8991
0.00085282 * tempFahrenheit*pow(percentHumidity, 2) +
9092
-0.00000199 * pow(tempFahrenheit, 2) * pow(percentHumidity, 2);
9193
}
9294

93-
9495
boolean DHT::read(void) {
95-
uint8_t laststate = HIGH;
96-
uint8_t counter = 0;
97-
uint8_t j = 0, i;
98-
unsigned long currenttime;
99-
10096
// Check if sensor was read less than two seconds ago and return early
10197
// to use last reading.
102-
currenttime = millis();
98+
uint32_t currenttime = millis();
10399
if (currenttime < _lastreadtime) {
104100
// ie there was a rollover
105101
_lastreadtime = 0;
106102
}
107-
if (!firstreading && ((currenttime - _lastreadtime) < 2000)) {
108-
return true; // return last correct measurement
109-
//delay(2000 - (currenttime - _lastreadtime));
103+
if (!_firstreading && ((currenttime - _lastreadtime) < 2000)) {
104+
return _lastresult; // return last correct measurement
110105
}
111-
firstreading = false;
112-
/*
113-
Serial.print("Currtime: "); Serial.print(currenttime);
114-
Serial.print(" Lasttime: "); Serial.print(_lastreadtime);
115-
*/
106+
_firstreading = false;
116107
_lastreadtime = millis();
117108

109+
// Reset 40 bits of received data to zero.
118110
data[0] = data[1] = data[2] = data[3] = data[4] = 0;
119-
120-
// pull the pin high and wait 250 milliseconds
111+
112+
// Send start signal. See DHT datasheet for full signal diagram:
113+
// http://www.adafruit.com/datasheets/Digital%20humidity%20and%20temperature%20sensor%20AM2302.pdf
114+
115+
// Go into high impedence state to let pull-up raise data line level and
116+
// start the reading process.
121117
digitalWrite(_pin, HIGH);
122118
delay(250);
123119

124-
// now pull it low for ~20 milliseconds
120+
// First set data line low for 20 milliseconds.
125121
pinMode(_pin, OUTPUT);
126122
digitalWrite(_pin, LOW);
127123
delay(20);
124+
125+
// Turn off interrupts temporarily because the next sections are timing critical
126+
// and we don't want any interruptions.
128127
noInterrupts();
128+
129+
// End the start signal by setting data line high for 40 microseconds.
129130
digitalWrite(_pin, HIGH);
130131
delayMicroseconds(40);
132+
133+
// Now start reading the data line to get the value from the DHT sensor.
131134
pinMode(_pin, INPUT);
135+
delayMicroseconds(10); // Delay a bit to let sensor pull data line low.
136+
137+
// First expect a low signal for ~80 microseconds followed by a high signal
138+
// for ~80 microseconds again.
139+
if (expectPulse(LOW) == 0) {
140+
DEBUG_PRINTLN(F("Timeout waiting for start signal low pulse."));
141+
_lastresult = false;
142+
return _lastresult;
143+
}
144+
if (expectPulse(HIGH) == 0) {
145+
DEBUG_PRINTLN(F("Timeout waiting for start signal high pulse."));
146+
_lastresult = false;
147+
return _lastresult;
148+
}
132149

133-
// read in timings
134-
for ( i=0; i< MAXTIMINGS; i++) {
135-
counter = 0;
136-
while (digitalRead(_pin) == laststate) {
137-
counter++;
138-
delayMicroseconds(1);
139-
if (counter == 255) {
140-
break;
141-
}
150+
// Now read the 40 bits sent by the sensor. Each bit is sent as a 50
151+
// microsecond low pulse followed by a variable length high pulse. If the
152+
// high pulse is ~28 microseconds then it's a 0 and if it's ~70 microseconds
153+
// then it's a 1. We measure the cycle count of the initial 50us low pulse
154+
// and use that to compare to the cycle count of the high pulse to determine
155+
// if the bit is a 0 (high state cycle count < low state cycle count), or a
156+
// 1 (high state cycle count > low state cycle count).
157+
for (int i=0; i<40; ++i) {
158+
uint32_t lowCycles = expectPulse(LOW);
159+
if (lowCycles == 0) {
160+
DEBUG_PRINTLN(F("Timeout waiting for bit low pulse."));
161+
_lastresult = false;
162+
return _lastresult;
142163
}
143-
laststate = digitalRead(_pin);
144-
145-
if (counter == 255) break;
146-
147-
// ignore first 3 transitions
148-
if ((i >= 4) && (i%2 == 0)) {
149-
// shove each bit into the storage bytes
150-
data[j/8] <<= 1;
151-
if (counter > _count)
152-
data[j/8] |= 1;
153-
j++;
164+
uint32_t highCycles = expectPulse(HIGH);
165+
if (highCycles == 0) {
166+
DEBUG_PRINTLN(F("Timeout waiting for bit high pulse."));
167+
_lastresult = false;
168+
return _lastresult;
154169
}
155-
170+
data[i/8] <<= 1;
171+
// Now compare the low and high cycle times to see if the bit is a 0 or 1.
172+
if (highCycles > lowCycles) {
173+
// High cycles are greater than 50us low cycle count, must be a 1.
174+
data[i/8] |= 1;
175+
}
176+
// Else high cycles are less than (or equal to, a weird case) the 50us low
177+
// cycle count so this must be a zero. Nothing needs to be changed in the
178+
// stored data.
156179
}
157180

181+
// Re-enable interrupts, timing critical code is complete.
158182
interrupts();
159-
160-
/*
161-
Serial.println(j, DEC);
162-
Serial.print(data[0], HEX); Serial.print(", ");
163-
Serial.print(data[1], HEX); Serial.print(", ");
164-
Serial.print(data[2], HEX); Serial.print(", ");
165-
Serial.print(data[3], HEX); Serial.print(", ");
166-
Serial.print(data[4], HEX); Serial.print(" =? ");
167-
Serial.println(data[0] + data[1] + data[2] + data[3], HEX);
168-
*/
169-
170-
// check we read 40 bits and that the checksum matches
171-
if ((j >= 40) &&
172-
(data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
173-
return true;
174-
}
175-
176183

177-
return false;
184+
DEBUG_PRINTLN(F("Received:"));
185+
DEBUG_PRINT(data[0], HEX); DEBUG_PRINT(F(", "));
186+
DEBUG_PRINT(data[1], HEX); DEBUG_PRINT(F(", "));
187+
DEBUG_PRINT(data[2], HEX); DEBUG_PRINT(F(", "));
188+
DEBUG_PRINT(data[3], HEX); DEBUG_PRINT(F(", "));
189+
DEBUG_PRINT(data[4], HEX); DEBUG_PRINT(F(" =? "));
190+
DEBUG_PRINTLN(data[0] + data[1] + data[2] + data[3], HEX);
191+
192+
// Check we read 40 bits and that the checksum matches.
193+
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
194+
_lastresult = true;
195+
return _lastresult;
196+
}
197+
else {
198+
DEBUG_PRINTLN(F("Checksum failure!"));
199+
_lastresult = false;
200+
return _lastresult;
201+
}
202+
}
178203

204+
// Expect the signal line to be at the specified level for a period of time and
205+
// return a count of loop cycles spent at that level (this cycle count can be
206+
// used to compare the relative time of two pulses). If more than a millisecond
207+
// ellapses without the level changing then the call fails with a 0 response.
208+
uint32_t DHT::expectPulse(bool level) {
209+
uint32_t count = 0;
210+
uint32_t end = micros() + 1000;
211+
// Loop while counting cycles until the level changes.
212+
while (digitalRead(_pin) == level) {
213+
count++;
214+
if (micros() >= end) {
215+
// Exceeded timeout waiting for level to change, fail.
216+
return 0;
217+
}
218+
}
219+
return count;
179220
}

DHT.h

Lines changed: 60 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,60 @@
1-
#ifndef DHT_H
2-
#define DHT_H
3-
#if ARDUINO >= 100
4-
#include "Arduino.h"
5-
#else
6-
#include "WProgram.h"
7-
#endif
8-
9-
/* DHT library
10-
11-
MIT license
12-
written by Adafruit Industries
13-
*/
14-
15-
// how many timing transitions we need to keep track of. 2 * number bits + extra
16-
#define MAXTIMINGS 85
17-
18-
#define DHT11 11
19-
#define DHT22 22
20-
#define DHT21 21
21-
#define AM2301 21
22-
23-
class DHT {
24-
private:
25-
uint8_t data[6];
26-
uint8_t _pin, _type, _count;
27-
unsigned long _lastreadtime;
28-
boolean firstreading;
29-
30-
public:
31-
DHT(uint8_t pin, uint8_t type, uint8_t count=6);
32-
void begin(void);
33-
float readTemperature(bool S=false);
34-
float convertCtoF(float);
35-
float convertFtoC(float);
36-
float computeHeatIndex(float tempFahrenheit, float percentHumidity);
37-
float readHumidity(void);
38-
boolean read(void);
39-
40-
};
41-
#endif
1+
/* DHT library
2+
3+
MIT license
4+
written by Adafruit Industries
5+
*/
6+
#ifndef DHT_H
7+
#define DHT_H
8+
9+
#if ARDUINO >= 100
10+
#include "Arduino.h"
11+
#else
12+
#include "WProgram.h"
13+
#endif
14+
15+
16+
// Uncomment to enable printing out nice debug messages.
17+
//#define DHT_DEBUG
18+
19+
// Define where debug output will be printed.
20+
#define DEBUG_PRINTER Serial
21+
22+
// Setup debug printing macros.
23+
#ifdef DHT_DEBUG
24+
#define DEBUG_PRINT(...) { DEBUG_PRINTER.print(__VA_ARGS__); }
25+
#define DEBUG_PRINTLN(...) { DEBUG_PRINTER.println(__VA_ARGS__); }
26+
#else
27+
#define DEBUG_PRINT(...) {}
28+
#define DEBUG_PRINTLN(...) {}
29+
#endif
30+
31+
// Define types of sensors.
32+
#define DHT11 11
33+
#define DHT22 22
34+
#define DHT21 21
35+
#define AM2301 21
36+
37+
38+
class DHT {
39+
public:
40+
DHT(uint8_t pin, uint8_t type, uint8_t count=6);
41+
void begin(void);
42+
float readTemperature(bool S=false);
43+
float convertCtoF(float);
44+
float convertFtoC(float);
45+
float computeHeatIndex(float tempFahrenheit, float percentHumidity);
46+
float readHumidity(void);
47+
boolean read(void);
48+
49+
private:
50+
uint8_t data[6];
51+
uint8_t _pin, _type;
52+
uint32_t _lastreadtime;
53+
bool _firstreading;
54+
bool _lastresult;
55+
56+
uint32_t expectPulse(bool level);
57+
58+
};
59+
60+
#endif

0 commit comments

Comments
 (0)