mirror of
https://github.com/nodemcu/nodemcu-firmware.git
synced 2025-01-16 20:52:57 +08:00
bf15299cea
* DHT module: fix the handling of negative temps. The macro handling the conversion from the 2 bytes buffer to a double was handling negative values by checking the sign bit and taking the negative value of the number minus the sign bit. Unfortunately this does not work as the negative values are represented in 1's complement, so for instance -1 was becoming -32767 * +1 = b0000_0000_0000_ 0001 * -1 = 1111_1111_1111_1111 This replace the spacial code with a signed 16 bits value. * Refactoring: removes some code duplication. * Fixed the conversion of the 8/16 bits values Co-authored-by: Marco Dondero <marco@dondero.eu>
341 lines
8.2 KiB
C
341 lines
8.2 KiB
C
//
|
|
// FILE: dht.cpp
|
|
// AUTHOR: Rob Tillaart
|
|
// VERSION: 0.1.14
|
|
// PURPOSE: DHT Temperature & Humidity Sensor library for Arduino
|
|
// URL: http://arduino.cc/playground/Main/DHTLib
|
|
//
|
|
// HISTORY:
|
|
// 0.1.14 replace digital read with faster (~3x) code => more robust low MHz machines.
|
|
// 0.1.13 fix negative dht_temperature
|
|
// 0.1.12 support DHT33 and DHT44 initial version
|
|
// 0.1.11 renamed DHTLIB_TIMEOUT
|
|
// 0.1.10 optimized faster WAKEUP + TIMEOUT
|
|
// 0.1.09 optimize size: timeout check + use of mask
|
|
// 0.1.08 added formula for timeout based upon clockspeed
|
|
// 0.1.07 added support for DHT21
|
|
// 0.1.06 minimize footprint (2012-12-27)
|
|
// 0.1.05 fixed negative dht_temperature bug (thanks to Roseman)
|
|
// 0.1.04 improved readability of code using DHTLIB_OK in code
|
|
// 0.1.03 added error values for temp and dht_humidity when read failed
|
|
// 0.1.02 added error codes
|
|
// 0.1.01 added support for Arduino 1.0, fixed typos (31/12/2011)
|
|
// 0.1.00 by Rob Tillaart (01/04/2011)
|
|
//
|
|
// inspired by DHT11 library
|
|
//
|
|
// Released to the public domain
|
|
//
|
|
|
|
#include "user_interface.h"
|
|
#include "platform.h"
|
|
#include <stdio.h>
|
|
#include "dht.h"
|
|
|
|
#ifndef LOW
|
|
#define LOW 0
|
|
#endif /* ifndef LOW */
|
|
|
|
#ifndef HIGH
|
|
#define HIGH 1
|
|
#endif /* ifndef HIGH */
|
|
|
|
static double dht_humidity;
|
|
static double dht_temperature;
|
|
|
|
static uint8_t dht_bytes[5]; // buffer to receive data
|
|
|
|
typedef enum {
|
|
Humidity = 0,
|
|
Temperature,
|
|
Humidity8,
|
|
Temperature8
|
|
} dht_Signal;
|
|
|
|
static int dht_readSensor(uint8_t pin, uint8_t wakeupDelay);
|
|
static double getValue(dht_Signal s);
|
|
static bool verifyChecksum();
|
|
|
|
/////////////////////////////////////////////////////
|
|
//
|
|
// PUBLIC
|
|
//
|
|
|
|
// return values:
|
|
// Humidity
|
|
double dht_getHumidity(void)
|
|
{
|
|
return dht_humidity;
|
|
}
|
|
|
|
// return values:
|
|
// Temperature
|
|
double dht_getTemperature(void)
|
|
{
|
|
return dht_temperature;
|
|
}
|
|
|
|
// return values:
|
|
// DHTLIB_OK
|
|
// DHTLIB_ERROR_CHECKSUM
|
|
// DHTLIB_ERROR_TIMEOUT
|
|
int dht_read_universal(uint8_t pin)
|
|
{
|
|
// READ VALUES
|
|
int rv = dht_readSensor(pin, DHTLIB_DHT_UNI_WAKEUP);
|
|
if (rv != DHTLIB_OK)
|
|
{
|
|
dht_humidity = DHTLIB_INVALID_VALUE; // invalid value, or is NaN prefered?
|
|
dht_temperature = DHTLIB_INVALID_VALUE; // invalid value
|
|
return rv; // propagate error value
|
|
}
|
|
|
|
#if defined(DHT_DEBUG_BYTES)
|
|
int i;
|
|
for (i = 0; i < 5; i++)
|
|
{
|
|
DHT_DEBUG("%02X\n", dht_bytes[i]);
|
|
}
|
|
#endif // defined(DHT_DEBUG_BYTES)
|
|
|
|
// Assume it is DHT11
|
|
// If it is DHT11, both temp and humidity's decimal
|
|
if ((dht_bytes[1] == 0) && (dht_bytes[3] == 0))
|
|
{
|
|
// It may DHT11
|
|
// CONVERT AND STORE
|
|
DHT_DEBUG("DHT11 method\n");
|
|
dht_humidity = getValue(Humidity8);
|
|
dht_temperature = getValue(Temperature8);
|
|
|
|
// TEST CHECKSUM
|
|
if (!verifyChecksum())
|
|
{
|
|
// It may not DHT11
|
|
dht_humidity = DHTLIB_INVALID_VALUE; // invalid value, or is NaN prefered?
|
|
dht_temperature = DHTLIB_INVALID_VALUE; // invalid value
|
|
// Do nothing
|
|
}
|
|
else
|
|
{
|
|
return DHTLIB_OK;
|
|
}
|
|
}
|
|
|
|
// Assume it is not DHT11
|
|
// CONVERT AND STORE
|
|
DHT_DEBUG("DHTxx method\n");
|
|
dht_humidity = getValue(Humidity);
|
|
dht_temperature = getValue(Temperature);
|
|
|
|
// TEST CHECKSUM
|
|
if (!verifyChecksum())
|
|
{
|
|
return DHTLIB_ERROR_CHECKSUM;
|
|
}
|
|
return DHTLIB_OK;
|
|
}
|
|
|
|
// return values:
|
|
// DHTLIB_OK
|
|
// DHTLIB_ERROR_CHECKSUM
|
|
// DHTLIB_ERROR_TIMEOUT
|
|
int dht_read11(uint8_t pin)
|
|
{
|
|
// READ VALUES
|
|
int rv = dht_readSensor(pin, DHTLIB_DHT11_WAKEUP);
|
|
if (rv != DHTLIB_OK)
|
|
{
|
|
dht_humidity = DHTLIB_INVALID_VALUE; // invalid value, or is NaN prefered?
|
|
dht_temperature = DHTLIB_INVALID_VALUE; // invalid value
|
|
return rv;
|
|
}
|
|
|
|
// CONVERT AND STORE
|
|
dht_humidity = getValue(Humidity8);
|
|
dht_temperature = getValue(Temperature8);
|
|
|
|
// TEST CHECKSUM
|
|
if (!verifyChecksum()) return DHTLIB_ERROR_CHECKSUM;
|
|
|
|
return DHTLIB_OK;
|
|
}
|
|
|
|
|
|
// return values:
|
|
// DHTLIB_OK
|
|
// DHTLIB_ERROR_CHECKSUM
|
|
// DHTLIB_ERROR_TIMEOUT
|
|
int dht_read(uint8_t pin)
|
|
{
|
|
// READ VALUES
|
|
int rv = dht_readSensor(pin, DHTLIB_DHT_WAKEUP);
|
|
if (rv != DHTLIB_OK)
|
|
{
|
|
dht_humidity = DHTLIB_INVALID_VALUE; // invalid value, or is NaN prefered?
|
|
dht_temperature = DHTLIB_INVALID_VALUE; // invalid value
|
|
return rv; // propagate error value
|
|
}
|
|
|
|
// CONVERT AND STORE
|
|
dht_humidity = getValue(Humidity);
|
|
dht_temperature = getValue(Temperature);
|
|
|
|
// TEST CHECKSUM
|
|
if (!verifyChecksum())
|
|
{
|
|
return DHTLIB_ERROR_CHECKSUM;
|
|
}
|
|
return DHTLIB_OK;
|
|
}
|
|
|
|
// return values:
|
|
// DHTLIB_OK
|
|
// DHTLIB_ERROR_CHECKSUM
|
|
// DHTLIB_ERROR_TIMEOUT
|
|
int dht_read21(uint8_t pin) __attribute__((alias("dht_read")));
|
|
|
|
// return values:
|
|
// DHTLIB_OK
|
|
// DHTLIB_ERROR_CHECKSUM
|
|
// DHTLIB_ERROR_TIMEOUT
|
|
int dht_read22(uint8_t pin) __attribute__((alias("dht_read")));
|
|
|
|
// return values:
|
|
// DHTLIB_OK
|
|
// DHTLIB_ERROR_CHECKSUM
|
|
// DHTLIB_ERROR_TIMEOUT
|
|
int dht_read33(uint8_t pin) __attribute__((alias("dht_read")));
|
|
|
|
// return values:
|
|
// DHTLIB_OK
|
|
// DHTLIB_ERROR_CHECKSUM
|
|
// DHTLIB_ERROR_TIMEOUT
|
|
int dht_read44(uint8_t pin) __attribute__((alias("dht_read")));
|
|
|
|
/////////////////////////////////////////////////////
|
|
//
|
|
// PRIVATE
|
|
//
|
|
|
|
// return values:
|
|
// DHTLIB_OK
|
|
// DHTLIB_ERROR_TIMEOUT
|
|
int dht_readSensor(uint8_t pin, uint8_t wakeupDelay)
|
|
{
|
|
// INIT BUFFERVAR TO RECEIVE DATA
|
|
uint8_t mask = 128;
|
|
uint8_t idx = 0;
|
|
uint8_t i = 0;
|
|
|
|
// replace digitalRead() with Direct Port Reads.
|
|
// reduces footprint ~100 bytes => portability issue?
|
|
// direct port read is about 3x faster
|
|
// uint8_t bit = digitalPinToBitMask(pin);
|
|
// uint8_t port = digitalPinToPort(pin);
|
|
// volatile uint8_t *PIR = portInputRegister(port);
|
|
|
|
// EMPTY BUFFER
|
|
memset(dht_bytes, sizeof(uint8_t)*5, 0);
|
|
|
|
// REQUEST SAMPLE
|
|
// pinMode(pin, OUTPUT);
|
|
platform_gpio_mode(pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_PULLUP);
|
|
DIRECT_MODE_OUTPUT(pin);
|
|
// digitalWrite(pin, LOW); // T-be
|
|
DIRECT_WRITE_LOW(pin);
|
|
// delay(wakeupDelay);
|
|
for (i = 0; i < wakeupDelay; i++) os_delay_us(1000);
|
|
// Disable interrupts
|
|
ets_intr_lock();
|
|
// digitalWrite(pin, HIGH); // T-go
|
|
DIRECT_WRITE_HIGH(pin);
|
|
os_delay_us(40);
|
|
// pinMode(pin, INPUT);
|
|
DIRECT_MODE_INPUT(pin);
|
|
|
|
// GET ACKNOWLEDGE or TIMEOUT
|
|
uint16_t loopCntLOW = DHTLIB_TIMEOUT;
|
|
while (DIRECT_READ(pin) == LOW ) // T-rel
|
|
{
|
|
os_delay_us(1);
|
|
if (--loopCntLOW == 0) return DHTLIB_ERROR_TIMEOUT;
|
|
}
|
|
|
|
uint16_t loopCntHIGH = DHTLIB_TIMEOUT;
|
|
while (DIRECT_READ(pin) != LOW ) // T-reh
|
|
{
|
|
os_delay_us(1);
|
|
if (--loopCntHIGH == 0) return DHTLIB_ERROR_TIMEOUT;
|
|
}
|
|
|
|
// READ THE OUTPUT - 40 BITS => 5 BYTES
|
|
for (i = 40; i != 0; i--)
|
|
{
|
|
loopCntLOW = DHTLIB_TIMEOUT;
|
|
while (DIRECT_READ(pin) == LOW )
|
|
{
|
|
os_delay_us(1);
|
|
if (--loopCntLOW == 0) return DHTLIB_ERROR_TIMEOUT;
|
|
}
|
|
|
|
uint32_t t = system_get_time();
|
|
|
|
loopCntHIGH = DHTLIB_TIMEOUT;
|
|
while (DIRECT_READ(pin) != LOW )
|
|
{
|
|
os_delay_us(1);
|
|
if (--loopCntHIGH == 0) return DHTLIB_ERROR_TIMEOUT;
|
|
}
|
|
|
|
if ((system_get_time() - t) > 40)
|
|
{
|
|
dht_bytes[idx] |= mask;
|
|
}
|
|
mask >>= 1;
|
|
if (mask == 0) // next byte?
|
|
{
|
|
mask = 128;
|
|
idx++;
|
|
}
|
|
}
|
|
// Enable interrupts
|
|
ets_intr_unlock();
|
|
// pinMode(pin, OUTPUT);
|
|
DIRECT_MODE_OUTPUT(pin);
|
|
// digitalWrite(pin, HIGH);
|
|
DIRECT_WRITE_HIGH(pin);
|
|
|
|
return DHTLIB_OK;
|
|
}
|
|
|
|
// Assembles the high and low byte in a signed 16bit value
|
|
static double getValue(dht_Signal s)
|
|
{
|
|
uint8_t high=0, low=0;
|
|
|
|
// the '8' variants leave the low byte set to 0
|
|
switch(s){
|
|
case Humidity:
|
|
low = dht_bytes[1];
|
|
case Humidity8:
|
|
high = dht_bytes[0];
|
|
break;
|
|
case Temperature:
|
|
low = dht_bytes[3];
|
|
case Temperature8:
|
|
high = dht_bytes[2];
|
|
break;
|
|
}
|
|
return ((high << 8) | low) * 0.1;
|
|
}
|
|
|
|
static bool verifyChecksum(){
|
|
uint8_t sum = dht_bytes[0] + dht_bytes[1] + dht_bytes[2] + dht_bytes[3];
|
|
return (dht_bytes[4] == sum);
|
|
}
|
|
|
|
//
|
|
// END OF FILE
|
|
//
|