Add dht module.
This commit is contained in:
parent
c8e99d50a5
commit
927ee7fc5f
|
@ -60,6 +60,12 @@ config LUA_MODULE_BTHCI
|
||||||
help
|
help
|
||||||
Includes the simple BlueTooth HCI module.
|
Includes the simple BlueTooth HCI module.
|
||||||
|
|
||||||
|
config LUA_MODULE_DHT
|
||||||
|
bool "DHT11/21/22/AM2301/AM2302 module"
|
||||||
|
default "n"
|
||||||
|
help
|
||||||
|
Includes the dht module.
|
||||||
|
|
||||||
config LUA_MODULE_ENCODER
|
config LUA_MODULE_ENCODER
|
||||||
bool "Encoder module"
|
bool "Encoder module"
|
||||||
default "n"
|
default "n"
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
|
||||||
|
|
||||||
|
#include "module.h"
|
||||||
|
#include "lauxlib.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LDHT_OK = 0,
|
||||||
|
LDHT_ERROR_CHECKSUM = -1,
|
||||||
|
LDHT_ERROR_TIMEOUT = -2,
|
||||||
|
LDHT_INVALID_VALUE = -999
|
||||||
|
} ldht_result_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
LDHT11,
|
||||||
|
LDHT2X
|
||||||
|
} ldht_type_t;
|
||||||
|
|
||||||
|
static int ldht_compute_data11( uint8_t *data, double *temp, double *humi )
|
||||||
|
{
|
||||||
|
*humi = data[0];
|
||||||
|
*temp = data[2];
|
||||||
|
|
||||||
|
uint8_t sum = data[0] + data[1] + data[2] + data[3];
|
||||||
|
return sum == data[4] ? LDHT_OK : LDHT_ERROR_CHECKSUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ldht_compute_data2x( uint8_t *data, double *temp, double *humi )
|
||||||
|
{
|
||||||
|
*humi = (data[0] * 256 + data[1]) * 0.1;
|
||||||
|
*temp = ((data[2] & 0x7f) * 256 + data[3]) * 0.1;
|
||||||
|
|
||||||
|
if (data[2] & 0x80)
|
||||||
|
*temp = - *temp;
|
||||||
|
|
||||||
|
uint8_t sum = data[0] + data[1] + data[2] + data[3];
|
||||||
|
return sum == data[4] ? LDHT_OK : LDHT_ERROR_CHECKSUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ldht_read_generic( lua_State *L, ldht_type_t type )
|
||||||
|
{
|
||||||
|
int stack = 0;
|
||||||
|
|
||||||
|
int gpio = luaL_checkint( L, ++stack );
|
||||||
|
luaL_argcheck( L, platform_gpio_output_exists( gpio ), stack, "invalid gpio" );
|
||||||
|
|
||||||
|
uint8_t data[5];
|
||||||
|
if (platform_dht_read( gpio,
|
||||||
|
type == LDHT11 ? PLATFORM_DHT11_WAKEUP_MS : PLATFORM_DHT2X_WAKEUP_MS,
|
||||||
|
data ) != PLATFORM_OK) {
|
||||||
|
lua_pushinteger( L, LDHT_ERROR_TIMEOUT );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
double temp, humi;
|
||||||
|
int res;
|
||||||
|
switch (type) {
|
||||||
|
case LDHT11:
|
||||||
|
res = ldht_compute_data11( data, &temp, &humi );
|
||||||
|
break;
|
||||||
|
case LDHT2X:
|
||||||
|
res = ldht_compute_data2x( data, &temp, &humi );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res = LDHT_INVALID_VALUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lua_pushinteger( L, res );
|
||||||
|
lua_pushnumber( L, temp );
|
||||||
|
lua_pushnumber( L, humi );
|
||||||
|
int tempdec = (int)((temp - (int)temp) * 1000);
|
||||||
|
int humidec = (int)((humi - (int)humi) * 1000);
|
||||||
|
lua_pushinteger( L, tempdec );
|
||||||
|
lua_pushinteger( L, humidec );
|
||||||
|
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ldht_read11( lua_State *L )
|
||||||
|
{
|
||||||
|
return ldht_read_generic( L, LDHT11 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ldht_read2x( lua_State *L )
|
||||||
|
{
|
||||||
|
return ldht_read_generic( L, LDHT2X );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const LUA_REG_TYPE dht_map[] = {
|
||||||
|
{ LSTRKEY( "read11" ), LFUNCVAL( ldht_read11 ) },
|
||||||
|
{ LSTRKEY( "read2x" ), LFUNCVAL( ldht_read2x ) },
|
||||||
|
{ LSTRKEY( "OK" ), LNUMVAL( LDHT_OK ) },
|
||||||
|
{ LSTRKEY( "ERROR_CHECKSUM" ), LNUMVAL( LDHT_ERROR_CHECKSUM ) },
|
||||||
|
{ LSTRKEY( "ERROR_TIMEOUT" ), LNUMVAL( LDHT_ERROR_TIMEOUT ) },
|
||||||
|
{ LNILKEY, LNILVAL }
|
||||||
|
};
|
||||||
|
|
||||||
|
NODEMCU_MODULE(DHT, "dht", dht_map, NULL);
|
|
@ -0,0 +1,205 @@
|
||||||
|
|
||||||
|
/* ****************************************************************************
|
||||||
|
*
|
||||||
|
* ESP32 platform interface for DHT temperature & humidity sensors
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017, Arnim Laeuger
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
* ****************************************************************************/
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
#include "driver/rmt.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
|
||||||
|
#undef DHT_DEBUG
|
||||||
|
|
||||||
|
// RX idle threshold [us]
|
||||||
|
// needs to be larger than any duration occurring during bit slots
|
||||||
|
// datasheet specs up to 200us for "Bus master has released time"
|
||||||
|
#define DHT_DURATION_RX_IDLE (250)
|
||||||
|
|
||||||
|
// zero bit duration threshold [us]
|
||||||
|
// a high phase
|
||||||
|
// * shorter than this is detected as a zero bit
|
||||||
|
// * longer than this is detected as a one bit
|
||||||
|
#define DHT_DURATION_ZERO (50)
|
||||||
|
|
||||||
|
|
||||||
|
// grouped information for RMT management
|
||||||
|
static struct {
|
||||||
|
int channel;
|
||||||
|
RingbufHandle_t rb;
|
||||||
|
int gpio;
|
||||||
|
} dht_rmt = {-1, NULL, -1};
|
||||||
|
|
||||||
|
|
||||||
|
static void dht_deinit( void )
|
||||||
|
{
|
||||||
|
// drive idle level 1
|
||||||
|
gpio_set_level( dht_rmt.gpio, 1 );
|
||||||
|
|
||||||
|
rmt_rx_stop( dht_rmt.channel );
|
||||||
|
rmt_driver_uninstall( dht_rmt.channel );
|
||||||
|
|
||||||
|
platform_rmt_release( dht_rmt.channel );
|
||||||
|
|
||||||
|
// invalidate channel and gpio assignments
|
||||||
|
dht_rmt.channel = -1;
|
||||||
|
dht_rmt.gpio = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dht_init( uint8_t gpio_num )
|
||||||
|
{
|
||||||
|
// acquire an RMT module for RX
|
||||||
|
if ((dht_rmt.channel = platform_rmt_allocate( 1 )) >= 0) {
|
||||||
|
|
||||||
|
#ifdef DHT_DEBUG
|
||||||
|
ESP_LOGI("dht", "RMT RX channel: %d", dht_rmt.channel);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rmt_config_t rmt_rx;
|
||||||
|
rmt_rx.channel = dht_rmt.channel;
|
||||||
|
rmt_rx.gpio_num = gpio_num;
|
||||||
|
rmt_rx.clk_div = 80; // base period is 1us
|
||||||
|
rmt_rx.mem_block_num = 1;
|
||||||
|
rmt_rx.rmt_mode = RMT_MODE_RX;
|
||||||
|
rmt_rx.rx_config.filter_en = true;
|
||||||
|
rmt_rx.rx_config.filter_ticks_thresh = 30;
|
||||||
|
rmt_rx.rx_config.idle_threshold = DHT_DURATION_RX_IDLE;
|
||||||
|
if (rmt_config( &rmt_rx ) == ESP_OK) {
|
||||||
|
if (rmt_driver_install( rmt_rx.channel, 512, 0 ) == ESP_OK) {
|
||||||
|
|
||||||
|
rmt_get_ringbuf_handler( dht_rmt.channel, &dht_rmt.rb );
|
||||||
|
|
||||||
|
dht_rmt.gpio = gpio_num;
|
||||||
|
|
||||||
|
// use gpio for TX direction
|
||||||
|
// drive idle level 1
|
||||||
|
gpio_set_level( gpio_num, 1 );
|
||||||
|
gpio_pullup_dis( gpio_num );
|
||||||
|
gpio_pulldown_dis( gpio_num );
|
||||||
|
gpio_set_direction( gpio_num, GPIO_MODE_INPUT_OUTPUT_OD );
|
||||||
|
gpio_set_intr_type( gpio_num, GPIO_INTR_DISABLE );
|
||||||
|
|
||||||
|
return PLATFORM_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_rmt_release( dht_rmt.channel );
|
||||||
|
}
|
||||||
|
|
||||||
|
return PLATFORM_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int platform_dht_read( uint8_t gpio_num, uint8_t wakeup_ms, uint8_t *data )
|
||||||
|
{
|
||||||
|
if (dht_init( gpio_num ) != PLATFORM_OK)
|
||||||
|
return PLATFORM_ERR;
|
||||||
|
|
||||||
|
// send start signal and arm RX channel
|
||||||
|
TickType_t xDelay = pdMS_TO_TICKS( wakeup_ms ) > 0 ? pdMS_TO_TICKS( wakeup_ms ) : 1;
|
||||||
|
gpio_set_level( gpio_num, 0 ); // pull wire low
|
||||||
|
vTaskDelay( xDelay ); // time low phase
|
||||||
|
rmt_rx_start( dht_rmt.channel, true ); // arm RX channel
|
||||||
|
gpio_set_level( gpio_num, 1 ); // release wire
|
||||||
|
|
||||||
|
// wait for incoming bit stream
|
||||||
|
size_t rx_size;
|
||||||
|
rmt_item32_t* rx_items = (rmt_item32_t *)xRingbufferReceive( dht_rmt.rb, &rx_size, pdMS_TO_TICKS( 100 ) );
|
||||||
|
|
||||||
|
// default is "no error"
|
||||||
|
// error conditions have to overwrite this with PLATFORM_ERR
|
||||||
|
int res = PLATFORM_OK;
|
||||||
|
|
||||||
|
if (rx_items) {
|
||||||
|
|
||||||
|
#ifdef DHT_DEBUG
|
||||||
|
ESP_LOGI("dht", "rx_items received: %d", rx_size);
|
||||||
|
for (size_t i = 0; i < rx_size / 4; i++) {
|
||||||
|
ESP_LOGI("dht", "level: %d, duration %d", rx_items[i].level0, rx_items[i].duration0);
|
||||||
|
ESP_LOGI("dht", "level: %d, duration %d", rx_items[i].level1, rx_items[i].duration1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// we expect 40 bits of payload plus a response bit and two edges for start and stop signals
|
||||||
|
// each bit on the wire consumes 2 rmt samples (and 2 rmt samples stretch over 4 bytes)
|
||||||
|
if (rx_size >= (5*8 + 1+1) * 4) {
|
||||||
|
|
||||||
|
// check framing
|
||||||
|
if (rx_items[ 0].level0 == 1 && // rising edge of the start signal
|
||||||
|
rx_items[ 0].level1 == 0 && rx_items[1].level0 == 1 && // response signal
|
||||||
|
rx_items[41].level1 == 0) { // falling edge of stop signal
|
||||||
|
|
||||||
|
// run through the bytes
|
||||||
|
for (size_t byte = 0; byte < 5 && res == PLATFORM_OK; byte++) {
|
||||||
|
size_t bit_pos = 1 + byte*8;
|
||||||
|
data[byte] = 0;
|
||||||
|
|
||||||
|
// decode the bits inside a byte
|
||||||
|
for (size_t bit = 0; bit < 8; bit++, bit_pos++) {
|
||||||
|
if (rx_items[bit_pos].level1 != 0) {
|
||||||
|
// not a falling edge, terminate decoding
|
||||||
|
res = PLATFORM_ERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// ignore duration of low level
|
||||||
|
|
||||||
|
// data is sent MSB first
|
||||||
|
data[byte] <<= 1;
|
||||||
|
if (rx_items[bit_pos + 1].level0 == 1 && rx_items[bit_pos + 1].duration0 > DHT_DURATION_ZERO)
|
||||||
|
data[byte] |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DHT_DEBUG
|
||||||
|
ESP_LOGI("dht", "data 0x%02x", data[byte]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// all done
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// framing mismatch on start, response, or stop signals
|
||||||
|
res = PLATFORM_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// too few bits received
|
||||||
|
res = PLATFORM_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
vRingbufferReturnItem( dht_rmt.rb, (void *)rx_items );
|
||||||
|
} else {
|
||||||
|
// time out occurred, this indicates an unconnected / misconfigured bus
|
||||||
|
res = PLATFORM_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
dht_deinit();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
|
@ -164,6 +164,14 @@ uint8_t platform_onewire_crc8( const uint8_t *addr, uint8_t len );
|
||||||
bool platform_onewire_check_crc16( const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc );
|
bool platform_onewire_check_crc16( const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc );
|
||||||
uint16_t platform_onewire_crc16( const uint8_t* input, uint16_t len, uint16_t crc );
|
uint16_t platform_onewire_crc16( const uint8_t* input, uint16_t len, uint16_t crc );
|
||||||
|
|
||||||
|
// *****************************************************************************
|
||||||
|
// DHT platform interface
|
||||||
|
#define PLATFORM_DHT11_WAKEUP_MS 20
|
||||||
|
#define PLATFORM_DHT2X_WAKEUP_MS 1
|
||||||
|
|
||||||
|
int platform_dht_read( uint8_t gpio_num, uint8_t wakeup_ms, uint8_t *data );
|
||||||
|
|
||||||
|
|
||||||
// Internal flash erase/write functions
|
// Internal flash erase/write functions
|
||||||
|
|
||||||
uint32_t platform_flash_get_sector_of_address( uint32_t addr );
|
uint32_t platform_flash_get_sector_of_address( uint32_t addr );
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
# DHT Module
|
||||||
|
| Since | Origin / Contributor | Maintainer | Source |
|
||||||
|
| :----- | :-------------------- | :---------- | :------ |
|
||||||
|
| 2017-03-30 | [Arnim Läuger](https://github.com/devsaurus) | [Arnim Läuger](https://github.com/devsaurus) | [dht](../../../components/modules/dht.c)|
|
||||||
|
|
||||||
|
## Constants
|
||||||
|
Constants for various functions.
|
||||||
|
|
||||||
|
`dht.OK`, `dht.ERROR_CHECKSUM`, `dht.ERROR_TIMEOUT` represent the potential values for the DHT read status
|
||||||
|
|
||||||
|
## dht.read11()
|
||||||
|
Read DHT11 humidity temperature combo sensor.
|
||||||
|
|
||||||
|
#### Syntax
|
||||||
|
`dht.read11(pin)`
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
`pin` 0~33, IO index
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
- `status` as defined in Constants
|
||||||
|
- `temp` temperature
|
||||||
|
- `humi` humidity
|
||||||
|
- `temp_dec` temperature decimal (always 0)
|
||||||
|
- `humi_dec` humidity decimal (always 0)
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
```lua
|
||||||
|
pin = 4
|
||||||
|
status, temp, humi = dht.read11(pin)
|
||||||
|
if status == dht.OK then
|
||||||
|
print("DHT Temperature:"..temp..";".."Humidity:"..humi)
|
||||||
|
|
||||||
|
elseif status == dht.ERROR_CHECKSUM then
|
||||||
|
print( "DHT Checksum error." )
|
||||||
|
elseif status == dht.ERROR_TIMEOUT then
|
||||||
|
print( "DHT timed out." )
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## dht.read2x()
|
||||||
|
Read DHT21/22/33/43 and AM2301/2302/2303 humidity temperature combo sensors.
|
||||||
|
|
||||||
|
#### Syntax
|
||||||
|
`dht.read2x(pin)`
|
||||||
|
|
||||||
|
#### Parameters
|
||||||
|
`pin` 0~33, IO index
|
||||||
|
|
||||||
|
#### 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`.
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
```lua
|
||||||
|
pin = 4
|
||||||
|
status, temp, humi, temp_dec, humi_dec = dht.read2x(pin)
|
||||||
|
if status == dht.OK then
|
||||||
|
-- Integer firmware using this example
|
||||||
|
print(string.format("DHT Temperature:%d.%03d;Humidity:%d.%03d\r\n",
|
||||||
|
math.floor(temp),
|
||||||
|
temp_dec,
|
||||||
|
math.floor(humi),
|
||||||
|
humi_dec
|
||||||
|
))
|
||||||
|
|
||||||
|
-- Float firmware using this example
|
||||||
|
print("DHT Temperature:"..temp..";".."Humidity:"..humi)
|
||||||
|
|
||||||
|
elseif status == dht.ERROR_CHECKSUM then
|
||||||
|
print( "DHT Checksum error." )
|
||||||
|
elseif status == dht.ERROR_TIMEOUT then
|
||||||
|
print( "DHT timed out." )
|
||||||
|
end
|
||||||
|
```
|
|
@ -1,7 +0,0 @@
|
||||||
Support for this Lua module has been discontinued.
|
|
||||||
|
|
||||||
Equivalent functionality is available from the dht module in the NodeMCU
|
|
||||||
firmware code base. Refer to `docs/en/modules/dht.md` for API
|
|
||||||
documentation.
|
|
||||||
|
|
||||||
The original Lua code can be found in the [git repository](https://github.com/nodemcu/nodemcu-firmware/tree/2fbd5ed509964a16057b22e00aa8469d6a522d73/lua_modules/dht_lib).
|
|
|
@ -33,6 +33,7 @@ pages:
|
||||||
- Modules:
|
- Modules:
|
||||||
- 'bit': 'en/modules/bit.md'
|
- 'bit': 'en/modules/bit.md'
|
||||||
- 'bthci': 'en/modules/bthci.md'
|
- 'bthci': 'en/modules/bthci.md'
|
||||||
|
- 'dht': 'en/modules/dht.md'
|
||||||
- 'file': 'en/modules/file.md'
|
- 'file': 'en/modules/file.md'
|
||||||
- 'i2c': 'en/modules/i2c.md'
|
- 'i2c': 'en/modules/i2c.md'
|
||||||
- 'node': 'en/modules/node.md'
|
- 'node': 'en/modules/node.md'
|
||||||
|
|
Loading…
Reference in New Issue