Contiki-NG
Loading...
Searching...
No Matches
dht11-sensor.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2021 Yago Fontoura do Rosario <yago.rosario@hotmail.com.br>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31/*---------------------------------------------------------------------------*/
32
33/**
34 * \addtogroup dht11-sensor
35 * @{
36 * \file
37 * DHT 11 sensor implementation
38 *
39 * \see https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf
40 *
41 * \author
42 * Yago Fontoura do Rosario <yago.rosario@hotmail.com.br
43 */
44
45#include "contiki.h"
46#include "dht11-sensor.h"
47#include <string.h>
48#include "dev/gpio-hal.h"
49
50/*---------------------------------------------------------------------------*/
51/**
52 * @brief GPIO High
53 *
54 */
55#define DHT11_SIGNAL_HIGH (1)
56
57/**
58 * @brief GPIO Low
59 *
60 */
61#define DHT11_SIGNAL_LOW (0)
62
63/**
64 * @brief Duration of signal start phase 1 according to data sheet
65 *
66 */
67#define DHT11_SIGNAL_START_PHASE1_DURATION (40)
68
69/**
70 * @brief Duration of signal start phase 2 according to data sheet
71 *
72 */
73#define DHT11_SIGNAL_START_PHASE2_DURATION (80)
74
75/**
76 * @brief Duration of signal start phase 3 according to data sheet
77 *
78 */
79#define DHT11_SIGNAL_START_PHASE3_DURATION (80)
80
81/**
82 * @brief Duration of signal response phase 1 according to data sheet
83 *
84 */
85#define DHT11_SIGNAL_RESPONSE_PHASE1_DURATION (50)
86
87/**
88 * @brief Duration of signal response if bit is set to 0, according to data sheet
89 *
90 */
91#define DHT11_SIGNAL_RESPONSE_BIT_0_DURATION (28)
92
93/**
94 * @brief Duration of signal response if bit is set to 1, according to data sheet
95 *
96 */
97#define DHT11_SIGNAL_RESPONSE_BIT_1_DURATION (70)
98
99/**
100 * @brief Sensor timer drift in ticks
101 *
102 * DHT uses 1us granularity and rtimer granularity is higher.
103 * So, allow the reading to drift by 1 tick
104 *
105 */
106#define DHT11_TICKS_GUARD (1)
107
108/**
109 * @brief Sensor timer drift in us from rtimer
110 *
111 * DHT uses 1us granularity and rtimer granularity is higher.
112 * So, allow the reading to drift by 1 tick in us
113 *
114 */
115#define DHT11_US_GUARD RTIMERTICKS_TO_US(1)
116
117/**
118 * @brief Number of data requests
119 *
120 */
121#define DHT11_DATA_SAMPLES (40)
122
123/**
124 * @brief Number of bytes in data
125 *
126 */
127#define DHT11_DATA_SIZE (5)
128
129/**
130 * @brief DHT11 maximum sample rate is 1 Hz (1 second)
131 *
132 */
133#define DHT11_SAMPLING_RATE_SECONDS (1)
134/*---------------------------------------------------------------------------*/
135/**
136 * @brief DHT struct
137 *
138 */
139typedef struct {
140 /**
141 * @brief GPIO Port
142 *
143 */
144 gpio_hal_port_t port;
145 /**
146 * @brief GPIO Pin
147 *
148 */
149 gpio_hal_pin_t pin;
150 /**
151 * @brief DH status
152 *
153 */
154 uint8_t status;
155 /**
156 * @brief Time of last read
157 *
158 */
159 clock_time_t last_read;
160 /**
161 * @brief Data array
162 *
163 */
164 uint8_t data[DHT11_DATA_SIZE];
165} dht_t;
166
167/**
168 * @brief DHT struct
169 *
170 */
171static dht_t dht;
172/*---------------------------------------------------------------------------*/
173static int
174dht11_humidity_integer(void)
175{
176 return dht.data[0];
177}
178/*---------------------------------------------------------------------------*/
179static int
180dht11_humidity_decimal(void)
181{
182 return dht.data[1];
183}
184/*---------------------------------------------------------------------------*/
185static int
186dht11_temperature_integer(void)
187{
188 return dht.data[2];
189}
190/*---------------------------------------------------------------------------*/
191static int
192dht11_temperature_decimal(void)
193{
194 return dht.data[3];
195}
196/*---------------------------------------------------------------------------*/
197static int8_t
198dht_signal_duration(uint8_t active, uint32_t max_duration)
199{
200 rtimer_clock_t elapsed_ticks;
201 rtimer_clock_t max_wait_ticks = US_TO_RTIMERTICKS(max_duration) + DHT11_TICKS_GUARD;
202 rtimer_clock_t start_ticks = RTIMER_NOW();
203
204 /* Wait for signal to change */
205 RTIMER_BUSYWAIT_UNTIL(gpio_hal_arch_read_pin(dht.port, dht.pin) != active, max_wait_ticks);
206
207 elapsed_ticks = RTIMER_NOW() - start_ticks;
208
209 if(elapsed_ticks > max_wait_ticks) {
210 return -1;
211 }
212
213 return RTIMERTICKS_TO_US(elapsed_ticks);
214}
215/*---------------------------------------------------------------------------*/
216static int8_t
217dht_signal_transition(uint8_t active, uint32_t max_duration)
218{
219 return dht_signal_duration(active, max_duration);
220}
221/*---------------------------------------------------------------------------*/
222static uint8_t
223dht_verify_checksum(void)
224{
225 return ((dht.data[0] + dht.data[1] + dht.data[2] + dht.data[3]) & 0xFF) == dht.data[4];
226}
227/*---------------------------------------------------------------------------*/
228static uint8_t
230{
231 uint8_t j, i;
232 /* Array to store the duration of each data signal to be calculated later */
233 int8_t data_signal_duration[DHT11_DATA_SAMPLES];
234
235 /**
236 * Data Single-bus free status is at high voltage level. When the communication
237 * between MCU and DHT11 begins, the programme of MCU will set Data Single-bus
238 * voltage level from high to low and this process must take at least 18ms to
239 * ensure DHT’s detection of MCU's signal, then MCU will pull up voltage and
240 * wait 20-40us for DHT’s response.
241 */
242 gpio_hal_arch_pin_set_output(dht.port, dht.pin);
243 gpio_hal_arch_clear_pin(dht.port, dht.pin);
244 RTIMER_BUSYWAIT(US_TO_RTIMERTICKS(18000UL));
245 gpio_hal_arch_set_pin(dht.port, dht.pin);
246 gpio_hal_arch_pin_set_input(dht.port, dht.pin);
247
248 if(dht_signal_transition(DHT11_SIGNAL_HIGH, DHT11_SIGNAL_START_PHASE1_DURATION) == -1) {
250 }
251
252 /**
253 * Once DHT detects the start signal,it will send out a low-voltage-level response
254 * signal, which lasts 80us. Then the programme of DHT sets Data Single-bus voltage
255 * level from low to high and keeps it for 80us for DHT’s preparation for sending data.
256 */
257 if(dht_signal_transition(DHT11_SIGNAL_LOW, DHT11_SIGNAL_START_PHASE2_DURATION) == -1) {
259 }
260
261 if(dht_signal_transition(DHT11_SIGNAL_HIGH, DHT11_SIGNAL_START_PHASE3_DURATION) == -1) {
263 }
264
265 for(i = 0; i < DHT11_DATA_SAMPLES; i++) {
266 /**
267 * When DHT is sending data to MCU, every bit of data begins with the 50us
268 * low-voltage-level and the length of the following high-voltage-level signal
269 * determines whether data bit is "0" or "1"
270 */
271 if(dht_signal_transition(DHT11_SIGNAL_LOW, DHT11_SIGNAL_RESPONSE_PHASE1_DURATION) == -1) {
273 }
274
275 /*
276 * Save in array and calculate later.
277 * Should not spend time calculating in the loop else the bit bang timing gets lost
278 * Use bit 0 and bit 1 duration summed up to improve timming
279 */
280 data_signal_duration[i] = dht_signal_duration(DHT11_SIGNAL_HIGH,
283 if(data_signal_duration[i] == -1) {
285 }
286 }
287
288 memset(dht.data, 0, sizeof(uint8_t) * DHT11_DATA_SIZE);
289 for(j = 0, i = 0; i < DHT11_DATA_SAMPLES; i++) {
290
291 /**
292 * 26-28us voltage-length means data "0"
293 * 70us voltage-length means 1 bit data "1"
294 */
295 if(data_signal_duration[i] >= DHT11_SIGNAL_RESPONSE_BIT_0_DURATION + DHT11_US_GUARD) {
296 dht.data[j] = (dht.data[j] << 1) | 1;
297 } else {
298 dht.data[j] = dht.data[j] << 1;
299 }
300
301 /* Next byte */
302 if(i % 8 == 7U) {
303 j++;
304 }
305 }
306
307 /* Verify checksum */
308 if(!dht_verify_checksum()) {
310 } else {
311 return DHT11_STATUS_OKAY;
312 }
313}
314/*---------------------------------------------------------------------------*/
315static int
316value(int type)
317{
318 switch(type) {
320 return dht11_humidity_integer();
322 return dht11_humidity_decimal();
324 return dht11_temperature_integer();
326 return dht11_temperature_decimal();
327 }
328
329 return 0;
330}
331/*---------------------------------------------------------------------------*/
332static int
333status(int type)
334{
335 (void)type;
336
337 return dht.status;
338}
339/*---------------------------------------------------------------------------*/
340static int
341configure(int type, int c)
342{
343 switch(type) {
345 dht.port = c;
346 break;
348 dht.pin = c;
349 break;
350 case SENSORS_HW_INIT:
351 dht.last_read = 0;
352 case SENSORS_ACTIVE:
353 if(c == 1) {
354 clock_time_t now;
355
356 now = clock_seconds();
357 if(now - dht.last_read < DHT11_SAMPLING_RATE_SECONDS) {
358 return 0;
359 }
360 dht.last_read = now;
361 dht.status = dht_read();
362 }
363 case SENSORS_READY:
364 break;
365 default:
366 return 0;
367 }
368
369 return 1;
370}
371/*---------------------------------------------------------------------------*/
372SENSORS_SENSOR(dht11_sensor, "dht11", value, configure, status);
373/*----------------------------------------------------------------------------*/
374/** @} */
DHT 11 sensor header file.
Header file for the GPIO HAL.
unsigned long clock_seconds(void)
Get the current value of the platform seconds.
Definition clock.c:130
#define DHT11_DATA_SIZE
Number of bytes in data.
#define DHT11_SIGNAL_START_PHASE1_DURATION
Duration of signal start phase 1 according to data sheet.
#define DHT11_SIGNAL_RESPONSE_BIT_1_DURATION
Duration of signal response if bit is set to 1, according to data sheet.
static uint8_t dht_read(void)
#define DHT11_SIGNAL_LOW
GPIO Low.
#define DHT11_STATUS_CHECKSUM_FAILED
DHT11 status checksum failed.
#define DHT11_CONFIGURE_GPIO_PIN
DHT11 Configuration type for GPIO Pin.
#define DHT11_SIGNAL_HIGH
GPIO High.
#define DHT11_VALUE_HUMIDITY_INTEGER
DHT11 value type for humidity integer part.
#define DHT11_SIGNAL_START_PHASE3_DURATION
Duration of signal start phase 3 according to data sheet.
#define DHT11_TICKS_GUARD
Sensor timer drift in ticks.
#define DHT11_US_GUARD
Sensor timer drift in us from rtimer.
#define DHT11_VALUE_TEMPERATURE_INTEGER
DHT11 value type for temperature integer part.
#define DHT11_SIGNAL_RESPONSE_BIT_0_DURATION
Duration of signal response if bit is set to 0, according to data sheet.
#define DHT11_DATA_SAMPLES
Number of data requests.
#define DHT11_VALUE_TEMPERATURE_DECIMAL
DHT11 value type for temperature decimal part.
#define DHT11_SIGNAL_START_PHASE2_DURATION
Duration of signal start phase 2 according to data sheet.
#define DHT11_CONFIGURE_GPIO_PORT
DHT11 Configuration type for GPIO Port.
#define DHT11_SAMPLING_RATE_SECONDS
DHT11 maximum sample rate is 1 Hz (1 second)
static dht_t dht
DHT struct.
#define DHT11_STATUS_TIMEOUT
DHT11 status timeout.
#define DHT11_STATUS_OKAY
DHT11 status okay.
#define DHT11_VALUE_HUMIDITY_DECIMAL
DHT11 value type for humidity decimal part.
#define DHT11_SIGNAL_RESPONSE_PHASE1_DURATION
Duration of signal response phase 1 according to data sheet.
uint8_t gpio_hal_port_t
A data structure that represents ports.
Definition gpio-hal.h:110
uint8_t gpio_hal_pin_t
GPIO pin number representation.
Definition gpio-hal.h:103
#define RTIMER_BUSYWAIT_UNTIL(cond, max_time)
Busy-wait until a condition for at most max_time.
Definition rtimer.h:213
#define RTIMER_BUSYWAIT(duration)
Busy-wait for a fixed duration.
Definition rtimer.h:220
#define RTIMER_NOW()
Get the current clock time.
Definition rtimer.h:187