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 BUSYWAIT_UNTIL(max_time) \
55  do { \
56  rtimer_clock_t t0; \
57  t0 = RTIMER_NOW(); \
58  while(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + (max_time))) { \
59  watchdog_periodic(); \
60  } \
61  } while(0)
62 /*---------------------------------------------------------------------------*/
63 #define DHT22_PORT_BASE GPIO_PORT_TO_BASE(DHT22_PORT)
64 #define DHT22_PIN_MASK GPIO_PIN_MASK(DHT22_PIN)
65 /*---------------------------------------------------------------------------*/
66 static uint8_t enabled;
67 static uint8_t busy;
68 static uint8_t dht22_data[DHT22_BUFFER];
69 /*---------------------------------------------------------------------------*/
70 static int
71 dht22_read(void)
72 {
73  uint8_t i;
74  uint8_t j = 0;
75  uint8_t last_state = 0xFF;
76  uint8_t counter = 0;
77  uint8_t checksum = 0;
78 
79  if(enabled) {
80  /* Exit low power mode and initialize variables */
81  GPIO_SET_OUTPUT(DHT22_PORT_BASE, DHT22_PIN_MASK);
82  GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
83  BUSYWAIT_UNTIL(DHT22_AWAKE_TIME);
84  memset(dht22_data, 0, DHT22_BUFFER);
85 
86  /* Initialization sequence */
87  GPIO_CLR_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
88  BUSYWAIT_UNTIL(DHT22_START_TIME);
89  GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
91 
92  /* Prepare to read, DHT22 should keep line low 80us, then 80us high.
93  * The ready-to-send-bit condition is the line kept low for 50us, then if
94  * the line is high between 24-25us the bit sent will be "0" (zero), else
95  * if the line is high between 70-74us the bit sent will be "1" (one).
96  */
97  GPIO_SET_INPUT(DHT22_PORT_BASE, DHT22_PIN_MASK);
98 
99  for(i = 0; i < DHT22_MAX_TIMMING; i++) {
100  counter = 0;
101  while(GPIO_READ_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK) == last_state) {
102  counter++;
104 
105  /* Exit if not responsive */
106  if(counter == 0xFF) {
107  break;
108  }
109  }
110 
111  last_state = GPIO_READ_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
112 
113  /* Double check for stray sensor */
114  if(counter == 0xFF) {
115  break;
116  }
117 
118  /* Ignore the first 3 transitions (the 80us x 2 start condition plus the
119  * first ready-to-send-bit state), and discard ready-to-send-bit counts
120  */
121  if((i >= 4) && ((i % 2) == 0)) {
122  dht22_data[j / 8] <<= 1;
123  if(counter > DHT22_COUNT) {
124  dht22_data[j / 8] |= 1;
125  }
126  j++;
127  }
128  }
129 
130  for(i = 0; i < DHT22_BUFFER; i++) {
131  PRINTF("DHT22: (%u) %u\n", i, dht22_data[i]);
132  }
133 
134  /* If we have 5 bytes (40 bits), wrap-up and end */
135  if(j >= 40) {
136  /* The first 2 bytes are humidity values, the next 2 are temperature, the
137  * final byte is the checksum
138  */
139  checksum = dht22_data[0] + dht22_data[1] + dht22_data[2] + dht22_data[3];
140  checksum &= 0xFF;
141  if(dht22_data[4] == checksum) {
142  GPIO_SET_INPUT(DHT22_PORT_BASE, DHT22_PIN_MASK);
143  GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
144  return DHT22_SUCCESS;
145  }
146  PRINTF("DHT22: bad checksum\n");
147  }
148  }
149  return DHT22_ERROR;
150 }
151 /*---------------------------------------------------------------------------*/
152 static uint16_t
153 dht22_humidity(void)
154 {
155  uint16_t res;
156  res = dht22_data[0];
157  res *= 256;
158  res += dht22_data[1];
159  busy = 0;
160  return res;
161 }
162 /*---------------------------------------------------------------------------*/
163 static uint16_t
164 dht22_temperature(void)
165 {
166  uint16_t res;
167  res = dht22_data[2] & 0x7F;
168  res *= 256;
169  res += dht22_data[3];
170  busy = 0;
171  return res;
172 }
173 /*---------------------------------------------------------------------------*/
174 static int
175 value(int type)
176 {
177  if((type != DHT22_READ_HUM) && (type != DHT22_READ_TEMP) &&
178  (type != DHT22_READ_ALL)) {
179  PRINTF("DHT22: Invalid type %u\n", type);
180  return DHT22_ERROR;
181  }
182 
183  if(busy) {
184  PRINTF("DHT22: ongoing operation, wait\n");
185  return DHT22_BUSY;
186  }
187 
188  busy = 1;
189 
190  if(dht22_read() != DHT22_SUCCESS) {
191  PRINTF("DHT22: Fail to read sensor\n");
192  GPIO_SET_INPUT(DHT22_PORT_BASE, DHT22_PIN_MASK);
193  GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
194  busy = 0;
195  return DHT22_ERROR;
196  }
197 
198  switch(type) {
199  case DHT22_READ_HUM:
200  return dht22_humidity();
201  case DHT22_READ_TEMP:
202  return dht22_temperature();
203  case DHT22_READ_ALL:
204  return DHT22_SUCCESS;
205  default:
206  return DHT22_ERROR;
207  }
208 }
209 /*---------------------------------------------------------------------------*/
210 int16_t
211 dht22_read_all(int16_t *temperature, int16_t *humidity)
212 {
213  if((temperature == NULL) || (humidity == NULL)) {
214  PRINTF("DHT22: Invalid arguments\n");
215  return DHT22_ERROR;
216  }
217 
218  if(value(DHT22_READ_ALL) != DHT22_ERROR) {
219  *temperature = dht22_temperature();
220  *humidity = dht22_humidity();
221  return DHT22_SUCCESS;
222  }
223 
224  /* Already cleaned-up in the value() function */
225  return DHT22_ERROR;
226 }
227 /*---------------------------------------------------------------------------*/
228 static int
229 configure(int type, int value)
230 {
231  if(type != SENSORS_ACTIVE) {
232  return DHT22_ERROR;
233  }
234 
235  GPIO_SOFTWARE_CONTROL(DHT22_PORT_BASE, DHT22_PIN_MASK);
236  GPIO_SET_INPUT(DHT22_PORT_BASE, DHT22_PIN_MASK);
237  ioc_set_over(DHT22_PORT, DHT22_PIN, IOC_OVERRIDE_OE);
238  GPIO_SET_PIN(DHT22_PORT_BASE, DHT22_PIN_MASK);
239 
240  /* Restart flag */
241  busy = 0;
242 
243  if(value) {
244  enabled = 1;
245  return DHT22_SUCCESS;
246  }
247 
248  enabled = 0;
249  return DHT22_SUCCESS;
250 }
251 /*---------------------------------------------------------------------------*/
252 SENSORS_SENSOR(dht22, DHT22_SENSOR, value, configure, NULL);
253 /*---------------------------------------------------------------------------*/
254 /** @} */
#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