From 99eba80c4dd27b2b06f19ba7e162029b414a54ae Mon Sep 17 00:00:00 2001 From: jsuiker Date: Wed, 20 Apr 2016 22:03:18 +0000 Subject: [PATCH] Added DHT library to extras and sample code to examples --- examples/dht_sensor/Makefile | 4 + examples/dht_sensor/dht_sensor.c | 46 ++++++++++ extras/dht/component.mk | 10 +++ extras/dht/dht.c | 144 +++++++++++++++++++++++++++++++ extras/dht/dht.h | 17 ++++ 5 files changed, 221 insertions(+) create mode 100644 examples/dht_sensor/Makefile create mode 100644 examples/dht_sensor/dht_sensor.c create mode 100644 extras/dht/component.mk create mode 100644 extras/dht/dht.c create mode 100644 extras/dht/dht.h diff --git a/examples/dht_sensor/Makefile b/examples/dht_sensor/Makefile new file mode 100644 index 0000000..cfdde69 --- /dev/null +++ b/examples/dht_sensor/Makefile @@ -0,0 +1,4 @@ +PROGRAM=dht_sensor +EXTRA_COMPONENTS = extras/dht +include ../../common.mk + diff --git a/examples/dht_sensor/dht_sensor.c b/examples/dht_sensor/dht_sensor.c new file mode 100644 index 0000000..11f2c43 --- /dev/null +++ b/examples/dht_sensor/dht_sensor.c @@ -0,0 +1,46 @@ +/* + * + * This sample code is in the public domain. + */ +#include "espressif/esp_common.h" +#include "esp/uart.h" +#include "FreeRTOS.h" +#include "task.h" +#include "dht.h" +#include "esp8266.h" + +/* An example using the ubiquitous DHT** humidity sensors + * to read and print a new temperature and humidity measurement + * from a sensor attached to GPIO pin 4. + */ +int const dht_gpio = 4; + +void dhtMeasurementTask(void *pvParameters) +{ + int8_t temperature = 0; + int8_t humidity = 0; + + // DHT sensors that come mounted on a PCB generally have + // pull-up resistors on the data pin. It is recommended + // to provide an external pull-up resistor otherwise... + gpio_set_pullup(dht_gpio, false, false); + + while(1) { + + if (dht_fetch_data(dht_gpio, &humidity, &temperature)) { + printf("Humidity: %i%% Temp: %iC\n", humidity, temperature); + } else { + printf("Could not read data from sensor..."); + } + + // Three second delay... + vTaskDelay(3000 / portTICK_RATE_MS); + } +} + +void user_init(void) +{ + uart_set_baud(0, 115200); + xTaskCreate(dhtMeasurementTask, (signed char *)"dhtMeasurementTask", 256, NULL, 2, NULL); +} + diff --git a/extras/dht/component.mk b/extras/dht/component.mk new file mode 100644 index 0000000..0948e4d --- /dev/null +++ b/extras/dht/component.mk @@ -0,0 +1,10 @@ +# Component makefile for extras/dht + +INC_DIRS += $(ROOT)extras/dht + +# args for passing into compile rule generation +extras/dht_INC_DIR = $(ROOT)extras/dht +extras/dht_SRC_DIR = $(ROOT)extras/dht + +$(eval $(call component_compile_rules,extras/dht)) + diff --git a/extras/dht/dht.c b/extras/dht/dht.c new file mode 100644 index 0000000..100763a --- /dev/null +++ b/extras/dht/dht.c @@ -0,0 +1,144 @@ +/* + * Part of esp-open-rtos + * Copyright (C) 2016 Jonathan Hartsuiker (https://github.com/jsuiker) + * BSD Licensed as described in the file LICENSE + * + */ + +#include "dht.h" +#include "string.h" +#include "task.h" +#include "esp/gpio.h" + +#include // sdk_os_delay_us + +#ifndef DEBUG_DHT +#define DEBUG_DHT 0 +#endif + +#if DEBUG_DHT +#define debug(fmt, ...) printf("%s" fmt "\n", "dht: ", ## __VA_ARGS__); +#else +#define debug(fmt, ...) /* (do nothing) */ +#endif + +/* + * Note: + * A suitable pull-up resistor should be connected to the selected GPIO line + * + * __ ______ _______ ___________________________ + * \ A / \ C / \ DHT duration_data_low / \ + * \_______/ B \______/ D \__________________________/ DHT duration_data_high \__ + * + * + * Initializing communications with the DHT requires four 'phases' as follows: + * + * Phase A - MCU pulls signal low for at least 18000 us + * Phase B - MCU allows signal to float back up and waits 20-40us for DHT to pull it low + * Phase C - DHT pulls signal low for ~80us + * Phase D - DHT lets signal float back up for ~80us + * + * After this, the DHT transmits its first bit by holding the signal low for 50us + * and then letting it float back high for a period of time that depends on the data bit. + * duration_data_high is shorter than 50us for a logic '0' and longer than 50us for logic '1'. + * + * There are a total of 40 data bits trasnmitted sequentially. These bits are read into a byte array + * of length 5. The first and third bytes are humidity (%) and temperature (C), respectively. Bytes 2 and 4 + * are zero-filled and the fifth is a checksum such that: + * + * byte_5 == (byte_1 + byte_2 + byte_3 + btye_4) & 0xFF + * +*/ + +/* + * @pin the selected GPIO pin + * @interval how frequently the pin state is checked in microseconds + * @timeout maximum length of time to wait for the expected pin state + * @expected_pin_state high (true) or low (false) pin state + * @counter pointer to external uint8_t for tallying the duration waited for the pin state +*/ + +bool dht_await_pin_state(uint8_t pin, uint8_t interval, uint8_t timeout, bool expected_pin_state, uint8_t * counter) { + + for (*counter = 0; *counter < timeout; *counter+=interval) { + if (gpio_read(pin) == expected_pin_state) return true; + sdk_os_delay_us(interval); + } + + return false; +} + +/* + * + * + * @pin the selected GPIO pin + * @humidity pointer to external int8_t to store resulting humidity value + * @temperature pointer to external int8_t to store resulting temperature value +*/ + +bool dht_fetch_data(int8_t pin, int8_t * humidity, int8_t * temperature) { + int8_t data[40] = {0}; + int8_t result[5] = {0}; + uint8_t i = 0; + + uint8_t init_phase_duration = 0; + uint8_t duration_data_low = 0; + uint8_t duration_data_high = 0; + + gpio_enable(pin, GPIO_OUT_OPEN_DRAIN); + + taskENTER_CRITICAL(); + + // Phase 'A' pulling signal low to initiate read sequence + gpio_write(pin, 0); + sdk_os_delay_us(20000); + gpio_write(pin, 1); + + // Step through Phase 'B' at 2us intervals, 40us max + if (dht_await_pin_state(pin, 2, 40, false, &init_phase_duration)) { + // Step through Phase 'C ' at 2us intervals, 88us max + if (dht_await_pin_state(pin, 2, 88, true, &init_phase_duration)) { + // Step through Phase 'D' at 2us intervals, 88us max + if (dht_await_pin_state(pin, 2, 88, false, &init_phase_duration)) { + + // Read in each of the 40 bits of data... + for (i = 0; i < 40; i++) { + if (dht_await_pin_state(pin, 2, 60, true, &duration_data_low)) { + if (dht_await_pin_state(pin, 2, 75, false, &duration_data_high)) { + data[i] = duration_data_high > duration_data_low; + } + } + } + + taskEXIT_CRITICAL(); + + for (i = 0; i < 40; i++) { + // Read each bit into 'result' byte array... + result[i/8] <<= 1; + result[i/8] |= data[i]; + } + + if (result[4] == ((result[0] + result[1] + result[2] + result[3]) & 0xFF)) { + // Data valid, checksum succeeded... + *humidity = result[0]; + *temperature = result[2]; + debug("Successfully retrieved sensor data..."); + return true; + } else { + debug("Checksum failed, invalid data received from sensor..."); + } + + } else { + debug("Initialization error, problem in phase 'D'..."); + } + } else { + debug("Initialization error, problem in phase 'C'..."); + } + } else { + debug("Initialization error, problem in phase 'B'..."); + } + + taskEXIT_CRITICAL(); + return false; +} + diff --git a/extras/dht/dht.h b/extras/dht/dht.h new file mode 100644 index 0000000..c8a5ed9 --- /dev/null +++ b/extras/dht/dht.h @@ -0,0 +1,17 @@ +/* + * Part of esp-open-rtos + * Copyright (C) 2016 Jonathan Hartsuiker (https://github.com/jsuiker) + * BSD Licensed as described in the file LICENSE + * + */ + +#ifndef __DTH_H__ +#define __DHT_H__ + +#include "FreeRTOS.h" + +bool dht_wait_for_pin_state(uint8_t pin, uint8_t interval, uint8_t timeout, bool expected_pin_sate, uint8_t * counter); +bool dht_fetch_data(int8_t pin, int8_t * humidity, int8_t * temperature); + +#endif +