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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dht22.cpp Source File

dht22.cpp

00001 /*
00002  * (C) The University of Kent and Simon Cooksey 2015.
00003  * Proddled a bit by Fred
00004  */
00005 
00006 #include "mbed.h"
00007 #include <inttypes.h>
00008 
00009 #include "dht22.h"
00010 
00011 /*
00012  * The DHT22 uses a 1 wire interface, sending 1's and 0s by varying the length
00013  * of the HIGH time on the signal pin.
00014  */
00015 
00016 /* delay for approx 2 microseconds */
00017 void DHT22::wait_2us (void)
00018 {
00019     int i;
00020     
00021     /* 16 * 14 nops, plus loopend */
00022     for (i=0; i<16; i++) {
00023         __asm__ __volatile__ ("         \n" \
00024             "   nop                     \n" \
00025             "   nop                     \n" \
00026             "   nop                     \n" \
00027             "   nop                     \n" \
00028             "   nop                     \n" \
00029             "   nop                     \n" \
00030             "   nop                     \n" \
00031             "   nop                     \n" \
00032             "   nop                     \n" \
00033             "   nop                     \n" \
00034             "   nop                     \n" \
00035             "   nop                     \n" \
00036             "   nop                     \n" \
00037             "   nop                     \n");
00038 
00039     }
00040     return;
00041 }
00042 
00043 
00044 /* ensure the comms pin is set for input */
00045 void DHT22::setinput (void)
00046 {
00047     if (!isinput) {
00048         dht22_s.input ();
00049         isinput = 1;
00050     }
00051 }
00052 
00053 /* ensure the comms pin is set for output */
00054 void DHT22::setoutput (void)
00055 {
00056     if (isinput) {
00057         dht22_s.output ();
00058         isinput = 0;
00059     }
00060 }
00061 
00062 
00063 int DHT22::wait_for_level (int lvl, const int max)
00064 {
00065     int time;
00066 
00067     setinput ();
00068     
00069     for (time=0; ((max == -1) || (time < max)) && (dht22_s != lvl); time += 2) {
00070         wait_2us ();
00071     }
00072     if ((max > 0) && (time >= max)) {
00073         /* timed out */
00074         return -1;
00075     }
00076     
00077     if (time) {
00078         /* means we saw a transition, so let it settle */
00079         wait_2us ();
00080         time += 2;
00081     }
00082     
00083     return time;            
00084 }
00085 
00086 
00087 /*
00088  * Send a start bit to the DHT22
00089  */
00090 void DHT22::send_start (void)
00091 {
00092     int dly;
00093     
00094     //__disable_irq ();
00095     setoutput ();
00096     dht22_s = 0;
00097     /* drag low for 1ms */
00098     for (dly=0; dly<(DHT22_START_BIT_TIME >> 1); dly++) {
00099         wait_2us ();
00100     }
00101     // wait_us (DHT22_START_BIT_TIME);
00102     dht22_s = 1;
00103     setinput ();
00104     //__enable_irq ();
00105 }
00106 
00107 /*
00108  * Wait for the DHT22 to send the start bit ACK, after this we can read data.
00109  */
00110 int DHT22::wait_start (void)
00111 {
00112     /* level should be 1 */
00113     if (dht22_s == 0) {
00114         return -1;
00115     }
00116     if (wait_for_level (0, 500) < 0) {
00117         /* should respond in 20-200 us, it didn't in 500 */
00118         return -2;
00119     }
00120     if (wait_for_level (1, 100) < 0) {
00121         /* only for 80 us (max 85 in datasheet) */
00122         return -3;
00123     }
00124     if (wait_for_level (0, 100) < 0) {
00125         /* only for 80 us (max 85 in datasheet) */
00126         return -4;
00127     }
00128     /* at this point we're about to start seeing the MSB of data [39-0] */
00129     
00130     return 0;    
00131 }
00132 
00133 /*
00134  * reads 8 bits of data, returns value [0-255] on success, -1 on error (timeout)
00135  */
00136 int DHT22::read_byte (void)
00137 {
00138     int d, bit;
00139     int v = 0;
00140     
00141     /* should be zero already */
00142     if (dht22_s == 1) {
00143         return -1;
00144     }
00145     
00146     for (bit=7; bit>=0; bit--) {
00147         /* expect it to stay low for 50us (max 55) */
00148         if (wait_for_level (1, 100) < 0) {
00149             /* timed out after 100us */
00150             return -2;
00151         }
00152 
00153 
00154         d = wait_for_level (0, 100);
00155         if (d < 0) {
00156             /* timed out after 100us */
00157             return -3;
00158         }
00159 
00160 
00161         if (d > DHT22_SIGNAL_HIGH_LOW_BOUNDARY) {
00162             v |= (1 << bit);
00163 #ifdef DEBUG_DHT22
00164             debug = 1;
00165         } else {
00166             debug = 0;
00167 #endif
00168         }
00169 
00170     }
00171     return v;
00172 }
00173 
00174 
00175 /*
00176  * Reads a packet of DHT22 data.
00177  *
00178  * Param data: the packet to fill.  returns 0 on success, < 0 on error (timeout of some kind)
00179  */
00180 int DHT22::read (DHT22_data_t *data)
00181 {
00182     uint8_t buf[5];
00183     uint16_t u_hum, u_tmp;
00184     int i;
00185 
00186 #ifdef DEBUG_DHT22
00187     debug = 0;
00188 #endif
00189     __disable_irq ();
00190     // Send start bits
00191     send_start();
00192 
00193     if (wait_start () < 0) {
00194         __enable_irq ();
00195         return -1;              /* timed out waiting for start response */
00196     }
00197     /* read 40 bits worth -- MSB first */
00198     for (i=4; i>=0; i--) {
00199         int v = read_byte ();
00200         
00201         if (v < 0) {
00202             /* timed out waiting for data */
00203             __enable_irq ();
00204             return -2;
00205         }
00206         buf[i] = (uint8_t)v;
00207     }
00208 
00209     /* yay, got here! -- sensor should release the wire in 50us (max 55) */
00210     if (wait_for_level (1, 100) < 0) {
00211         /* timed out at this point, but still fill the buffer */
00212         i = -3;
00213     } else {
00214         i = 0;
00215     }
00216     __enable_irq ();
00217     
00218     /* unscramble */
00219     u_hum = ((uint16_t)buf[4] << 8) | buf[3];
00220     u_tmp = ((uint16_t)buf[2] << 8) | buf[1];
00221     
00222     if (u_hum & 0x8000) {
00223         data->humidity = 1 - (int)(u_hum ^ 0x8000);
00224     } else {
00225         data->humidity = (int)u_hum;
00226     }
00227     if (u_tmp & 0x8000) {
00228         data->temp = 1 - (int)(u_tmp ^ 0x8000);
00229     } else {
00230         data->temp = (int)u_tmp;
00231     }
00232 
00233     data->checksum = buf[0];
00234 
00235 #ifdef DEBUG_DHT22
00236     debug = 0;
00237 #endif
00238     
00239     return i;
00240 }
00241