Browse Source

Fix DHT module (#3334)

* DHT module negative values bug fix
* Revamp of the DHT module, DHT12 support
* Updated documentation
Lukáš Voborský 3 years ago
parent
commit
9c1f4aca5b
4 changed files with 103 additions and 185 deletions
  1. 53 136
      app/dht/dht.c
  2. 8 11
      app/dht/dht.h
  3. 15 36
      app/modules/dht.c
  4. 27 2
      docs/modules/dht.md

+ 53 - 136
app/dht/dht.c

@@ -26,6 +26,7 @@
 //
 // Released to the public domain
 //
+// #define NODE_DEBUG
 
 #include "user_interface.h"
 #include "platform.h"
@@ -40,21 +41,14 @@
 #define HIGH    1
 #endif /* ifndef HIGH */
 
+#define COMBINE_HIGH_AND_LOW_BYTE(byte_high, byte_low)  ((uint16_t)((byte_high) << 8) | (byte_low))
+
 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();
 
 /////////////////////////////////////////////////////
 //
@@ -79,10 +73,15 @@ double dht_getTemperature(void)
 // DHTLIB_OK
 // DHTLIB_ERROR_CHECKSUM
 // DHTLIB_ERROR_TIMEOUT
-int dht_read_universal(uint8_t pin)
+int dht_read(uint8_t pin, dht_type type)
 {
     // READ VALUES
-    int rv = dht_readSensor(pin, DHTLIB_DHT_UNI_WAKEUP);
+    int rv = dht_readSensor(pin, 
+      type == DHT22 ? DHTLIB_DHT_WAKEUP : 
+      type == DHT11 ? DHTLIB_DHT11_WAKEUP :
+      DHTLIB_DHT_UNI_WAKEUP
+    );
+    
     if (rv != DHTLIB_OK)
     {
         dht_humidity    = DHTLIB_INVALID_VALUE;  // invalid value, or is NaN prefered?
@@ -90,129 +89,73 @@ int dht_read_universal(uint8_t pin)
         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)
+    NODE_DBG("DHT registers: %x\t%x\t%x\t%x\t%x == %x\n", dht_bytes[0], dht_bytes[1], dht_bytes[2], dht_bytes[3], dht_bytes[4], (uint8_t)(dht_bytes[0] + dht_bytes[1] + dht_bytes[2] + dht_bytes[3]));
 
-    // Assume it is DHT11
+    // Assume it is special case of DHT11,
+    // i.e. positive temperature and dht_bytes[3] == 0 ((dht_bytes[3] & 0x0f) * 0.1 to be added to temperature readout)
     // If it is DHT11, both temp and humidity's decimal
+    dht_humidity    = dht_bytes[0];
+    dht_temperature = dht_bytes[2];
     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);
+        NODE_DBG("DHT11 method\n");
 
         // 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
+        uint8_t sum = dht_bytes[0] + dht_bytes[2];
+        if (dht_bytes[4] == sum)
         {
             return DHTLIB_OK;
         }
     }
 
-    // Assume it is not DHT11
+    // Assume it is not DHT11 special case
     // CONVERT AND STORE
