DHT22 library, based on Simon Cooksey's. Improved with some error checking and more rigid timing (interrupts off).
Fork of lib_dht22 by
dht22.cpp@3:40df3c72813f, 2016-11-03 (annotated)
- Committer:
- co657_frmb
- Date:
- Thu Nov 03 11:08:45 2016 +0000
- Revision:
- 3:40df3c72813f
- Parent:
- 2:02cbaab7c6cd
- Child:
- 4:30a98da09c59
fixed up some things, still need a touch more tidying.
Who changed what in which revision?
User | Revision | Line number | New 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 | 3:40df3c72813f | 163 | debug = 1; |
co657_frmb | 3:40df3c72813f | 164 | } else { |
co657_frmb | 3:40df3c72813f | 165 | debug = 0; |
co657_sjc80 | 0:257ba13e416e | 166 | } |
co657_frmb | 3:40df3c72813f | 167 | |
co657_sjc80 | 0:257ba13e416e | 168 | } |
co657_frmb | 3:40df3c72813f | 169 | return v; |
co657_sjc80 | 0:257ba13e416e | 170 | } |
co657_sjc80 | 0:257ba13e416e | 171 | |
co657_sjc80 | 0:257ba13e416e | 172 | |
co657_sjc80 | 0:257ba13e416e | 173 | /* |
co657_sjc80 | 0:257ba13e416e | 174 | * Reads a packet of DHT22 data. |
co657_sjc80 | 0:257ba13e416e | 175 | * |
co657_frmb | 3:40df3c72813f | 176 | * Param data: the packet to fill. returns 0 on success, < 0 on error (timeout of some kind) |
co657_sjc80 | 0:257ba13e416e | 177 | */ |
co657_frmb | 3:40df3c72813f | 178 | int DHT22::read (DHT22_data_t *data) |
co657_sjc80 | 0:257ba13e416e | 179 | { |
co657_frmb | 3:40df3c72813f | 180 | uint8_t buf[5]; |
co657_frmb | 3:40df3c72813f | 181 | uint16_t u_hum, u_tmp; |
co657_frmb | 3:40df3c72813f | 182 | int i; |
co657_frmb | 3:40df3c72813f | 183 | |
co657_frmb | 3:40df3c72813f | 184 | debug = 0; |
co657_frmb | 3:40df3c72813f | 185 | __disable_irq (); |
co657_sjc80 | 0:257ba13e416e | 186 | // Send start bits |
co657_sjc80 | 0:257ba13e416e | 187 | send_start(); |
co657_sjc80 | 0:257ba13e416e | 188 | |
co657_frmb | 3:40df3c72813f | 189 | if (wait_start () < 0) { |
co657_frmb | 3:40df3c72813f | 190 | __enable_irq (); |
co657_frmb | 3:40df3c72813f | 191 | return -1; /* timed out waiting for start response */ |
co657_frmb | 3:40df3c72813f | 192 | } |
co657_frmb | 3:40df3c72813f | 193 | /* read 40 bits worth -- MSB first */ |
co657_frmb | 3:40df3c72813f | 194 | for (i=4; i>=0; i--) { |
co657_frmb | 3:40df3c72813f | 195 | int v = read_byte (); |
co657_frmb | 3:40df3c72813f | 196 | |
co657_frmb | 3:40df3c72813f | 197 | if (v < 0) { |
co657_frmb | 3:40df3c72813f | 198 | /* timed out waiting for data */ |
co657_frmb | 3:40df3c72813f | 199 | __enable_irq (); |
co657_frmb | 3:40df3c72813f | 200 | return -2; |
co657_frmb | 3:40df3c72813f | 201 | } |
co657_frmb | 3:40df3c72813f | 202 | buf[i] = (uint8_t)v; |
co657_frmb | 3:40df3c72813f | 203 | } |
co657_sjc80 | 0:257ba13e416e | 204 | |
co657_frmb | 3:40df3c72813f | 205 | /* yay, got here! -- sensor should release the wire in 50us (max 55) */ |
co657_frmb | 3:40df3c72813f | 206 | if (wait_for_level (1, 100) < 0) { |
co657_frmb | 3:40df3c72813f | 207 | /* timed out at this point, but still fill the buffer */ |
co657_frmb | 3:40df3c72813f | 208 | i = -3; |
co657_frmb | 3:40df3c72813f | 209 | } else { |
co657_frmb | 3:40df3c72813f | 210 | i = 0; |
co657_frmb | 3:40df3c72813f | 211 | } |
co657_frmb | 3:40df3c72813f | 212 | __enable_irq (); |
co657_frmb | 3:40df3c72813f | 213 | |
co657_frmb | 3:40df3c72813f | 214 | /* unscramble */ |
co657_frmb | 3:40df3c72813f | 215 | u_hum = ((uint16_t)buf[4] << 8) | buf[3]; |
co657_frmb | 3:40df3c72813f | 216 | u_tmp = ((uint16_t)buf[2] << 8) | buf[1]; |
co657_frmb | 3:40df3c72813f | 217 | |
co657_frmb | 3:40df3c72813f | 218 | if (u_hum & 0x8000) { |
co657_frmb | 3:40df3c72813f | 219 | data->humidity = 1 - (int)(u_hum ^ 0x8000); |
co657_frmb | 3:40df3c72813f | 220 | } else { |
co657_frmb | 3:40df3c72813f | 221 | data->humidity = (int)u_hum; |
co657_frmb | 3:40df3c72813f | 222 | } |
co657_frmb | 3:40df3c72813f | 223 | if (u_tmp & 0x8000) { |
co657_frmb | 3:40df3c72813f | 224 | data->temp = 1 - (int)(u_tmp ^ 0x8000); |
co657_frmb | 3:40df3c72813f | 225 | } else { |
co657_frmb | 3:40df3c72813f | 226 | data->temp = (int)u_tmp; |
co657_frmb | 3:40df3c72813f | 227 | } |
co657_sjc80 | 0:257ba13e416e | 228 | |
co657_frmb | 3:40df3c72813f | 229 | data->checksum = buf[0]; |
co657_frmb | 3:40df3c72813f | 230 | debug = 0; |
co657_frmb | 3:40df3c72813f | 231 | |
co657_frmb | 3:40df3c72813f | 232 | return i; |
co657_frmb | 3:40df3c72813f | 233 | } |
co657_frmb | 3:40df3c72813f | 234 |