Lab_interaccio/2013/Sck_SD_beta/DHT22.cpp

238 lines
6.2 KiB
C++
Raw Permalink Normal View History

2025-02-25 21:29:42 +01:00
/*
DHT22.cpp - DHT22 sensor library
Developed by Ben Adams - 2011
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Humidity and Temperature Sensor DHT22 info found at
http://www.sparkfun.com/products/10167
Version 0.5: 15 Jan 2012 by Craig Ringer
- Updated to build against Arduino 1.0
- Made accessors inline in the header so they can be optimized away
Version 0.4: 24-Jan-2011 by Ben Adams
Added return code constants to keywords.txt
Returns DHT_ERROR_CHECKSUM on check sum mismatch
Version 0.3: 17-Jan-2011 by Ben Adams
This version reads data
Needs check sum code added at the end of readData
Version 0.2: 16-Jan-2011 by Ben Adams
Changed coding style to match other Arduino libraries.
This version will not read data either!
Version 0.1: 10-Jan-2011 by Ben Adams nethoncho AT gmail.com
First Version is a skeleton. This version will not read data!
Code adapted from the following sources:
The Arduino OneWire lib
http://sheepdogguides.com/arduino/ar3ne1humDHT11.htm
*/
#include "DHT22.h"
#include <Arduino.h>
#include <pins_arduino.h>
extern "C" {
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
}
#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
#define DIRECT_MODE_INPUT(base, mask) ((*(base+1)) &= ~(mask))
#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) |= (mask))
#define DIRECT_WRITE_LOW(base, mask) ((*(base+2)) &= ~(mask))
//#define DIRECT_WRITE_HIGH(base, mask) ((*(base+2)) |= (mask))
// This should be 40, but the sensor is adding an extra bit at the start
#define DHT22_DATA_BIT_COUNT 41
DHT22::DHT22(uint8_t pin)
{
_bitmask = digitalPinToBitMask(pin);
_baseReg = portInputRegister(digitalPinToPort(pin));
_lastReadTime = millis();
_lastHumidity = DHT22_ERROR_VALUE;
_lastTemperature = DHT22_ERROR_VALUE;
}
//
// Read the 40 bit data stream from the DHT 22
// Store the results in private member data to be read by public member functions
//
DHT22_ERROR_t DHT22::readData()
{
uint8_t bitmask = _bitmask;
volatile uint8_t *reg asm("r30") = _baseReg;
uint8_t retryCount;
uint8_t bitTimes[DHT22_DATA_BIT_COUNT];
int currentHumidity;
int currentTemperature;
uint8_t checkSum, csPart1, csPart2, csPart3, csPart4;
unsigned long currentTime;
int i;
currentHumidity = 0;
currentTemperature = 0;
checkSum = 0;
currentTime = millis();
for(i = 0; i < DHT22_DATA_BIT_COUNT; i++)
{
bitTimes[i] = 0;
}
if(currentTime - _lastReadTime < 2000)
{
// Caller needs to wait 2 seconds between each call to readData
return DHT_ERROR_TOOQUICK;
}
_lastReadTime = currentTime;
// Pin needs to start HIGH, wait until it is HIGH with a timeout
cli();
DIRECT_MODE_INPUT(reg, bitmask);
sei();
retryCount = 0;
do
{
if (retryCount > 125)
{
return DHT_BUS_HUNG;
}
retryCount++;
delayMicroseconds(2);
} while(!DIRECT_READ(reg, bitmask));
// Send the activate pulse
cli();
DIRECT_WRITE_LOW(reg, bitmask);
DIRECT_MODE_OUTPUT(reg, bitmask); // Output Low
sei();
delayMicroseconds(1100); // 1.1 ms
cli();
DIRECT_MODE_INPUT(reg, bitmask); // Switch back to input so pin can float
sei();
// Find the start of the ACK Pulse
retryCount = 0;
do
{
if (retryCount > 25) //(Spec is 20 to 40 us, 25*2 == 50 us)
{
return DHT_ERROR_NOT_PRESENT;
}
retryCount++;
delayMicroseconds(2);
} while(!DIRECT_READ(reg, bitmask));
// Find the end of the ACK Pulse
retryCount = 0;
do
{
if (retryCount > 50) //(Spec is 80 us, 50*2 == 100 us)
{
return DHT_ERROR_ACK_TOO_LONG;
}
retryCount++;
delayMicroseconds(2);
} while(DIRECT_READ(reg, bitmask));
// Read the 40 bit data stream
for(i = 0; i < DHT22_DATA_BIT_COUNT; i++)
{
// Find the start of the sync pulse
retryCount = 0;
do
{
if (retryCount > 35) //(Spec is 50 us, 35*2 == 70 us)
{
return DHT_ERROR_SYNC_TIMEOUT;
}
retryCount++;
delayMicroseconds(2);
} while(!DIRECT_READ(reg, bitmask));
// Measure the width of the data pulse
retryCount = 0;
do
{
if (retryCount > 50) //(Spec is 80 us, 50*2 == 100 us)
{
return DHT_ERROR_DATA_TIMEOUT;
}
retryCount++;
delayMicroseconds(2);
} while(DIRECT_READ(reg, bitmask));
bitTimes[i] = retryCount;
}
// Now bitTimes have the number of retries (us *2)
// that were needed to find the end of each data bit
// Spec: 0 is 26 to 28 us
// Spec: 1 is 70 us
// bitTimes[x] <= 11 is a 0
// bitTimes[x] > 11 is a 1
// Note: the bits are offset by one from the data sheet, not sure why
for(i = 0; i < 16; i++)
{
if(bitTimes[i + 1] > 11)
{
currentHumidity |= (1 << (15 - i));
}
}
for(i = 0; i < 16; i++)
{
if(bitTimes[i + 17] > 11)
{
currentTemperature |= (1 << (15 - i));
}
}
for(i = 0; i < 8; i++)
{
if(bitTimes[i + 33] > 11)
{
checkSum |= (1 << (7 - i));
}
}
_lastHumidity = currentHumidity & 0x7FFF;
if(currentTemperature & 0x8000)
{
// Below zero, non standard way of encoding negative numbers!
// Convert to native negative format.
_lastTemperature = -currentTemperature & 0x7FFF;
}
else
{
_lastTemperature = currentTemperature;
}
csPart1 = currentHumidity >> 8;
csPart2 = currentHumidity & 0xFF;
csPart3 = currentTemperature >> 8;
csPart4 = currentTemperature & 0xFF;
if(checkSum == ((csPart1 + csPart2 + csPart3 + csPart4) & 0xFF))
{
return DHT_ERROR_NONE;
}
return DHT_ERROR_CHECKSUM;
}
//
// This is used when the millis clock rolls over to zero
//
void DHT22::clockReset()
{
_lastReadTime = millis();
}