|
| 1 | +/* |
| 2 | + DHT22.cpp - DHT22 sensor library |
| 3 | + Developed by Ben Adams - 2011 |
| 4 | +
|
| 5 | + This library is free software; you can redistribute it and/or |
| 6 | + modify it under the terms of the GNU Lesser General Public |
| 7 | + License as published by the Free Software Foundation; either |
| 8 | + version 2.1 of the License, or (at your option) any later version. |
| 9 | +
|
| 10 | + This library is distributed in the hope that it will be useful, |
| 11 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | + Lesser General Public License for more details. |
| 14 | +
|
| 15 | + You should have received a copy of the GNU Lesser General Public |
| 16 | + License along with this library; if not, write to the Free Software |
| 17 | + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 18 | +
|
| 19 | +
|
| 20 | +Humidity and Temperature Sensor DHT22 info found at |
| 21 | +http://www.sparkfun.com/products/10167 |
| 22 | +
|
| 23 | +Version 0.3: 17-Jan-2011 by Ben Adams |
| 24 | +This version reads data |
| 25 | +Needs check sum code added at the end of readData |
| 26 | +
|
| 27 | +Version 0.2: 16-Jan-2011 by Ben Adams |
| 28 | +Changed coding style to match other Arduino libraries. |
| 29 | +This version will not read data either! |
| 30 | +
|
| 31 | +Version 0.1: 10-Jan-2011 by Ben Adams nethoncho AT gmail.com |
| 32 | +First Version is a skeleton. This version will not read data! |
| 33 | +Code adapted from the following sources: |
| 34 | +The Arduino OneWire lib |
| 35 | +http://sheepdogguides.com/arduino/ar3ne1humDHT11.htm |
| 36 | +
|
| 37 | +*/ |
| 38 | + |
| 39 | +#include "DHT22.h" |
| 40 | +#include "pins_arduino.h" |
| 41 | + |
| 42 | +extern "C" { |
| 43 | +#include "WConstants.h" |
| 44 | +#include <avr/io.h> |
| 45 | +#include <avr/interrupt.h> |
| 46 | +#include <avr/pgmspace.h> |
| 47 | +} |
| 48 | + |
| 49 | +#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) |
| 50 | +#define DIRECT_MODE_INPUT(base, mask) ((*(base+1)) &= ~(mask)) |
| 51 | +#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) |= (mask)) |
| 52 | +#define DIRECT_WRITE_LOW(base, mask) ((*(base+2)) &= ~(mask)) |
| 53 | +//#define DIRECT_WRITE_HIGH(base, mask) ((*(base+2)) |= (mask)) |
| 54 | + |
| 55 | +// This should be 40, but the sensor is adding an extra bit at the start |
| 56 | +#define DHT22_DATA_BIT_COUNT 41 |
| 57 | + |
| 58 | +DHT22::DHT22(uint8_t pin) |
| 59 | +{ |
| 60 | + _bitmask = digitalPinToBitMask(pin); |
| 61 | + _baseReg = portInputRegister(digitalPinToPort(pin)); |
| 62 | + _lastReadTime = millis(); |
| 63 | + _lastHumidity = DHT22_ERROR_VALUE; |
| 64 | + _lastTemperature = DHT22_ERROR_VALUE; |
| 65 | +} |
| 66 | + |
| 67 | +// |
| 68 | +// Read the 40 bit data stream from the DHT 22 |
| 69 | +// Store the results in private member data to be read by public member functions |
| 70 | +// |
| 71 | +DHT22_ERROR_t DHT22::readData() |
| 72 | +{ |
| 73 | + uint8_t bitmask = _bitmask; |
| 74 | + volatile uint8_t *reg asm("r30") = _baseReg; |
| 75 | + uint8_t retryCount; |
| 76 | + uint8_t bitTimes[DHT22_DATA_BIT_COUNT]; |
| 77 | + int currentHumidity; |
| 78 | + int currentTemperature; |
| 79 | + uint8_t checkSum; |
| 80 | + unsigned long currentTime; |
| 81 | + int i; |
| 82 | + |
| 83 | + currentHumidity = 0; |
| 84 | + currentTemperature = 0; |
| 85 | + checkSum = 0; |
| 86 | + currentTime = millis(); |
| 87 | + for(i = 0; i < DHT22_DATA_BIT_COUNT; i++) |
| 88 | + { |
| 89 | + bitTimes[i] = 0; |
| 90 | + } |
| 91 | + |
| 92 | + if(currentTime - _lastReadTime < 2000) |
| 93 | + { |
| 94 | + // Caller needs to wait 2 seconds between each call to readData |
| 95 | + return DHT_ERROR_TOOQUICK; |
| 96 | + } |
| 97 | + _lastReadTime = currentTime; |
| 98 | + |
| 99 | + // Pin needs to start HIGH, wait until it is HIGH with a timeout |
| 100 | + cli(); |
| 101 | + DIRECT_MODE_INPUT(reg, bitmask); |
| 102 | + sei(); |
| 103 | + retryCount = 0; |
| 104 | + do |
| 105 | + { |
| 106 | + if (retryCount > 125) |
| 107 | + { |
| 108 | + return DHT_BUS_HUNG; |
| 109 | + } |
| 110 | + retryCount++; |
| 111 | + delayMicroseconds(2); |
| 112 | + } while(!DIRECT_READ(reg, bitmask)); |
| 113 | + // Send the activate pulse |
| 114 | + cli(); |
| 115 | + DIRECT_WRITE_LOW(reg, bitmask); |
| 116 | + DIRECT_MODE_OUTPUT(reg, bitmask); // Output Low |
| 117 | + sei(); |
| 118 | + delayMicroseconds(1100); // 1.1 ms |
| 119 | + cli(); |
| 120 | + DIRECT_MODE_INPUT(reg, bitmask); // Switch back to input so pin can float |
| 121 | + sei(); |
| 122 | + // Find the start of the ACK Pulse |
| 123 | + retryCount = 0; |
| 124 | + do |
| 125 | + { |
| 126 | + if (retryCount > 25) //(Spec is 20 to 40 us, 25*2 == 50 us) |
| 127 | + { |
| 128 | + return DHT_ERROR_NOT_PRESENT; |
| 129 | + } |
| 130 | + retryCount++; |
| 131 | + delayMicroseconds(2); |
| 132 | + } while(!DIRECT_READ(reg, bitmask)); |
| 133 | + // Find the end of the ACK Pulse |
| 134 | + retryCount = 0; |
| 135 | + do |
| 136 | + { |
| 137 | + if (retryCount > 50) //(Spec is 80 us, 50*2 == 100 us) |
| 138 | + { |
| 139 | + return DHT_ERROR_ACK_TOO_LONG; |
| 140 | + } |
| 141 | + retryCount++; |
| 142 | + delayMicroseconds(2); |
| 143 | + } while(DIRECT_READ(reg, bitmask)); |
| 144 | + // Read the 40 bit data stream |
| 145 | + for(i = 0; i < DHT22_DATA_BIT_COUNT; i++) |
| 146 | + { |
| 147 | + // Find the start of the sync pulse |
| 148 | + retryCount = 0; |
| 149 | + do |
| 150 | + { |
| 151 | + if (retryCount > 35) //(Spec is 50 us, 35*2 == 70 us) |
| 152 | + { |
| 153 | + return DHT_ERROR_SYNC_TIMEOUT; |
| 154 | + } |
| 155 | + retryCount++; |
| 156 | + delayMicroseconds(2); |
| 157 | + } while(!DIRECT_READ(reg, bitmask)); |
| 158 | + // Measure the width of the data pulse |
| 159 | + retryCount = 0; |
| 160 | + do |
| 161 | + { |
| 162 | + if (retryCount > 50) //(Spec is 80 us, 50*2 == 100 us) |
| 163 | + { |
| 164 | + return DHT_ERROR_DATA_TIMEOUT; |
| 165 | + } |
| 166 | + retryCount++; |
| 167 | + delayMicroseconds(2); |
| 168 | + } while(DIRECT_READ(reg, bitmask)); |
| 169 | + bitTimes[i] = retryCount; |
| 170 | + } |
| 171 | + // Now bitTimes have the number of retries (us *2) |
| 172 | + // that were needed to find the end of each data bit |
| 173 | + // Spec: 0 is 26 to 28 us |
| 174 | + // Spec: 1 is 70 us |
| 175 | + // bitTimes[x] <= 11 is a 0 |
| 176 | + // bitTimes[x] > 11 is a 1 |
| 177 | + // Note: the bits are offset by one from the data sheet, not sure why |
| 178 | + for(i = 0; i < 16; i++) |
| 179 | + { |
| 180 | + if(bitTimes[i + 1] > 11) |
| 181 | + { |
| 182 | + currentHumidity |= (1 << (15 - i)); |
| 183 | + } |
| 184 | + } |
| 185 | + for(i = 0; i < 16; i++) |
| 186 | + { |
| 187 | + if(bitTimes[i + 17] > 11) |
| 188 | + { |
| 189 | + currentTemperature |= (1 << (15 - i)); |
| 190 | + } |
| 191 | + } |
| 192 | + for(i = 0; i < 8; i++) |
| 193 | + { |
| 194 | + if(bitTimes[i + 33] > 11) |
| 195 | + { |
| 196 | + checkSum |= (1 << (7 - i)); |
| 197 | + } |
| 198 | + } |
| 199 | + |
| 200 | + _lastHumidity = (float(currentHumidity & 0x7FFF) / 10.0); |
| 201 | + if(currentTemperature & 0x8000) |
| 202 | + { |
| 203 | + // Below zero, non standard way of encoding negative numbers! |
| 204 | + currentTemperature &= 0x7FFF; |
| 205 | + _lastTemperature = (float(currentTemperature) / 10.0) * -1.0; |
| 206 | + } |
| 207 | + else |
| 208 | + { |
| 209 | + _lastTemperature = float(currentTemperature) / 10.0; |
| 210 | + } |
| 211 | + |
| 212 | + // TODO: Test the checksum and return DHT_ERROR_CHECKSUM if bad |
| 213 | + |
| 214 | + return DHT_ERROR_NONE; |
| 215 | +} |
| 216 | + |
| 217 | +float DHT22::getHumidity() |
| 218 | +{ |
| 219 | + return _lastHumidity; |
| 220 | +} |
| 221 | + |
| 222 | +float DHT22::getTemperatureC() |
| 223 | +{ |
| 224 | + return _lastTemperature; |
| 225 | +} |
| 226 | + |
| 227 | +// |
| 228 | +// This is used when the millis clock rolls over to zero |
| 229 | +// |
| 230 | +void DHT22::clockReset() |
| 231 | +{ |
| 232 | + _lastReadTime = millis(); |
| 233 | +} |
0 commit comments