-    DHT_DEBUG("DHTxx method\n");
-    dht_humidity = getValue(Humidity);
-    dht_temperature = getValue(Temperature);
-
-    // TEST CHECKSUM
-    if (!verifyChecksum())
-    {
-        return DHTLIB_ERROR_CHECKSUM;
+    NODE_DBG("DHTxx method\n");
+
+    switch (type) {
+      case DHT11:
+      case DHT12:
+        dht_humidity += dht_bytes[1] * 0.1;
+        break;
+      default:
+        dht_humidity = COMBINE_HIGH_AND_LOW_BYTE(dht_bytes[0], dht_bytes[1]) * 0.1;
+        break;
     }
-    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
+    switch (type) {
+      case DHT11:
+        if (dht_bytes[3] & 0x80) {
+          dht_temperature = -1 - dht_temperature;
+        }
+        dht_temperature += (dht_bytes[3] & 0x0f) * 0.1;
+        break;
+      case DHT12:
+        dht_temperature += (dht_bytes[3] & 0x0f) * 0.1;
+        if (dht_bytes[2] & 0x80)  // negative dht_temperature
+        {
+            dht_temperature *= -1;
+        }
+        break;
+      default: // DHT22, DHT_NON11
+        dht_temperature = COMBINE_HIGH_AND_LOW_BYTE(dht_bytes[2] & 0x7F, dht_bytes[3]) * 0.1;
+        if (dht_bytes[2] & 0x80)  // negative dht_temperature
+        {
+            dht_temperature *= -1;
+        }
+        break;
     }
 
-    // CONVERT AND STORE
-    dht_humidity = getValue(Humidity);
-    dht_temperature = getValue(Temperature);
-
     // TEST CHECKSUM
-    if (!verifyChecksum())
+    uint8_t sum = dht_bytes[0] + dht_bytes[1] + dht_bytes[2] + dht_bytes[3];
+    if (dht_bytes[4] != sum)
     {
         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
@@ -236,7 +179,7 @@ int dht_readSensor(uint8_t pin, uint8_t wakeupDelay)
     // volatile uint8_t *PIR = portInputRegister(port);
 
     // EMPTY BUFFER
-    memset(dht_bytes, sizeof(uint8_t)*5, 0);
+    memset(dht_bytes, 0, sizeof(uint8_t)*5);
 
     // REQUEST SAMPLE
     // pinMode(pin, OUTPUT);
@@ -309,32 +252,6 @@ int dht_readSensor(uint8_t pin, uint8_t wakeupDelay)
     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
 //

+ 8 - 11
app/dht/dht.h

@@ -30,8 +30,6 @@
 #define DHTLIB_DHT_WAKEUP       1
 #define DHTLIB_DHT_UNI_WAKEUP   18
 
-#define DHT_DEBUG
-
 // max timeout is 100 usec.
 // For a 16 Mhz proc 100 usec is 1600 clock cycles
 // loops using DHTLIB_TIMEOUT use at least 4 clock cycli
@@ -48,19 +46,18 @@
 #define DIRECT_WRITE_LOW(pin)    (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), 0))
 #define DIRECT_WRITE_HIGH(pin)   (GPIO_OUTPUT_SET(GPIO_ID_PIN(pin_num[pin]), 1))
 
+typedef enum {
+    DHT11 = 0,
+    DHT12,
+    DHT22,
+    DHT_NON11
+} dht_type;
+
 // return values:
 // DHTLIB_OK
 // DHTLIB_ERROR_CHECKSUM
 // DHTLIB_ERROR_TIMEOUT
-int dht_read_universal(uint8_t pin);
-int dht_read11(uint8_t pin);
-int dht_read(uint8_t pin);
-
-int dht_read21(uint8_t pin);
-int dht_read22(uint8_t pin);
-int dht_read33(uint8_t pin);
-int dht_read44(uint8_t pin);
-
+int dht_read(uint8_t pin, dht_type type);
 double dht_getHumidity(void);
 double dht_getTemperature(void);
 

+ 15 - 36
app/modules/dht.c

@@ -32,7 +32,7 @@ static int dht_lapi_read( lua_State *L )
 {
   unsigned id = luaL_checkinteger( L, 1 );
   MOD_CHECK_ID( dht, id );
-  lua_pushinteger( L, dht_read_universal(id) );
+  lua_pushinteger( L, dht_read(id, DHT_NON11) );
   aux_read( L );
   return 5;
 }
@@ -42,7 +42,17 @@ static int dht_lapi_read11( lua_State *L )
 {
   unsigned id = luaL_checkinteger( L, 1 );
   MOD_CHECK_ID( dht, id );
-  lua_pushinteger( L, dht_read11(id) );
+  lua_pushinteger( L, dht_read(id, DHT11) );
+  aux_read( L );
+  return 5;
+}
+
+// Lua: status, temp, humi, tempdec, humidec = dht.read12( id ))
+static int dht_lapi_read12( lua_State *L )
+{
+  unsigned id = luaL_checkinteger( L, 1 );
+  MOD_CHECK_ID( dht, id );
+  lua_pushinteger( L, dht_read(id, DHT12) );
   aux_read( L );
   return 5;
 }
@@ -52,48 +62,17 @@ static int dht_lapi_readxx( lua_State *L )
 {
   unsigned id = luaL_checkinteger( L, 1 );
   MOD_CHECK_ID( dht, id );
-  lua_pushinteger( L, dht_read(id) );
+  lua_pushinteger( L, dht_read(id, DHT22) );
   aux_read( L );
   return 5;
 }
 
-// // Lua: result = dht.humidity()
-// static int dht_lapi_humidity( lua_State *L )
-// {
-//   lua_pushnumber( L, dht_getHumidity() );
-//   return 1;
-// }
-
-// // Lua: result = dht.humiditydecimal()
-// static int dht_lapi_humiditydecimal( lua_State *L )
-// {
-//   double value = dht_getHumidity();
-//   int result = (int)((value - (int)value) * 1000);
-//   lua_pushnumber( L, result );
-//   return 1;
-// }
-
-// // Lua: result = dht.temperature()
-// static int dht_lapi_temperature( lua_State *L )
-// {
-//   lua_pushnumber( L, dht_getTemperature() );
-//   return 1;
-// }
-
-// // Lua: result = dht.temperaturedecimal()
-// static int dht_lapi_temperaturedecimal( lua_State *L )
-// {
-//   double value = dht_getTemperature();
-//   int result = (int)((value - (int)value) * 1000);
-//   lua_pushnumber( L, result );
-//   return 1;
-// }
-
 // Module function map
 LROT_BEGIN(dht, NULL, 0)
   LROT_FUNCENTRY( read, dht_lapi_read )
   LROT_FUNCENTRY( read11, dht_lapi_read11 )
-  LROT_FUNCENTRY( readxx, dht_lapi_readxx )
+  LROT_FUNCENTRY( read12, dht_lapi_read12 )
+  LROT_FUNCENTRY( readxx, dht_lapi_read )
   LROT_NUMENTRY( OK, DHTLIB_OK )
   LROT_NUMENTRY( ERROR_CHECKSUM, DHTLIB_ERROR_CHECKSUM )
   LROT_NUMENTRY( ERROR_TIMEOUT, DHTLIB_ERROR_TIMEOUT )

+ 27 - 2
docs/modules/dht.md

@@ -9,7 +9,8 @@ Constants for various functions.
 `dht.OK`, `dht.ERROR_CHECKSUM`, `dht.ERROR_TIMEOUT` represent the potential values for the DHT read status
 
 ## dht.read()
-Read all kinds of DHT sensors, including DHT11, 21, 22, 33, 44 humidity temperature combo sensor.
+Reads all kinds of DHT sensors, including DHT11, 21, 22, 33, 44 humidity temperature combo sensor.
+Returns correct readout except for DHT12 and negative temperatures by DHT11. Use [`dht.read12()`](#dhtread12) and  [`dht.read11()`](#dhtread11) instead. It is to use model specific read function anyway.
 
 #### Syntax
 `dht.read(pin)`
@@ -74,8 +75,32 @@ Read DHT11 humidity temperature combo sensor.
 #### See also
 [dht.read()](#dhtread)
 
+## dht.read12()
+Read DHT12 humidity temperature combo sensor.
+
+#### Syntax
+`dht.read12(pin)`
+
+#### Parameters
+`pin` pin number of DHT12 sensor (can't be 0), type is number
+
+#### Returns
+- `status` as defined in Constants
+- `temp` temperature (see note below)
+- `humi` humidity (see note below)
+- `temp_dec` temperature decimal
+- `humi_dec` humidity decimal
+
+!!! note
+
+    If using float firmware then `temp` and `humi` are floating point numbers. On an integer firmware, the final values have to be concatenated from `temp` and `temp_dec` / `humi` and `hum_dec`.
+
+#### See also
+[dht.read()](#dhtread)
+
+
 ## dht.readxx()
-Read all kinds of DHT sensors, except DHT11.
+Read all kinds of DHT sensors, except DHT11 and DHT12. Differs from `dht.read()` only by waiting only sufficient 1 ms for sensor wake-up while `dht.read()` waits universal 18 ms.
 
 ####Syntax
 `dht.readxx(pin)`