DHT22 library, based on Simon Cooksey's. Improved with some error checking and more rigid timing (interrupts off).

Fork of lib_dht22 by Jodie Perry

Committer:
co657_frmb
Date:
Thu Nov 03 11:12:51 2016 +0000
Revision:
4:30a98da09c59
Parent:
3:40df3c72813f
turned off debugging

Who changed what in which revision?

UserRevisionLine numberNew contents of line
co657_sjc80 0:257ba13e416e 1 /*
co657_sjc80 0:257ba13e416e 2 * (C) The University of Kent and Simon Cooksey 2015.
co657_frmb 3:40df3c72813f 3 * Proddled a bit by Fred
co657_sjc80 0:257ba13e416e 4 */
co657_sjc80 0:257ba13e416e 5
co657_sjc80 0:257ba13e416e 6 #include "mbed.h"
co657_sjc80 0:257ba13e416e 7 #include <inttypes.h>
co657_sjc80 0:257ba13e416e 8
co657_sjc80 0:257ba13e416e 9 #include "dht22.h"
co657_sjc80 0:257ba13e416e 10
co657_sjc80 0:257ba13e416e 11 /*
co657_sjc80 0:257ba13e416e 12 * The DHT22 uses a 1 wire interface, sending 1's and 0s by varying the length
co657_sjc80 0:257ba13e416e 13 * of the HIGH time on the signal pin.
co657_sjc80 0:257ba13e416e 14 */
co657_sjc80 0:257ba13e416e 15
co657_frmb 3:40df3c72813f 16 /* delay for approx 2 microseconds */
co657_frmb 3:40df3c72813f 17 void DHT22::wait_2us (void)
co657_sjc80 0:257ba13e416e 18 {
co657_frmb 3:40df3c72813f 19 int i;
co657_frmb 3:40df3c72813f 20
co657_frmb 3:40df3c72813f 21 /* 16 * 14 nops, plus loopend */
co657_frmb 3:40df3c72813f 22 for (i=0; i<16; i++) {
co657_frmb 3:40df3c72813f 23 __asm__ __volatile__ (" \n" \
co657_frmb 3:40df3c72813f 24 " nop \n" \
co657_frmb 3:40df3c72813f 25 " nop \n" \
co657_frmb 3:40df3c72813f 26 " nop \n" \
co657_frmb 3:40df3c72813f 27 " nop \n" \
co657_frmb 3:40df3c72813f 28 " nop \n" \
co657_frmb 3:40df3c72813f 29 " nop \n" \
co657_frmb 3:40df3c72813f 30 " nop \n" \
co657_frmb 3:40df3c72813f 31 " nop \n" \
co657_frmb 3:40df3c72813f 32 " nop \n" \
co657_frmb 3:40df3c72813f 33 " nop \n" \
co657_frmb 3:40df3c72813f 34 " nop \n" \
co657_frmb 3:40df3c72813f 35 " nop \n" \
co657_frmb 3:40df3c72813f 36 " nop \n" \
co657_frmb 3:40df3c72813f 37 " nop \n");
co657_frmb 3:40df3c72813f 38
co657_frmb 3:40df3c72813f 39 }
co657_frmb 3:40df3c72813f 40 return;
co657_frmb 3:40df3c72813f 41 }
co657_frmb 3:40df3c72813f 42
co657_sjc80 0:257ba13e416e 43
co657_frmb 3:40df3c72813f 44 /* ensure the comms pin is set for input */
co657_frmb 3:40df3c72813f 45 void DHT22::setinput (void)
co657_frmb 3:40df3c72813f 46 {
co657_frmb 3:40df3c72813f 47 if (!isinput) {
co657_frmb 3:40df3c72813f 48 dht22_s.input ();
co657_frmb 3:40df3c72813f 49 isinput = 1;
co657_frmb 3:40df3c72813f 50 }
co657_frmb 3:40df3c72813f 51 }
co657_frmb 3:40df3c72813f 52
co657_frmb 3:40df3c72813f 53 /* ensure the comms pin is set for output */
co657_frmb 3:40df3c72813f 54 void DHT22::setoutput (void)
co657_frmb 3:40df3c72813f 55 {
co657_frmb 3:40df3c72813f 56 if (isinput) {
co657_frmb 3:40df3c72813f 57 dht22_s.output ();
co657_frmb 3:40df3c72813f 58 isinput = 0;
co657_frmb 3:40df3c72813f 59 }
co657_frmb 3:40df3c72813f 60 }
co657_frmb 3:40df3c72813f 61
co657_sjc80 0:257ba13e416e 62
co657_frmb 3:40df3c72813f 63 int DHT22::wait_for_level (int lvl, const int max)
co657_frmb 3:40df3c72813f 64 {
co657_frmb 3:40df3c72813f 65 int time;
co657_frmb 3:40df3c72813f 66
co657_frmb 3:40df3c72813f 67 setinput ();
co657_frmb 3:40df3c72813f 68
co657_frmb 3:40df3c72813f 69 for (time=0; ((max == -1) || (time < max)) && (dht22_s != lvl); time += 2) {
co657_frmb 3:40df3c72813f 70 wait_2us ();
co657_frmb 3:40df3c72813f 71 }
co657_frmb 3:40df3c72813f 72 if ((max > 0) && (time >= max)) {
co657_frmb 3:40df3c72813f 73 /* timed out */
co657_frmb 3:40df3c72813f 74 return -1;
co657_frmb 3:40df3c72813f 75 }
co657_frmb 3:40df3c72813f 76
co657_frmb 3:40df3c72813f 77 if (time) {
co657_frmb 3:40df3c72813f 78 /* means we saw a transition, so let it settle */
co657_frmb 3:40df3c72813f 79 wait_2us ();
co657_frmb 3:40df3c72813f 80 time += 2;
co657_frmb 3:40df3c72813f 81 }
co657_frmb 3:40df3c72813f 82
co657_frmb 3:40df3c72813f 83 return time;
co657_sjc80 0:257ba13e416e 84 }
co657_sjc80 0:257ba13e416e 85
co657_frmb 3:40df3c72813f 86
co657_sjc80 0:257ba13e416e 87 /*
co657_sjc80 0:257ba13e416e 88 * Send a start bit to the DHT22
co657_sjc80 0:257ba13e416e 89 */
co657_frmb 3:40df3c72813f 90 void DHT22::send_start (void)
co657_sjc80 0:257ba13e416e 91 {
co657_frmb 3:40df3c72813f 92 int dly;
co657_frmb 3:40df3c72813f 93
co657_jnp8 2:02cbaab7c6cd 94 //__disable_irq ();
co657_frmb 3:40df3c72813f 95 setoutput ();
co657_sjc80 0:257ba13e416e 96 dht22_s = 0;
co657_frmb 3:40df3c72813f 97 /* drag low for 1ms */
co657_frmb 3:40df3c72813f 98 for (dly=0; dly<(DHT22_START_BIT_TIME >> 1); dly++) {
co657_frmb 3:40df3c72813f 99 wait_2us ();
co657_frmb 3:40df3c72813f 100 }
co657_frmb 3:40df3c72813f 101 // wait_us (DHT22_START_BIT_TIME);
co657_sjc80 0:257ba13e416e 102 dht22_s = 1;
co657_frmb 3:40df3c72813f 103 setinput ();
co657_jnp8 2:02cbaab7c6cd 104 //__enable_irq ();
co657_sjc80 0:257ba13e416e 105 }
co657_sjc80 0:257ba13e416e 106
co657_sjc80 0:257ba13e416e 107 /*
co657_sjc80 0:257ba13e416e 108 * Wait for the DHT22 to send the start bit ACK, after this we can read data.
co657_sjc80 0:257ba13e416e 109 */
co657_frmb 3:40df3c72813f 110 int DHT22::wait_start (void)
co657_sjc80 0:257ba13e416e 111 {
co657_frmb 3:40df3c72813f 112 /* level should be 1 */
co657_frmb 3:40df3c72813f 113 if (dht22_s == 0) {
co657_frmb 3:40df3c72813f 114 return -1;
co657_frmb 3:40df3c72813f 115 }
co657_frmb 3:40df3c72813f 116 if (wait_for_level (0, 500) < 0) {
co657_frmb 3:40df3c72813f 117 /* should respond in 20-200 us, it didn't in 500 */
co657_frmb 3:40df3c72813f 118 return -2;
co657_frmb 3:40df3c72813f 119 }
co657_frmb 3:40df3c72813f 120 if (wait_for_level (1, 100) < 0) {
co657_frmb 3:40df3c72813f 121 /* only for 80 us (max 85 in datasheet) */
co657_frmb 3:40df3c72813f 122 return -3;
co657_frmb 3:40df3c72813f 123 }
co657_frmb 3:40df3c72813f 124 if (wait_for_level (0, 100) < 0) {
co657_frmb 3:40df3c72813f 125 /* only for 80 us (max 85 in datasheet) */
co657_frmb 3:40df3c72813f 126 return -4;
co657_frmb 3:40df3c72813f 127 }
co657_frmb 3:40df3c72813f 128 /* at this point we're about to start seeing the MSB of data [39-0] */
co657_frmb 3:40df3c72813f 129
co657_frmb 3:40df3c72813f 130 return 0;
co657_sjc80 0:257ba13e416e 131 }
co657_sjc80 0:257ba13e416e 132
co657_sjc80 0:257ba13e416e 133 /*
co657_frmb 3:40df3c72813f 134 * reads 8 bits of data, returns value [0-255] on success, -1 on error (timeout)
co657_sjc80 0:257ba13e416e 135 */
co657_frmb 3:40df3c72813f 136 int DHT22::read_byte (void)
co657_sjc80 0:257ba13e416e 137 {
co657_frmb 3:40df3c72813f 138 int d, bit;
co657_frmb 3:40df3c72813f 139 int v = 0;
co657_frmb 3:40df3c72813f 140
co657_frmb 3:40df3c72813f 141 /* should be zero already */
co657_frmb 3:40df3c72813f 142 if (dht22_s == 1) {
co657_frmb 3:40df3c72813f 143 return -1;
co657_frmb 3:40df3c72813f 144 }
co657_frmb 3:40df3c72813f 145
co657_frmb 3:40df3c72813f 146 for (bit=7; bit>=0; bit--) {
co657_frmb 3:40df3c72813f 147 /* expect it to stay low for 50us (max 55) */
co657_frmb 3:40df3c72813f 148 if (wait_for_level (1, 100) < 0) {
co657_frmb 3:40df3c72813f 149 /* timed out after 100us */
co657_frmb 3:40df3c72813f 150 return -2;
co657_frmb 3:40df3c72813f 151 }
co657_frmb 3:40df3c72813f 152
co657_sjc80 0:257ba13e416e 153
co657_frmb 3:40df3c72813f 154 d = wait_for_level (0, 100);
co657_frmb 3:40df3c72813f 155 if (d < 0) {
co657_frmb 3:40df3c72813f 156 /* timed out after 100us */
co657_frmb 3:40df3c72813f 157 return -3;
co657_sjc80 0:257ba13e416e 158 }
co657_frmb 3:40df3c72813f 159
co657_frmb 3:40df3c72813f 160
co657_frmb 3:40df3c72813f 161 if (d > DHT22_SIGNAL_HIGH_LOW_BOUNDARY) {
co657_frmb 3:40df3c72813f 162 v |= (1 << bit);
co657_frmb 4:30a98da09c59 163 #ifdef DEBUG_DHT22
co657_frmb 3:40df3c72813f 164 debug = 1;
co657_frmb 4:30a98da09c59 165 } else {
co657_frmb 3:40df3c72813f 166 debug = 0;
co657_frmb 4:30a98da09c59 167 #endif
co657_sjc80 0:257ba13e416e 168 }
co657_frmb 3:40df3c72813f 169
co657_sjc80 0:257ba13e416e 170 }
co657_frmb 3:40df3c72813f 171 return v;
co657_sjc80 0:257ba13e416e 172 }
co657_sjc80 0:257ba13e416e 173
co657_sjc80 0:257ba13e416e 174
co657_sjc80 0:257ba13e416e 175 /*
co657_sjc80 0:257ba13e416e 176 * Reads a packet of DHT22 data.
co657_sjc80 0:257ba13e416e 177 *
co657_frmb 3:40df3c72813f 178 * Param data: the packet to fill. returns 0 on success, < 0 on error (timeout of some kind)
co657_sjc80 0:257ba13e416e 179 */
co657_frmb 3:40df3c72813f 180 int DHT22::read (DHT22_data_t *data)
co657_sjc80 0:257ba13e416e 181 {
co657_frmb 3:40df3c72813f 182 uint8_t buf[5];
co657_frmb 3:40df3c72813f 183 uint16_t u_hum, u_tmp;
co657_frmb 3:40df3c72813f 184 int i;
co657_frmb 4:30a98da09c59 185
co657_frmb 4:30a98da09c59 186 #ifdef DEBUG_DHT22
co657_frmb 3:40df3c72813f 187 debug = 0;
co657_frmb 4:30a98da09c59 188 #endif
co657_frmb 3:40df3c72813f 189 __disable_irq ();
co657_sjc80 0:257ba13e416e 190 // Send start bits
co657_sjc80 0:257ba13e416e 191 send_start();
co657_sjc80 0:257ba13e416e 192
co657_frmb 3:40df3c72813f 193 if (wait_start () < 0) {
co657_frmb 3:40df3c72813f 194 __enable_irq ();
co657_frmb 3:40df3c72813f 195 return -1; /* timed out waiting for start response */
co657_frmb 3:40df3c72813f 196 }
co657_frmb 3:40df3c72813f 197 /* read 40 bits worth -- MSB first */
co657_frmb 3:40df3c72813f 198 for (i=4; i>=0; i--) {
co657_frmb 3:40df3c72813f 199 int v = read_byte ();
co657_frmb 3:40df3c72813f 200
co657_frmb 3:40df3c72813f 201 if (v < 0) {
co657_frmb 3:40df3c72813f 202 /* timed out waiting for data */
co657_frmb 3:40df3c72813f 203 __enable_irq ();
co657_frmb 3:40df3c72813f 204 return -2;
co657_frmb 3:40df3c72813f 205 }
co657_frmb 3:40df3c72813f 206 buf[i] = (uint8_t)v;
co657_frmb 3:40df3c72813f 207 }
co657_sjc80 0:257ba13e416e 208
co657_frmb 3:40df3c72813f 209 /* yay, got here! -- sensor should release the wire in 50us (max 55) */
co657_frmb 3:40df3c72813f 210 if (wait_for_level (1, 100) < 0) {
co657_frmb 3:40df3c72813f 211 /* timed out at this point, but still fill the buffer */
co657_frmb 3:40df3c72813f 212 i = -3;
co657_frmb 3:40df3c72813f 213 } else {
co657_frmb 3:40df3c72813f 214 i = 0;
co657_frmb 3:40df3c72813f 215 }
co657_frmb 3:40df3c72813f 216 __enable_irq ();
co657_frmb 3:40df3c72813f 217
co657_frmb 3:40df3c72813f 218 /* unscramble */
co657_frmb 3:40df3c72813f 219 u_hum = ((uint16_t)buf[4] << 8) | buf[3];
co657_frmb 3:40df3c72813f 220 u_tmp = ((uint16_t)buf[2] << 8) | buf[1];
co657_frmb 3:40df3c72813f 221
co657_frmb 3:40df3c72813f 222 if (u_hum & 0x8000) {
co657_frmb 3:40df3c72813f 223 data->humidity = 1 - (int)(u_hum ^ 0x8000);
co657_frmb 3:40df3c72813f 224 } else {
co657_frmb 3:40df3c72813f 225 data->humidity = (int)u_hum;
co657_frmb 3:40df3c72813f 226 }
co657_frmb 3:40df3c72813f 227 if (u_tmp & 0x8000) {
co657_frmb 3:40df3c72813f 228 data->temp = 1 - (int)(u_tmp ^ 0x8000);
co657_frmb 3:40df3c72813f 229 } else {
co657_frmb 3:40df3c72813f 230 data->temp = (int)u_tmp;
co657_frmb 3:40df3c72813f 231 }
co657_sjc80 0:257ba13e416e 232
co657_frmb 3:40df3c72813f 233 data->checksum = buf[0];
co657_frmb 4:30a98da09c59 234
co657_frmb 4:30a98da09c59 235 #ifdef DEBUG_DHT22
co657_frmb 3:40df3c72813f 236 debug = 0;
co657_frmb 4:30a98da09c59 237 #endif
co657_frmb 3:40df3c72813f 238
co657_frmb 3:40df3c72813f 239 return i;
co657_frmb 3:40df3c72813f 240 }
co657_frmb 3:40df3c72813f 241