dht.c
3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
* Copyright 2015 Ludwig Knüpfer
* 2015 Christian Mehlis
* 2016-2017 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 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>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <stdint.h>
#include <string.h>
#include "log.h"
#include "assert.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"
#define PULSE_WIDTH_THRESHOLD (40U)
static uint16_t read(gpio_t pin, int bits)
{
uint16_t res = 0;
for (int i = 0; i < bits; i++) {
uint32_t start, end;
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_usec();
while (gpio_read(pin)) {}
end = xtimer_now_usec();
/* if the high phase was more than 40us, we got a 1 */
if ((end - start) > PULSE_WIDTH_THRESHOLD) {
res |= 0x0001;
}
}
return res;
}
int dht_init(dht_t *dev, const dht_params_t *params)
{
DEBUG("dht_init\n");
/* check parameters and configuration */
assert(dev && params &&
((dev->type == DHT11) || (dev->type == DHT22) || (dev->type == DHT21)));
memcpy(dev, params, sizeof(dht_t));
gpio_init(dev->pin, GPIO_OUT);
gpio_set(dev->pin);
xtimer_usleep(2000 * US_PER_MS);
DEBUG("dht_init: success\n");
return DHT_OK;
}
int dht_read(const dht_t *dev, int16_t *temp, int16_t *hum)
{
uint8_t csum, sum;
uint16_t raw_hum, raw_temp;
assert(dev && temp && hum);
/* send init signal to device */
gpio_clear(dev->pin);
xtimer_usleep(20 * US_PER_MS);
gpio_set(dev->pin);
xtimer_usleep(40);
/* sync on device */
gpio_init(dev->pin, dev->in_mode);
while (!gpio_read(dev->pin)) {}
while (gpio_read(dev->pin)) {}
/*
* data is read in sequentially, highest bit first:
* 40 .. 24 23 .. 8 7 .. 0
* [humidity][temperature][checksum]
*/
/* 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);
/* set pin high again - so we can trigger the next reading by pulling it low
* again */
gpio_init(dev->pin, GPIO_OUT);
gpio_set(dev->pin);
/* 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 */
}
return DHT_OK;
}