Skip to content

Commit 10a955a

Browse files
committed
update dht example
1 parent 7b64024 commit 10a955a

File tree

4 files changed

+457
-0
lines changed

4 files changed

+457
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#define BLINKER_PRINT Serial
2+
#define BLINKER_BLE
3+
4+
#include <Blinker.h>
5+
6+
#include <modules/dht/DHT.h>
7+
8+
#define DHTPIN 4
9+
10+
//#define DHTTYPE DHT11 // DHT 11
11+
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
12+
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
13+
14+
DHT dht(DHTPIN, DHTTYPE);
15+
16+
void setup()
17+
{
18+
Serial.begin(115200);
19+
20+
pinMode(LED_BUILTIN, OUTPUT);
21+
digitalWrite(LED_BUILTIN, LOW);
22+
23+
Blinker.begin();
24+
dht.begin();
25+
}
26+
27+
void loop()
28+
{
29+
Blinker.run();
30+
31+
if (Blinker.available()) {
32+
BLINKER_LOG2("Blinker.readString(): ", Blinker.readString());
33+
34+
Blinker.vibrate();
35+
36+
uint32_t BlinkerTime = millis();
37+
Blinker.print(BlinkerTime);
38+
Blinker.print("millis", BlinkerTime);
39+
}
40+
41+
float h = dht.readHumidity();
42+
float t = dht.readTemperature();
43+
44+
if (isnan(h) || isnan(t)) {
45+
BLINKER_LOG1("Failed to read from DHT sensor!");
46+
return;
47+
}
48+
49+
float hic = dht.computeHeatIndex(t, h, false);
50+
51+
BLINKER_LOG3("Humidity: ", h, " %");
52+
BLINKER_LOG3("Temperature: ", t, " *C");
53+
BLINKER_LOG3("Heat index: ", hic, " *C");
54+
55+
Blinker.print("humi", h, " %");
56+
Blinker.print("temp", t, " *C");
57+
Blinker.print("hic", hic, " *C");
58+
59+
Blinker.delay(2000);
60+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#define BLINKER_PRINT Serial
2+
#define BLINKER_WIFI
3+
4+
#include <Blinker.h>
5+
6+
char ssid[] = "<Your WiFi network SSID or name>";
7+
char pswd[] = "<Your WiFi network WPA password or WEP key>";
8+
9+
#include <modules/dht/DHT.h>
10+
11+
#define DHTPIN 4
12+
13+
//#define DHTTYPE DHT11 // DHT 11
14+
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
15+
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
16+
17+
DHT dht(DHTPIN, DHTTYPE);
18+
19+
void setup()
20+
{
21+
Serial.begin(115200);
22+
23+
pinMode(LED_BUILTIN, OUTPUT);
24+
digitalWrite(LED_BUILTIN, LOW);
25+
26+
Blinker.begin(ssid, pswd);
27+
dht.begin();
28+
}
29+
30+
void loop()
31+
{
32+
Blinker.run();
33+
34+
if (Blinker.available()) {
35+
BLINKER_LOG2("Blinker.readString(): ", Blinker.readString());
36+
37+
Blinker.vibrate();
38+
39+
uint32_t BlinkerTime = millis();
40+
Blinker.print(BlinkerTime);
41+
Blinker.print("millis", BlinkerTime);
42+
}
43+
44+
float h = dht.readHumidity();
45+
float t = dht.readTemperature();
46+
47+
if (isnan(h) || isnan(t)) {
48+
BLINKER_LOG1("Failed to read from DHT sensor!");
49+
return;
50+
}
51+
52+
float hic = dht.computeHeatIndex(t, h, false);
53+
54+
BLINKER_LOG3("Humidity: ", h, " %");
55+
BLINKER_LOG3("Temperature: ", t, " *C");
56+
BLINKER_LOG3("Heat index: ", hic, " *C");
57+
58+
Blinker.print("humi", h, " %");
59+
Blinker.print("temp", t, " *C");
60+
Blinker.print("hic", hic, " *C");
61+
62+
Blinker.delay(2000);
63+
}

src/modules/dht/DHT.cpp

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
/* DHT library
2+
3+
MIT license
4+
written by Adafruit Industries
5+
*/
6+
7+
#include "DHT.h"
8+
9+
#define MIN_INTERVAL 2000
10+
11+
DHT::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+
24+
void 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
35+
float 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+
64+
float DHT::convertCtoF(float c) {
65+
return c * 1.8 + 32;
66+
}
67+
68+
float DHT::convertFtoC(float f) {
69+
return (f - 32) * 0.55555;
70+
}
71+
72+
float 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
92+
float 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+
123+
boolean 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
237+
uint32_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+
}

0 commit comments

Comments
 (0)