1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-26 06:53:52 +01:00

Merge pull request #4664 from haukepetersen/opt_driver_dhtinit

drivers/dht: numerous improvements
This commit is contained in:
Peter Kietzmann 2016-02-29 16:23:31 +01:00
commit a8b6fba69c
7 changed files with 219 additions and 210 deletions

View File

@ -22,6 +22,7 @@ endif
ifneq (,$(filter dht,$(USEMODULE)))
USEMODULE += xtimer
FEATURES_REQUIRED = periph_gpio
endif
ifneq (,$(filter enc28j60,$(USEMODULE)))

View File

@ -1,6 +1,7 @@
/*
* Copyright 2015 Ludwig Knüpfer
* Copyright 2015 Christian Mehlis
* 2015 Christian Mehlis
* 2016 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -17,131 +18,72 @@
*
* @author Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de>
* @author Christian Mehlis <mehlis@inf.fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <stdint.h>
#include <string.h>
#include "log.h"
#include "xtimer.h"
#include "timex.h"
#include "periph/gpio.h"
#include "dht.h"
#include "dht_params.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/***********************************************************************
* internal API declaration
**********************************************************************/
#define PULSE_WIDTH_THRESHOLD (40U)
static void dht_read_data(gpio_t dev, uint32_t *data, uint8_t *checksum);
static int dht_test_checksum(uint32_t data, uint8_t checksum);
void dht_parse_11(dht_data_t *data, float *outhum, float *outtemp);
void dht_parse_22(dht_data_t *data, float *outhum, float *outtemp);
/**
* @brief Allocation of memory for device descriptors
*/
dht_t dht_devs[DHT_NUMOF];
/***********************************************************************
* internal API implementation
**********************************************************************/
void dht_parse_11(dht_data_t *data, float *outhum, float *outtemp)
static uint16_t read(gpio_t pin, int bits)
{
*outhum = data->humidity >> 8;
*outtemp = data->temperature >> 8;
}
uint32_t start, end;
uint16_t res = 0;
void dht_parse_22(dht_data_t *data, float *outhum, float *outtemp)
{
*outhum = data->humidity / 10;
/* the highest bit indicates a negative value */
if (data->temperature & 0x8000) {
*outtemp = (data->temperature & 0x7FFF) / -10;
}
else {
*outtemp = data->temperature / 10;
}
}
static int dht_test_checksum(uint32_t data, uint8_t checksum)
{
uint8_t sum;
sum = (data >> 0) & 0x000000FF;
sum += (data >> 8) & 0x000000FF;
sum += (data >> 16) & 0x000000FF;
sum += (data >> 24) & 0x000000FF;
return ((checksum == sum) && (checksum != 0));
}
static void dht_read_data(gpio_t dev, uint32_t *data, uint8_t *checksum)
{
/* send init signal to device */
gpio_clear(dev);
xtimer_usleep(20 * MS_IN_USEC);
gpio_set(dev);
xtimer_usleep(40);
/* sync on device */
gpio_init(dev, GPIO_DIR_IN, GPIO_PULLUP);
while (!gpio_read(dev)) ;
while (gpio_read(dev)) ;
/*
* data is read in sequentially, highest bit first:
* 40 .. 24 23 .. 8 7 .. 0
* [humidity][temperature][checksum]
*/
/* read all the bits */
uint64_t les_bits = 0x00000000000000;
for (int c = 0; c < 40; c++) {
les_bits <<= 1; /* this is a nop in the first iteration, but
we must not shift the last bit */
/* wait for start of bit */
while (!gpio_read(dev)) ;
unsigned long start = xtimer_now();
/* wait for end of bit */
while (gpio_read(dev)) ;
/* calculate bit length (long 1, short 0) */
unsigned long stop = xtimer_now();
/* compensate for overflow if needed */
if (stop < start) {
stop = UINT32_MAX - stop;
start = 0;
}
if ((stop - start) > 40) {
/* read 1, set bit */
les_bits |= 0x0000000000000001;
}
else {
/* read 0, don't set bit */
for (int i = 0; i < bits; i++) {
res <<= 1;
/* measure the length between the next rising and falling flanks (the
* time the pin is high - smoke up :-) */
while (!gpio_read(pin));
start = xtimer_now();
while (gpio_read(pin));
end = xtimer_now();
/* if the high phase was more than 40us, we got a 1 */
if ((end - start) > PULSE_WIDTH_THRESHOLD) {
res |= 0x0001;
}
}
*checksum = les_bits & 0x00000000000000FF;
*data = (les_bits >> 8) & 0x00000000FFFFFFFF;
gpio_init(dev, GPIO_DIR_OUT, GPIO_PULLUP);
gpio_set(dev);
return res;
}
/***********************************************************************
* public API implementation
**********************************************************************/
void dht_auto_init(void)
{
for (unsigned i = 0; i < DHT_NUMOF; i++) {
if (dht_init(&dht_devs[i], &dht_params[i]) < 0) {
LOG_ERROR("Unable to initialize DHT sensor #%i\n", i);
}
}
}
int dht_init(dht_t *dev, dht_type_t type, gpio_t gpio)
int dht_init(dht_t *dev, const dht_params_t *params)
{
DEBUG("dht_init\n");
dev->gpio = gpio;
dev->type = type;
memcpy(dev, params, sizeof(dht_t));
if (gpio_init(gpio, GPIO_DIR_OUT, GPIO_PULLUP) == -1) {
if (gpio_init(dev->pin, GPIO_DIR_OUT, dev->pull) == -1) {
return -1;
}
gpio_set(gpio);
gpio_set(dev->pin);
xtimer_usleep(2000 * MS_IN_USEC);
@ -149,51 +91,64 @@ int dht_init(dht_t *dev, dht_type_t type, gpio_t gpio)
return 0;
}
int dht_read_raw(dht_t *dev, dht_data_t *outdata)
int dht_read(dht_t *dev, int16_t *temp, int16_t *hum)
{
uint32_t data;
uint8_t checksum;
uint8_t csum, sum;
uint16_t raw_hum, raw_temp;
/* read raw data */
dht_read_data(dev->gpio, &data, &checksum);
/* send init signal to device */
gpio_clear(dev->pin);
xtimer_usleep(20 * MS_IN_USEC);
gpio_set(dev->pin);
xtimer_usleep(40);
/* check checksum */
int ret = dht_test_checksum(data, checksum);
if (!ret) {
DEBUG("checksum fail\n");
}
/* sync on device */
gpio_init(dev->pin, GPIO_DIR_IN, dev->pull);
while (!gpio_read(dev->pin)) ;
while (gpio_read(dev->pin)) ;
outdata->humidity = data >> 16;
outdata->temperature = data & 0x0000FFFF;
/*
* data is read in sequentially, highest bit first:
* 40 .. 24 23 .. 8 7 .. 0
* [humidity][temperature][checksum]
*/
return (ret - 1); /* take that logic! */
}
/* read the humidity, temperature, and checksum bits */
raw_hum = read(dev->pin, 16);
raw_temp = read(dev->pin, 16);
csum = (uint8_t)read(dev->pin, 8);
void dht_parse(dht_t *dev, dht_data_t *data, float *outrelhum, float *outtemp)
{
switch (dev->type) {
case (DHT11):
dht_parse_11(data, outrelhum, outtemp);
break;
/* set pin high again - so we can trigger the next reading by pulling it low
* again */
gpio_init(dev->pin, GPIO_DIR_OUT, dev->pull);
gpio_set(dev->pin);
case DHT22:
dht_parse_22(data, outrelhum, outtemp);
break;
default:
DEBUG("unknown DHT type\n");
}
}
int dht_read(dht_t *dev, float *outrelhum, float *outtemp)
{
/* read data, fail on error */
dht_data_t data;
if (dht_read_raw(dev, &data) == -1) {
/* 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 -1;
}
dht_parse(dev, &data, outrelhum, outtemp);
/* 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;
}
default:
return -2;
}
return 0;
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2016 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_dht
*
* @{
* @file
* @brief Default configuration for DHT devices
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef DHT_PARAMS_H
#define DHT_PARAMS_H
#include "board.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Set default configuration parameters for the DHT devices
* @{
*/
#ifndef DHT_PARAM_PIN
#define DHT_PARAM_PIN (GPIO_PIN(0, 0))
#endif
#ifndef DHT_PARAM_TYPE
#define DHT_PARAM_TYPE (DHT11)
#endif
#ifndef DHT_PARAM_PULL
#define DHT_PARAM_PULL (GPIO_PULLUP)
#endif
#define DHT_PARAMS_DEFAULT {.pin = DHT_PARAM_PIN, \
.type = DHT_PARAM_TYPE, \
.pull = DHT_PARAM_PULL}
/**@}*/
/**
* @brief Configure DHT devices
*/
static const dht_params_t dht_params[] =
{
#ifdef DHT_PARAMS_BOARD
DHT_PARAMS_BOARD,
#else
DHT_PARAMS_DEFAULT,
#endif
};
/**
* @brief Get the number of configured DHT devices
*/
#define DHT_NUMOF (sizeof(dht_params) / sizeof(dht_params[0]))
#ifdef __cplusplus
}
#endif
#endif /* DHT_PARAMS_H */
/** @} */

View File

@ -1,5 +1,7 @@
/*
* Copyright 2015 Ludwig Knüpfer, Christian Mehlis
* Copyright 2015 Ludwig Knüpfer,
* 2015 Christian Mehlis
* 2016 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -20,6 +22,7 @@
*
* @author Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de
* @author Christian Mehlis <mehlis@inf.fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef DHT_H
@ -54,57 +57,48 @@ typedef enum {
* @brief device descriptor for DHT sensor devices
*/
typedef struct {
gpio_t gpio; /**< GPIO pin of the device's data pin */
gpio_t pin; /**< GPIO pin of the device's data pin */
dht_type_t type; /**< type of the DHT device */
gpio_pp_t pull; /**< internal pull resistor configuration, set to
* GPIO_NOPULL when using an external pull-up */
} dht_t;
/**
* @brief configuration parameters for DHT devices
*/
typedef dht_t dht_params_t;
/**
* @brief auto-initialize all configured DHT devices
*/
void dht_auto_init(void);
/**
* @brief initialize a new DHT device
*
* @param[in] dev device descriptor of a DHT device
* @param[in] type type of the DHT device
* @param[in] gpio GPIO pin the device's data pin is connected to
* @param[out] dev device descriptor of a DHT device
* @param[in] params configuration parameters
*
* @return 0 on success
* @return -1 on error
*/
int dht_init(dht_t *dev, dht_type_t type, gpio_t gpio);
int dht_init(dht_t *dev, const dht_params_t *params);
/**
* @brief read sensor data from device
/**
* @brief get a new temperature and humidity value from the device
*
* @note if reading fails or checksum is invalid, no new values will be
* written into the result values
*
* @param[in] dev device descriptor of a DHT device
* @param[out] relhum pointer to relative humidity in g/m^3
* @param[out] temp pointer to temperature in degrees Celsius
*
* @return 0 on success
* @return -1 on error
*/
int dht_read(dht_t *dev, float *relhum, float *temp);
/**
* @brief read sensor data from device
*
* @note When reading fails and the function indicates an error,
* data will contain garbage.
*
* @param[in] dev device descriptor of a DHT device
* @param[in] data pointer to DHT data object
* @param[out] temp temperature value [in °C * 10^-1]
* @param[out] hum relative humidity value [in percent * 10^-1]
*
* @return 0 on success
* @return -1 on checksum error
* @return -2 on parsing error
*/
int dht_read_raw(dht_t *dev, dht_data_t *data);
/**
* @brief parse raw sensor data into relative humidity and Celsius
*
* @param[in] dev device descriptor of a DHT device
* @param[in] data sensor data
* @param[out] relhum pointer to relative humidity in g/m^3
* @param[out] temp pointer to temperature in degrees Celsius
*/
void dht_parse(dht_t *dev, dht_data_t *data, float *relhum, float *temp);
int dht_read(dht_t *dev, int16_t *temp, int16_t *hum);
#ifdef __cplusplus
}

View File

@ -138,6 +138,11 @@ void auto_init(void)
DEBUG("Auto init UDP module.\n");
gnrc_udp_init();
#endif
#ifdef MODULE_DHT
DEBUG("Auto init DHT devices.\n");
extern void dht_auto_init(void);
dht_auto_init();
#endif
/* initialize network devices */

View File

@ -1,22 +1,7 @@
APPLICATION = driver_dht
include ../Makefile.tests_common
FEATURES_REQUIRED = periph_gpio
USEMODULE += dht
USEMODULE += xtimer
# define parameters for selected boards
ifneq (,$(filter stm32f4discovery,$(BOARD)))
DHT_GPIO ?= GPIO_PIN\(4,3\)
endif
# set default device parameters in case they are undefined
DHT_GPIO ?= GPIO_PIN\(0,0\)
DHT_TYPE ?= DHT11
# export parameters
CFLAGS += -DDHT_TYPE=$(DHT_TYPE)
CFLAGS += -DDHT_GPIO=$(DHT_GPIO)
include $(RIOTBASE)/Makefile.include

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2015 Ludwig Knüpfer, Christian Mehlis
* 2016 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -15,50 +16,49 @@
*
* @author Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de>
* @author Christian Mehlis <mehlis@inf.fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#ifndef DHT_TYPE
#error "DHT_TYPE not defined"
#endif
#ifndef DHT_GPIO
#error "DHT_GPIO not defined"
#endif
#include <stdio.h>
#include "xtimer.h"
#include "dht.h"
#include "dht_params.h"
extern dht_t dht_devs[];
int main(void)
{
dht_t dev;
puts("DHT temperature and humidity sensor test application\n");
printf("Initializing DHT sensor at GPIO_%ld... ", (long)DHT_GPIO);
if (dht_init(&dev, DHT_TYPE, DHT_GPIO) == 0) {
puts("[OK]\n");
}
else {
puts("[Failed]");
return 1;
}
dht_data_t data;
float temp, hum;
/* periodically read temp and humidity values */
while (1) {
for (unsigned i = 0; i < DHT_NUMOF; i++) {
dht_t *dev = &dht_devs[i];
int16_t temp, hum;
int16_t dec_temp, dec_hum, int_temp, int_hum;
if (dht_read_raw(&dev, &data) == -1) {
puts("error reading data");
if (dht_read(dev, &temp, &hum) == -1) {
puts("error reading data");
continue;
}
/* split up values into integral and fractional parts for nicer
* printing
* TODO: this should be done in some kind of library... */
int_temp = temp / 10;
dec_temp = temp - (int_temp * 10);
int_hum = hum / 10;
dec_hum = hum - (int_hum * 10);
printf("DHT device #%i - ", i);
printf("temp: %i.%i°C, ", int_temp, dec_temp);
printf("relative humidity: %i.%i%%\n", int_hum, dec_hum);
xtimer_usleep(2000 * MS_IN_USEC);
}
dht_parse(&dev, &data, &hum, &temp);
printf("raw relative humidity: %i\nraw temperature: %i C\n", data.humidity, data.temperature);
printf("relative humidity: %i\ntemperature: %i C\n", (int) hum, (int) temp);
xtimer_usleep(2000 * MS_IN_USEC);
}
return 0;