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:
commit
a8b6fba69c
@ -22,6 +22,7 @@ endif
|
||||
|
||||
ifneq (,$(filter dht,$(USEMODULE)))
|
||||
USEMODULE += xtimer
|
||||
FEATURES_REQUIRED = periph_gpio
|
||||
endif
|
||||
|
||||
ifneq (,$(filter enc28j60,$(USEMODULE)))
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
69
drivers/dht/include/dht_params.h
Normal file
69
drivers/dht/include/dht_params.h
Normal 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 */
|
||||
/** @} */
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user