You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

199 lines
5.0 KiB

/*
* Copyright 2015 Ludwig Knüpfer
* Copyright 2015 Christian Mehlis
*
* 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
*
* @author Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de>
* @author Christian Mehlis <mehlis@inf.fu-berlin.de>
*
* @}
*/
#include <stdint.h>
#include "xtimer.h"
#include "timex.h"
#include "periph/gpio.h"
#include "dht.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/***********************************************************************
* internal API declaration
**********************************************************************/
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);
/***********************************************************************
* 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));
}
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 */
}
}
*checksum = les_bits & 0x00000000000000FF;
*data = (les_bits >> 8) & 0x00000000FFFFFFFF;
gpio_init(dev, GPIO_DIR_OUT, GPIO_PULLUP);
gpio_set(dev);
}
/***********************************************************************
* public API implementation
**********************************************************************/
int dht_init(dht_t *dev, dht_type_t type, gpio_t gpio)
{
DEBUG("dht_init\n");
dev->gpio = gpio;
dev->type = type;
if (gpio_init(gpio, GPIO_DIR_OUT, GPIO_PULLUP) == -1) {
return -1;
}
gpio_set(gpio);
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;
/* read raw data */
dht_read_data(dev->gpio, &data, &checksum);
/* 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;
}