Contiki-NG
dht22.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016, Zolertia - http://www.zolertia.com
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  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 /*---------------------------------------------------------------------------*/
31 /**
32  * \addtogroup zoul-dht22
33  * @{
34  *
35  * \file
36  * Driver for the DHT22 temperature and humidity sensor
37  */
38 /*---------------------------------------------------------------------------*/
39 #include "contiki.h"
40 #include "dht22.h"
41 #include "dev/gpio.h"
42 #include "lib/sensors.h"
43 #include "dev/ioc.h"
44 #include "dev/watchdog.h"
45 #include <stdio.h>
46 /*---------------------------------------------------------------------------*/
47 #define DEBUG 0
48 #if DEBUG
49 #define PRINTF(...) printf(__VA_ARGS__)
50 #else
51 #define PRINTF(...)
52 #endif
53 /*---------------------------------------------------------------------------*/
54 #define DHT22_PORT_BASE GPIO_PORT_TO_BASE(DHT22_PORT)
55 #define DHT22_PIN_MASK GPIO_PIN_MASK(DHT22_PIN)
56 /*---------------------------------------------------------------------------*/
57 static uint8_t enabled;
58 static uint8_t busy;
59 static uint8_t dht22_data[DHT22_BUFFER];
60 /*---------------------------------------------------------------------------*/
61 static int
62 dht22_read(void)
63 {
64  uint8_t i;
65  uint8_t j = 0;
66  uint8_t last_state = 0xFF;
67  uint8_t counter = 0;
68  uint8_t checksum = 0;
69 
70  if(enabled) {
71  /* Exit low power mode and initialize variables */
72  GPIO_SET_OUTPUT(DHT22_PORT_BASE, DHT22_PIN_MASK);
73  GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
75  memset(dht22_data, 0, DHT22_BUFFER);
76 
77  /* Initialization sequence */
78  GPIO_CLR_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
80  GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
82 
83  /* Prepare to read, DHT22 should keep line low 80us, then 80us high.
84  * The ready-to-send-bit condition is the line kept low for 50us, then if
85  * the line is high between 24-25us the bit sent will be "0" (zero), else
86  * if the line is high between 70-74us the bit sent will be "1" (one).
87  */
88  GPIO_SET_INPUT(DHT22_PORT_BASE, DHT22_PIN_MASK);
89 
90  for(i = 0; i < DHT22_MAX_TIMMING; i++) {
91  counter = 0;
92  while(GPIO_READ_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK) == last_state) {
93  counter++;
95 
96  /* Exit if not responsive */
97  if(counter == 0xFF) {
98  break;
99  }
100  }
101 
102  last_state = GPIO_READ_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
103 
104  /* Double check for stray sensor */
105  if(counter == 0xFF) {
106  break;
107  }
108 
109  /* Ignore the first 3 transitions (the 80us x 2 start condition plus the
110  * first ready-to-send-bit state), and discard ready-to-send-bit counts
111  */
112  if((i >= 4) && ((i % 2) == 0)) {
113  dht22_data[j / 8] <<= 1;
114  if(counter > DHT22_COUNT) {
115  dht22_data[j / 8] |= 1;
116  }
117  j++;
118  }
119  }
120 
121  for(i = 0; i < DHT22_BUFFER; i++) {
122  PRINTF("DHT22: (%u) %u\n", i, dht22_data[i]);
123  }
124 
125  /* If we have 5 bytes (40 bits), wrap-up and end */
126  if(j >= 40) {
127  /* The first 2 bytes are humidity values, the next 2 are temperature, the
128  * final byte is the checksum
129  */
130  checksum = dht22_data[0] + dht22_data[1] + dht22_data[2] + dht22_data[3];
131  checksum &= 0xFF;
132  if(dht22_data[4] == checksum) {
133  GPIO_SET_INPUT(DHT22_PORT_BASE, DHT22_PIN_MASK);
134  GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
135  return DHT22_SUCCESS;
136  }
137  PRINTF("DHT22: bad checksum\n");
138  }
139  }
140  return DHT22_ERROR;
141 }
142 /*---------------------------------------------------------------------------*/
143 static uint16_t
144 dht22_humidity(void)
145 {
146  uint16_t res;
147  res = dht22_data[0];
148  res *= 256;
149  res += dht22_data[1];
150  busy = 0;
151  return res;
152 }
153 /*---------------------------------------------------------------------------*/
154 static uint16_t
155 dht22_temperature(void)
156 {
157  uint16_t res;
158  res = dht22_data[2] & 0x7F;
159  res *= 256;
160  res += dht22_data[3];
161  busy = 0;
162  return res;
163 }
164 /*---------------------------------------------------------------------------*/
165 static int
166 value(int type)
167 {
168  if((type != DHT22_READ_HUM) && (type != DHT22_READ_TEMP) &&
169  (type != DHT22_READ_ALL)) {
170  PRINTF("DHT22: Invalid type %u\n", type);
171  return DHT22_ERROR;
172  }
173 
174  if(busy) {
175  PRINTF("DHT22: ongoing operation, wait\n");
176  return DHT22_BUSY;
177  }
178 
179  busy = 1;
180 
181  if(dht22_read() != DHT22_SUCCESS) {
182  PRINTF("DHT22: Fail to read sensor\n");
183  GPIO_SET_INPUT(DHT22_PORT_BASE, DHT22_PIN_MASK);
184  GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
185  busy = 0;
186  return DHT22_ERROR;
187  }
188 
189  switch(type) {
190  case DHT22_READ_HUM:
191  return dht22_humidity();
192  case DHT22_READ_TEMP:
193  return dht22_temperature();
194  case DHT22_READ_ALL:
195  return DHT22_SUCCESS;
196  default:
197  return DHT22_ERROR;
198  }
199 }
200 /*---------------------------------------------------------------------------*/
201 int16_t
202 dht22_read_all(int16_t *temperature, int16_t *humidity)
203 {
204  if((temperature == NULL) || (humidity == NULL)) {
205  PRINTF("DHT22: Invalid arguments\n");
206  return DHT22_ERROR;
207  }
208 
209  if(value(DHT22_READ_ALL) != DHT22_ERROR) {
210  *temperature = dht22_temperature();
211  *humidity = dht22_humidity();
212  return DHT22_SUCCESS;
213  }
214 
215  /* Already cleaned-up in the value() function */
216  return DHT22_ERROR;
217 }
218 /*---------------------------------------------------------------------------*/
219 static int
220 configure(int type, int value)
221 {
222  if(type != SENSORS_ACTIVE) {
223  return DHT22_ERROR;
224  }
225 
226  GPIO_SOFTWARE_CONTROL(DHT22_PORT_BASE, DHT22_PIN_MASK);
227  GPIO_SET_INPUT(DHT22_PORT_BASE, DHT22_PIN_MASK);
228  ioc_set_over(DHT22_PORT, DHT22_PIN, IOC_OVERRIDE_OE);
229  GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
230 
231  /* Restart flag */
232  busy = 0;
233 
234  if(value) {
235  enabled = 1;
236  return DHT22_SUCCESS;
237  }
238 
239  enabled = 0;
240  return DHT22_SUCCESS;
241 }
242 /*---------------------------------------------------------------------------*/
243 SENSORS_SENSOR(dht22, DHT22_SENSOR, value, configure, NULL);
244 /*---------------------------------------------------------------------------*/
245 /** @} */
#define GPIO_SET_PIN(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE high.
Definition: gpio.h:106
#define DHT22_START_TIME
20 ms
Definition: dht22.h:94
Header file with register and macro declarations for the cc2538 GPIO module.
#define GPIO_CLR_PIN(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE low.
Definition: gpio.h:113
Header file with declarations for the I/O Control module.
void clock_delay_usec(uint16_t dt)
Delay a given number of microseconds.
Definition: clock.c:150
#define DHT22_READING_DELAY
1 us
Definition: dht22.h:92
#define DHT22_AWAKE_TIME
250 ms
Definition: dht22.h:95
#define DHT22_READY_TIME
40 us
Definition: dht22.h:93
#define GPIO_READ_PIN(PORT_BASE, PIN_MASK)
Read pins with PIN_MASK of port with PORT_BASE.
Definition: gpio.h:147
#define DHT22_MAX_TIMMING
Maximum ticks in a single operation.
Definition: dht22.h:91
#define GPIO_SOFTWARE_CONTROL(PORT_BASE, PIN_MASK)
Configure the pin to be software controlled with PIN_MASK of port with PORT_BASE. ...
Definition: gpio.h:258
#define DHT22_COUNT
Minimum ticks to detect a "1" bit.
Definition: dht22.h:90
void ioc_set_over(uint8_t port, uint8_t pin, uint8_t over)
Set Port:Pin override function.
Definition: ioc.c:54
#define GPIO_SET_INPUT(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to input.
Definition: gpio.h:78
#define GPIO_SET_OUTPUT(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to output.
Definition: gpio.h:85
#define IOC_OVERRIDE_OE
Output Enable.
Definition: ioc.h:222
Header file for the DHT22 temperature and humidity sensor.
#define DHT22_BUFFER
Buffer to store the samples.
Definition: dht22.h:89
#define RTIMER_BUSYWAIT(duration)
Busy-wait for a fixed duration.
Definition: rtimer.h:218