diff --git a/drivers/dht/dht.c b/drivers/dht/dht.c index 83bca74aaf..085d71b352 100644 --- a/drivers/dht/dht.c +++ b/drivers/dht/dht.c @@ -42,12 +42,33 @@ #define PULSE_WIDTH_THRESHOLD (40U) /* If an expected pulse is not detected within 1000µs, something is wrong */ #define TIMEOUT (1000U) +/* The DHT sensor cannot measure more than once a second */ +#define DATA_HOLD_TIME (US_PER_SEC) -static inline void _reset(const dht_t *dev) +static inline void _reset(dht_t *dev) { - gpio_init(dev->pin, GPIO_OUT); - gpio_set(dev->pin); + gpio_init(dev->params.pin, GPIO_OUT); + gpio_set(dev->params.pin); +} +/** + * @brief Wait until the pin @p pin has level @p expect + * + * @param pin GPIO pin to wait for + * @param expect Wait until @p pin has this logic level + * @param timeout Timeout in µs + * + * @retval 0 Success + * @retval -1 Timeout occurred before level was reached + */ +static inline int _wait_for_level(gpio_t pin, bool expect, unsigned timeout) +{ + while (((gpio_read(pin) > 0) != expect) && timeout) { + xtimer_usleep(1); + timeout--; + } + + return (timeout > 0) ? 0 : -1; } static int _read(uint16_t *dest, gpio_t pin, int bits) @@ -60,23 +81,16 @@ static int _read(uint16_t *dest, gpio_t pin, int bits) res <<= 1; /* measure the length between the next rising and falling flanks (the * time the pin is high - smoke up :-) */ - unsigned counter = 0; - while (!gpio_read(pin)) { - if (counter++ >= TIMEOUT) { - return -1; - } - xtimer_usleep(1); + if (_wait_for_level(pin, 1, TIMEOUT)) { + return -1; } start = xtimer_now_usec(); - counter = 0; - while (gpio_read(pin)) { - if (counter++ >= TIMEOUT) { - return -1; - } - xtimer_usleep(1); + if (_wait_for_level(pin, 0, TIMEOUT)) { + return -1; } end = xtimer_now_usec(); + /* if the high phase was more than 40us, we got a 1 */ if ((end - start) > PULSE_WIDTH_THRESHOLD) { res |= 0x0001; @@ -92,10 +106,11 @@ int dht_init(dht_t *dev, const dht_params_t *params) DEBUG("dht_init\n"); /* check parameters and configuration */ - assert(dev && params && - ((params->type == DHT11) || (params->type == DHT22) || (params->type == DHT21))); + assert(dev && params); + assert((params->type == DHT11) || (params->type == DHT22) || (params->type == DHT21)); - *dev = *params; + memset(dev, 0, sizeof(dht_t)); + dev->params = *params; _reset(dev); @@ -105,91 +120,98 @@ int dht_init(dht_t *dev, const dht_params_t *params) return DHT_OK; } -int dht_read(const dht_t *dev, int16_t *temp, int16_t *hum) +int dht_read(dht_t *dev, int16_t *temp, int16_t *hum) { - uint16_t csum, sum; + uint16_t csum; uint16_t raw_hum, raw_temp; - assert(dev && temp && hum); + assert(dev); - /* send init signal to device */ - gpio_clear(dev->pin); - xtimer_usleep(20 * US_PER_MS); - gpio_set(dev->pin); - xtimer_usleep(40); + uint32_t now_us = xtimer_now_usec(); + if ((now_us - dev->last_read_us) > DATA_HOLD_TIME) { + /* send init signal to device */ + gpio_clear(dev->params.pin); + xtimer_usleep(20 * US_PER_MS); + gpio_set(dev->params.pin); + xtimer_usleep(40); - /* sync on device */ - gpio_init(dev->pin, dev->in_mode); - unsigned counter = 0; - while (!gpio_read(dev->pin)) { - if (counter++ > TIMEOUT) { + /* sync on device */ + gpio_init(dev->params.pin, dev->params.in_mode); + if (_wait_for_level(dev->params.pin, 1, TIMEOUT)) { _reset(dev); return DHT_TIMEOUT; } - xtimer_usleep(1); - } - counter = 0; - while (gpio_read(dev->pin)) { - if (counter++ > TIMEOUT) { + if (_wait_for_level(dev->params.pin, 0, TIMEOUT)) { _reset(dev); return DHT_TIMEOUT; } - xtimer_usleep(1); - } - /* - * data is read in sequentially, highest bit first: - * 40 .. 24 23 .. 8 7 .. 0 - * [humidity][temperature][checksum] - */ + /* + * data is read in sequentially, highest bit first: + * 40 .. 24 23 .. 8 7 .. 0 + * [humidity][temperature][checksum] + */ - /* read the humidity, temperature, and checksum bits */ - if (_read(&raw_hum, dev->pin, 16)) { + /* read the humidity, temperature, and checksum bits */ + if (_read(&raw_hum, dev->params.pin, 16)) { + _reset(dev); + return DHT_TIMEOUT; + } + + if (_read(&raw_temp, dev->params.pin, 16)) { + _reset(dev); + return DHT_TIMEOUT; + } + + if (_read(&csum, dev->params.pin, 8)) { + _reset(dev); + return DHT_TIMEOUT; + } + + /* Bring device back to defined state - so we can trigger the next reading + * by pulling the data pin low again */ _reset(dev); - return DHT_TIMEOUT; + + /* validate the checksum */ + uint8_t sum = (raw_temp >> 8) + (raw_temp & 0xff) + (raw_hum >> 8) + + (raw_hum & 0xff); + if (sum != csum) { + DEBUG("error: checksum doesn't match\n"); + return DHT_NOCSUM; + } + + /* parse the RAW values */ + DEBUG("RAW values: temp: %7i hum: %7i\n", (int)raw_temp, (int)raw_hum); + switch (dev->params.type) { + case DHT11: + dev->last_val.temperature = (int16_t)((raw_temp >> 8) * 10); + dev->last_val.humidity = (int16_t)((raw_hum >> 8) * 10); + break; + case DHT22: + dev->last_val.humidity = (int16_t)raw_hum; + /* if the high-bit is set, the value is negative */ + if (raw_temp & 0x8000) { + dev->last_val.temperature = (int16_t)((raw_temp & ~0x8000) * -1); + } + else { + dev->last_val.temperature = (int16_t)raw_temp; + } + break; + default: + return DHT_NODEV; /* this should never be reached */ + } + + /* update time of last measurement */ + dev->last_read_us = now_us; } - if (_read(&raw_temp, dev->pin, 16)) { - _reset(dev); - return DHT_TIMEOUT; + if (temp) { + *temp = dev->last_val.temperature; } - if (_read(&csum, dev->pin, 8)) { - _reset(dev); - return DHT_TIMEOUT; - } - - /* Bring device back to defined state - so we can trigger the next reading - * by pulling the data pin low again */ - _reset(dev); - - /* validate the checksum */ - sum = (raw_temp >> 8) + (raw_temp & 0xff) + (raw_hum >> 8) + (raw_hum & 0xff); - if ((sum != csum) || (csum == 0)) { - DEBUG("error: checksum invalid\n"); - return DHT_NOCSUM; - } - - /* parse the RAW values */ - DEBUG("RAW values: temp: %7i hum: %7i\n", (int)raw_temp, (int)raw_hum); - switch (dev->type) { - case DHT11: - *temp = (int16_t)((raw_temp >> 8) * 10); - *hum = (int16_t)((raw_hum >> 8) * 10); - break; - case DHT22: - *hum = (int16_t)raw_hum; - /* if the high-bit is set, the value is negative */ - if (raw_temp & 0x8000) { - *temp = (int16_t)((raw_temp & ~0x8000) * -1); - } - else { - *temp = (int16_t)raw_temp; - } - break; - default: - return DHT_NODEV; /* this should never be reached */ + if (hum) { + *hum = dev->last_val.humidity; } return DHT_OK; diff --git a/drivers/dht/dht_saul.c b/drivers/dht/dht_saul.c index c118e84427..c5ff1c2e3d 100644 --- a/drivers/dht/dht_saul.c +++ b/drivers/dht/dht_saul.c @@ -30,40 +30,25 @@ #include "saul.h" #include "dht.h" -#include "xtimer.h" -#define DHT_SAUL_HOLD_TIME (1000 * 1000U) /* 1s */ - -static int16_t temp, hum; -static uint32_t last = 0; - -static int check_and_read(const void *dev, phydat_t *res, int16_t *val, uint8_t unit) +static int read_temp(const void *dev, phydat_t *res) { - uint32_t now = xtimer_now_usec(); - - if ((now - last) > DHT_SAUL_HOLD_TIME) { - if (dht_read((const dht_t *)dev, &temp, &hum)) { - return -ECANCELED; - } - last = now; + if (dht_read((dht_t *)dev, &res->val[0], NULL)) { + return -ECANCELED; } - - res->val[0] = *val; - res->val[1] = 0; - res->val[2] = 0; - res->unit = unit; + res->unit = UNIT_TEMP_C; res->scale = -1; return 1; } -static int read_temp(const void *dev, phydat_t *res) -{ - return check_and_read(dev, res, &temp, UNIT_TEMP_C); -} - static int read_hum(const void *dev, phydat_t *res) { - return check_and_read(dev, res, &hum, UNIT_PERCENT); + if (dht_read((dht_t *)dev, NULL, &res->val[0])) { + return -ECANCELED; + } + res->unit = UNIT_PERCENT; + res->scale = -1; + return 1; } const saul_driver_t dht_temp_saul_driver = { diff --git a/drivers/include/dht.h b/drivers/include/dht.h index de08141ffb..973453c5b9 100644 --- a/drivers/include/dht.h +++ b/drivers/include/dht.h @@ -67,19 +67,24 @@ typedef enum { } dht_type_t; /** - * @brief Device descriptor for DHT sensor devices + * @brief Configuration parameters for DHT devices */ typedef struct { gpio_t pin; /**< GPIO pin of the device's data pin */ dht_type_t type; /**< type of the DHT device */ gpio_mode_t in_mode; /**< input pin configuration, with or without pull * resistor */ -} dht_t; + +} dht_params_t; /** - * @brief Configuration parameters for DHT devices + * @brief Device descriptor for DHT sensor devices */ -typedef dht_t dht_params_t; +typedef struct { + dht_params_t params; /**< Device parameters */ + dht_data_t last_val; /**< Values of the last measurement */ + uint32_t last_read_us; /**< Time of the last measurement */ +} dht_t; /** * @brief Initialize a new DHT device @@ -107,7 +112,7 @@ int dht_init(dht_t *dev, const dht_params_t *params); * @retval `DHT_TIMEOUT` Reading data timed out (check wires!) * @retval `DHT_NODEV` Unsupported device type specified */ -int dht_read(const dht_t *dev, int16_t *temp, int16_t *hum); +int dht_read(dht_t *dev, int16_t *temp, int16_t *hum); #ifdef __cplusplus }