Erriez DHT22 library for Arduino  1.2.1
AM2302/AM2303 DHT22 temperature and humidity sensor library for Arduino
ErriezDHT22.cpp
Go to the documentation of this file.
1 /*
2  * MIT License
3  *
4  * Copyright (c) 2018-2020 Erriez
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 
33 #include "ErriezDHT22.h"
34 
39 DHT22::DHT22(uint8_t pin) :
40  _temperatureSampleIndex(0), _numTemperatureSamples(0),
41  _humiditySampleIndex(0), _numHumiditySamples(0)
42 {
43  // Store data pin
44  _pin = pin;
45 
46  // For AVR targets only:
47  // Calculate bit and port register for faster pin reads and writes instead
48  // of using the slow digitalRead() function
49 #ifdef __AVR
50  _bit = digitalPinToBitMask(pin);
51  _port = digitalPinToPort(pin);
52 #endif
53 
54  // 1 ms timeout for reading data from DHT22 sensor
55  _maxCycles = microsecondsToClockCycles(1000);
56 }
57 
75 void DHT22::begin(uint8_t numSamples)
76 {
77  // Number of samples for average temperature and humidity calculation
78  _numSamples = numSamples;
79  if (_numSamples) {
80  _temperatureSamples = (int16_t *)malloc(numSamples * sizeof(int16_t));
81  _humiditySamples = (int16_t *)malloc(numSamples * sizeof(int16_t));
82  }
83 
84  // Try to enable internal pin pull-up resistor when available
85  pinMode(_pin, INPUT_PULLUP);
86 
87  // Initialize last measurement timestamp with negative interval to allow a new measurement
88  _lastMeasurementTimestamp = (uint32_t)-DHT22_MIN_READ_INTERVAL;
89 }
90 
102 {
103  if ((millis() - _lastMeasurementTimestamp) < 2000) {
104  // Interval between sensor reads too short
105  return false;
106  }
107 
108  // Read sensor data
109  return readSensorData();
110 }
111 
122 {
123  int16_t temperature = ~0;
124 
125  // Read data from sensor
126  if (_statusLastMeasurement != true) {
127  return temperature;
128  }
129 
130  // Calculate signed temperature
131  temperature = ((_data[2] & 0x7F) << 8) | _data[3];
132  if (_data[2] & 0x80) {
133  temperature *= -1;
134  }
135 
136  // Calculate temperature average
137  if ((_temperatureSamples != NULL) && (temperature != ~0)) {
138  // Store temperature sample
139  _temperatureSamples[_temperatureSampleIndex++ % _numSamples] = temperature;
140 
141  // Increment number of samples
142  if (_numTemperatureSamples < _numSamples) {
143  _numTemperatureSamples++;
144  }
145 
146  // Calculate average temperature
147  temperature = 0;
148  for (uint8_t i = 0; i < _numTemperatureSamples; i++) {
149  temperature += _temperatureSamples[i];
150  }
151  temperature /= _numTemperatureSamples;
152  }
153 
154  return temperature;
155 }
156 
165 {
166  int16_t humidity = ~0;
167 
168  // Read data from sensor
169  if (_statusLastMeasurement != true) {
170  return humidity;
171  }
172 
173  // Calculate humidity
174  humidity = (_data[0] << 8) | _data[1];
175 
176  // Calculate temperature average
177  if ((_humiditySamples != NULL) && (humidity != ~0)) {
178  // Store humidity sample
179  _humiditySamples[_humiditySampleIndex++ % _numSamples] = humidity;
180 
181  // Increment number of samples
182  if (_numHumiditySamples < _numSamples) {
183  _numHumiditySamples++;
184  }
185 
186  // Calculate average humidity
187  humidity = 0;
188  for (uint8_t i = 0; i < _numHumiditySamples; i++) {
189  humidity += _humiditySamples[i];
190  }
191  humidity /= _numHumiditySamples;
192  }
193 
194  return humidity;
195 }
196 
213 {
214  // Store last conversion timestamp
215  _lastMeasurementTimestamp = millis();
216 
217  // Read data from sensor until valid data has been read or maximum number of retries
218  // Mark current measurement as successful
219  _statusLastMeasurement = true;
220 
221  // Generate sensor start pulse
222  if (generateStart() != true) {
223  DEBUG_PRINTLN(F("DHT22: Start error"));
224  // Mark measurement as invalid
225  _statusLastMeasurement = false;
226  }
227 
228  // Read 5 Bytes data from sensor
229  if (_statusLastMeasurement) {
230  if (readBytes() != true) {
231  DEBUG_PRINTLN(F("DHT22: Read error"));
232  // Mark measurement as invalid
233  _statusLastMeasurement = false;
234  }
235  }
236 
237  // Check data parity
238  if (_statusLastMeasurement) {
239  if (((_data[0] + _data[1] + _data[2] + _data[3]) & 0xFF) != _data[4]) {
240  DEBUG_PRINTLN(F("DHT22: Parity error"));
241  // Mark measurement as invalid
242  _statusLastMeasurement = false;
243  }
244  }
245 
246  return _statusLastMeasurement;
247 }
248 
249 //--------------------------------------------------------------------------------------------------
250 // Private functions
251 //--------------------------------------------------------------------------------------------------
259 bool DHT22::generateStart()
260 {
261  // Data pin high (pull-up)
262  digitalWrite(_pin, HIGH);
263  delay(10);
264 
265  // Change data pin to output, low, followed by high
266  pinMode(_pin, OUTPUT);
267  digitalWrite(_pin, LOW);
268  delay(20);
269 
270  // Data pin to input (pull-up)
271  pinMode(_pin, INPUT_PULLUP);
272  delayMicroseconds(30);
273 
274  // Check data pin timing low
275  if (measurePulseWidth(LOW) == 0) {
276  return false;
277  }
278 
279  // Check data pin timing high
280  if (measurePulseWidth(HIGH) == 0) {
281  return false;
282  }
283 
284  // Sensor start successfully generated
285  return true;
286 }
287 
298 bool DHT22::readBytes()
299 {
300  // Disable interrupts during data transfer
301  noInterrupts();
302 
303  // Measure and store pulse width of each bit
304  for (int i = 0; i < (DHT22_NUM_DATA_BITS * 2); i += 2) {
305  cycles[i] = measurePulseWidth(LOW);
306  cycles[i + 1] = measurePulseWidth(HIGH);
307  }
308 
309  // Enable interrupts
310  interrupts();
311 
312  // Clear data buffer
313  memset(_data, 0, sizeof(_data));
314 
315  // Convert pulse width to data bit
316  for (int i = 0; i < DHT22_NUM_DATA_BITS; ++i) {
317  uint32_t lowCycles = cycles[2 * i];
318  uint32_t highCycles = cycles[(2 * i) + 1];
319 
320  // Check valid bit timing
321  if ((lowCycles == 0) || (highCycles == 0)) {
322  return false;
323  }
324 
325  // Calculate byte index in data array
326  int byteIndex = i / 8;
327 
328  // Store bit
329  _data[byteIndex] <<= 1;
330  if (highCycles > lowCycles) {
331  _data[byteIndex] |= 1;
332  }
333  }
334 
335  return true;
336 }
337 
346 uint32_t DHT22::measurePulseWidth(uint8_t level)
347 {
348  uint32_t count = 0;
349 
350 #ifdef __AVR
351  while ((*portInputRegister(_port) & _bit) == (level ? _bit : 0)) {
352  if (count++ >= _maxCycles) {
353  // Timeout
354  return 0;
355  }
356  }
357 
358 #else
359  while (digitalRead(_pin) == level) {
360  if (count++ >= _maxCycles) {
361  // Timeout
362  return 0;
363  }
364  }
365 #endif
366 
367  return count;
368 }
int16_t readHumidity()
Read humidity from sensor.
DHT22 (AM2302/AM2303) Humidity and Temperature sensor library for Arduino.
void begin(uint8_t numSamples=0)
Initialize sensor.
Definition: ErriezDHT22.cpp:75
#define DHT22_NUM_DATA_BITS
Definition: ErriezDHT22.h:50
#define DEBUG_PRINTLN(...)
Debug print configuration.
Definition: ErriezDHT22.h:56
#define DHT22_MIN_READ_INTERVAL
Enable debug prints to Serial.
Definition: ErriezDHT22.h:42
int16_t readTemperature()
Read temperature from sensor.
bool available()
Check if new temperature or humidity read is allowed.
DHT22(uint8_t pin)
Constructor DHT22 sensor.
Definition: ErriezDHT22.cpp:39
bool readSensorData()
Read data from sensor.