2015-05-15 22:10:27 +02:00
|
|
|
/*
|
2015-09-27 18:58:30 +02:00
|
|
|
* Copyright 2015 Ludwig Knüpfer
|
2016-01-21 15:24:57 +01:00
|
|
|
* 2015 Christian Mehlis
|
|
|
|
* 2016 Freie Universität Berlin
|
2015-05-15 22:10:27 +02:00
|
|
|
*
|
|
|
|
* 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 driver_dht
|
|
|
|
* @{
|
|
|
|
*
|
|
|
|
* @file
|
|
|
|
* @brief Device driver implementation for the DHT 11 and 22
|
|
|
|
* temperature and humidity sensor
|
|
|
|
*
|
2015-09-27 18:58:30 +02:00
|
|
|
* @author Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de>
|
2015-05-15 22:10:27 +02:00
|
|
|
* @author Christian Mehlis <mehlis@inf.fu-berlin.de>
|
2016-01-21 15:24:57 +01:00
|
|
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
2015-05-15 22:10:27 +02:00
|
|
|
*
|
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdint.h>
|
2016-01-21 15:24:57 +01:00
|
|
|
#include <string.h>
|
2015-05-15 22:10:27 +02:00
|
|
|
|
2016-01-21 15:24:57 +01:00
|
|
|
#include "log.h"
|
2015-07-30 15:58:43 +02:00
|
|
|
#include "xtimer.h"
|
2015-05-15 22:10:27 +02:00
|
|
|
#include "timex.h"
|
|
|
|
#include "periph/gpio.h"
|
|
|
|
|
|
|
|
#include "dht.h"
|
2016-01-21 15:24:57 +01:00
|
|
|
#include "dht_params.h"
|
2015-05-15 22:10:27 +02:00
|
|
|
|
|
|
|
#define ENABLE_DEBUG (0)
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* internal API declaration
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* internal API implementation
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
void dht_parse_11(dht_data_t *data, float *outhum, float *outtemp)
|
|
|
|
{
|
|
|
|
*outhum = data->humidity >> 8;
|
|
|
|
*outtemp = data->temperature >> 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2016-01-21 16:22:26 +01:00
|
|
|
/***********************************************************************
|
|
|
|
* public API implementation
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
dht_t dht_devs[DHT_NUMOF];
|
|
|
|
|
|
|
|
void dht_auto_init(void)
|
2015-05-15 22:10:27 +02:00
|
|
|
{
|
2016-01-21 16:22:26 +01:00
|
|
|
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, const dht_params_t *params)
|
|
|
|
{
|
|
|
|
DEBUG("dht_init\n");
|
|
|
|
|
|
|
|
memcpy(dev, params, sizeof(dht_t));
|
|
|
|
|
|
|
|
if (gpio_init(dev->pin, GPIO_DIR_OUT, dev->pull) == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
gpio_set(dev->pin);
|
|
|
|
|
|
|
|
xtimer_usleep(2000 * MS_IN_USEC);
|
|
|
|
|
|
|
|
DEBUG("dht_init: success\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int dht_read_raw(dht_t *dev, dht_data_t *outdata)
|
|
|
|
{
|
|
|
|
uint32_t data;
|
|
|
|
uint8_t checksum;
|
|
|
|
|
2015-05-15 22:10:27 +02:00
|
|
|
/* send init signal to device */
|
2016-01-21 16:22:26 +01:00
|
|
|
gpio_clear(dev->pin);
|
2015-07-30 15:58:43 +02:00
|
|
|
xtimer_usleep(20 * MS_IN_USEC);
|
2016-01-21 16:22:26 +01:00
|
|
|
gpio_set(dev->pin);
|
2015-07-30 15:58:43 +02:00
|
|
|
xtimer_usleep(40);
|
2015-05-15 22:10:27 +02:00
|
|
|
|
|
|
|
/* sync on device */
|
2016-01-21 16:22:26 +01:00
|
|
|
gpio_init(dev->pin, GPIO_DIR_IN, dev->pull);
|
|
|
|
while (!gpio_read(dev->pin)) ;
|
|
|
|
while (gpio_read(dev->pin)) ;
|
2015-05-15 22:10:27 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 */
|
2016-01-21 16:22:26 +01:00
|
|
|
while (!gpio_read(dev->pin)) ;
|
2015-07-30 15:58:43 +02:00
|
|
|
unsigned long start = xtimer_now();
|
2015-05-15 22:10:27 +02:00
|
|
|
/* wait for end of bit */
|
2016-01-21 16:22:26 +01:00
|
|
|
while (gpio_read(dev->pin)) ;
|
2015-05-15 22:10:27 +02:00
|
|
|
/* calculate bit length (long 1, short 0) */
|
2015-07-30 15:58:43 +02:00
|
|
|
unsigned long stop = xtimer_now();
|
2015-05-15 22:10:27 +02:00
|
|
|
/* compensate for overflow if needed */
|
|
|
|
if (stop < start) {
|
2015-07-30 15:58:43 +02:00
|
|
|
stop = UINT32_MAX - stop;
|
2015-05-15 22:10:27 +02:00
|
|
|
start = 0;
|
|
|
|
}
|
|
|
|
if ((stop - start) > 40) {
|
|
|
|
/* read 1, set bit */
|
|
|
|
les_bits |= 0x0000000000000001;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* read 0, don't set bit */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-21 16:22:26 +01:00
|
|
|
checksum = les_bits & 0x00000000000000FF;
|
|
|
|
data = (les_bits >> 8) & 0x00000000FFFFFFFF;
|
2015-05-15 22:10:27 +02:00
|
|
|
|
2016-01-21 16:22:26 +01:00
|
|
|
gpio_init(dev->pin, GPIO_DIR_OUT, dev->pull);
|
2016-01-21 15:24:57 +01:00
|
|
|
gpio_set(dev->pin);
|
2015-05-15 22:10:27 +02:00
|
|
|
|
|
|
|
/* check checksum */
|
|
|
|
int ret = dht_test_checksum(data, checksum);
|
|
|
|
if (!ret) {
|
|
|
|
DEBUG("checksum fail\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
outdata->humidity = data >> 16;
|
|
|
|
outdata->temperature = data & 0x0000FFFF;
|
|
|
|
|
|
|
|
return (ret - 1); /* take that logic! */
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
dht_parse(dev, &data, outrelhum, outtemp);
|
|
|
|
return 0;
|
|
|
|
}
|