DHT22 library, based on Simon Cooksey's. Improved with some error checking and more rigid timing (interrupts off).
Fork of lib_dht22 by
Diff: dht22.cpp
- Revision:
- 3:40df3c72813f
- Parent:
- 2:02cbaab7c6cd
- Child:
- 4:30a98da09c59
--- a/dht22.cpp Wed Nov 02 16:29:53 2016 +0000 +++ b/dht22.cpp Thu Nov 03 11:08:45 2016 +0000 @@ -1,5 +1,6 @@ /* * (C) The University of Kent and Simon Cooksey 2015. + * Proddled a bit by Fred */ #include "mbed.h" @@ -12,142 +13,222 @@ * of the HIGH time on the signal pin. */ -/* - * Wait for a rising or falling edge on the sense pin. - * - * Returns: the number of uS elapsed before the transition - */ -int DHT22::wait_for_edge(edge_type_t type) +/* delay for approx 2 microseconds */ +void DHT22::wait_2us (void) { - //__disable_irq (); - dht22_s.input(); + int i; + + /* 16 * 14 nops, plus loopend */ + for (i=0; i<16; i++) { + __asm__ __volatile__ (" \n" \ + " nop \n" \ + " nop \n" \ + " nop \n" \ + " nop \n" \ + " nop \n" \ + " nop \n" \ + " nop \n" \ + " nop \n" \ + " nop \n" \ + " nop \n" \ + " nop \n" \ + " nop \n" \ + " nop \n" \ + " nop \n"); + + } + return; +} + - // Timing is done by increasing this number, as the Timer class appears to - // be super slow. - int time = 0; - do { - wait_us(2); - time+=2; - } while(dht22_s != (int)type); +/* ensure the comms pin is set for input */ +void DHT22::setinput (void) +{ + if (!isinput) { + dht22_s.input (); + isinput = 1; + } +} + +/* ensure the comms pin is set for output */ +void DHT22::setoutput (void) +{ + if (isinput) { + dht22_s.output (); + isinput = 0; + } +} + - // wait for the edge to transition properly - wait_us(2); - //__enable_irq (); - return time; +int DHT22::wait_for_level (int lvl, const int max) +{ + int time; + + setinput (); + + for (time=0; ((max == -1) || (time < max)) && (dht22_s != lvl); time += 2) { + wait_2us (); + } + if ((max > 0) && (time >= max)) { + /* timed out */ + return -1; + } + + if (time) { + /* means we saw a transition, so let it settle */ + wait_2us (); + time += 2; + } + + return time; } + /* * Send a start bit to the DHT22 */ -void DHT22::send_start() +void DHT22::send_start (void) { + int dly; + //__disable_irq (); - dht22_s.output(); + setoutput (); dht22_s = 0; - wait_us(DHT22_START_BIT_TIME); + /* drag low for 1ms */ + for (dly=0; dly<(DHT22_START_BIT_TIME >> 1); dly++) { + wait_2us (); + } + // wait_us (DHT22_START_BIT_TIME); dht22_s = 1; - dht22_s.input(); + setinput (); //__enable_irq (); } /* * Wait for the DHT22 to send the start bit ACK, after this we can read data. */ -void DHT22::await_start_response() +int DHT22::wait_start (void) { - dht22_s.input(); - wait_for_edge(EDGE_TYPE_FALLING); // 20-40 uS - wait_for_edge(EDGE_TYPE_RISING); // 80 uS - wait_for_edge(EDGE_TYPE_FALLING); // 80 uS + /* level should be 1 */ + if (dht22_s == 0) { + return -1; + } + if (wait_for_level (0, 500) < 0) { + /* should respond in 20-200 us, it didn't in 500 */ + return -2; + } + if (wait_for_level (1, 100) < 0) { + /* only for 80 us (max 85 in datasheet) */ + return -3; + } + if (wait_for_level (0, 100) < 0) { + /* only for 80 us (max 85 in datasheet) */ + return -4; + } + /* at this point we're about to start seeing the MSB of data [39-0] */ + + return 0; } /* - * Reads 16 bits of data from the DHT22 - * - * Returns: the signed value read. dht22_t. - * NB. the DHT22 uses a sign bit to do -ve and positive, but this is - * incompatible with signed numbers in C, so the conversion is done here. + * reads 8 bits of data, returns value [0-255] on success, -1 on error (timeout) */ -int16_t DHT22::read_word() +int DHT22::read_byte (void) { - dht22_s.input(); - int32_t duration; - int16_t word = 0x00; - for(char bit = 0; bit < 16; bit++) - { - /* /-----------\ - * / duration \ 50us - * ----/ \------- - */ - wait_for_edge(EDGE_TYPE_RISING); - duration = wait_for_edge(EDGE_TYPE_FALLING); + int d, bit; + int v = 0; + + /* should be zero already */ + if (dht22_s == 1) { + return -1; + } + + for (bit=7; bit>=0; bit--) { + /* expect it to stay low for 50us (max 55) */ + if (wait_for_level (1, 100) < 0) { + /* timed out after 100us */ + return -2; + } + - if(duration > DHT22_SIGNAL_HIGH_LOW_BOUNDARY) - { - word |= (1 << 15-bit); + d = wait_for_level (0, 100); + if (d < 0) { + /* timed out after 100us */ + return -3; } - else - { - word |= (0 << 15-bit); + + + if (d > DHT22_SIGNAL_HIGH_LOW_BOUNDARY) { + v |= (1 << bit); + debug = 1; + } else { + debug = 0; } + } - if(word & 0x8000) - return 1 - (word ^ 0x8000); - return word; + return v; } -/* - * Reads 8 bits of data from the DHT22 - * - * Returns: the unsigned checksum value read. dht22_t. - */ -uint8_t DHT22::read_checksum() -{ - dht22_s.input(); - uint32_t duration; - uint8_t word; - for(char bit = 0; bit < sizeof(uint8_t)*8; bit++) - { - /* /-----------\ - * / duration \ 50us - * ----/ \------- - */ - wait_for_edge(EDGE_TYPE_RISING); - duration = wait_for_edge(EDGE_TYPE_FALLING); - - if(duration > DHT22_SIGNAL_HIGH_LOW_BOUNDARY) - { - word |= (1 << 7-bit); - } - else - { - word |= (0 << 7-bit); - } - } - return word; -} /* * Reads a packet of DHT22 data. * - * Param data: the packet to fill. + * Param data: the packet to fill. returns 0 on success, < 0 on error (timeout of some kind) */ -void DHT22::read(DHT22_data_t * data) +int DHT22::read (DHT22_data_t *data) { + uint8_t buf[5]; + uint16_t u_hum, u_tmp; + int i; + + debug = 0; + __disable_irq (); // Send start bits send_start(); - // Wait for device to respond - await_start_response(); - - // Read data bits (16+16) - int16_t humidity = read_word(); - int16_t temp = read_word(); + if (wait_start () < 0) { + __enable_irq (); + return -1; /* timed out waiting for start response */ + } + /* read 40 bits worth -- MSB first */ + for (i=4; i>=0; i--) { + int v = read_byte (); + + if (v < 0) { + /* timed out waiting for data */ + __enable_irq (); + return -2; + } + buf[i] = (uint8_t)v; + } - // Read checksum (8) - uint8_t checksum = read_checksum(); + /* yay, got here! -- sensor should release the wire in 50us (max 55) */ + if (wait_for_level (1, 100) < 0) { + /* timed out at this point, but still fill the buffer */ + i = -3; + } else { + i = 0; + } + __enable_irq (); + + /* unscramble */ + u_hum = ((uint16_t)buf[4] << 8) | buf[3]; + u_tmp = ((uint16_t)buf[2] << 8) | buf[1]; + + if (u_hum & 0x8000) { + data->humidity = 1 - (int)(u_hum ^ 0x8000); + } else { + data->humidity = (int)u_hum; + } + if (u_tmp & 0x8000) { + data->temp = 1 - (int)(u_tmp ^ 0x8000); + } else { + data->temp = (int)u_tmp; + } - data->humidity = (humidity); - data->temp = (temp); - data->checksum = checksum; -} \ No newline at end of file + data->checksum = buf[0]; + debug = 0; + + return i; +} +