Emdioh bf15299cea
Correct negative results in DHT driver (#3210)
* 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>
2020-08-03 19:58:19 +01:00

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
//