A simple library for reading data from a DHT22 sensor
Dependents: frdm_dht22_example DISCO-L053C8_ePD_demo
Simple library for doing DHT22 sensor readings. I've tested this on an FRDM K64F, but I see no reason it wouldn't work on other platforms.
Note that the data in `dht22_data_t` is fixed point, to convert to a normal number, divide by 10.
There is an example application here: https://developer.mbed.org/users/co657_sjc80/code/frdm_dht22_example/
dht22.cpp
- Committer:
- co657_sjc80
- Date:
- 2016-11-03
- Revision:
- 2:e52d76ef24b3
- Parent:
- 0:257ba13e416e
File content as of revision 2:e52d76ef24b3:
/* * (C) The University of Kent and Simon Cooksey 2015. * Proddled a lot by Fred */ #include "mbed.h" #include <inttypes.h> #include "dht22.h" /* * The DHT22 uses a 1 wire interface, sending 1's and 0s by varying the length * of the HIGH time on the signal pin. */ /* delay for approx 2 microseconds */ void DHT22::wait_2us (void) { 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; } /* 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; } } 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) { int dly; //__disable_irq (); setoutput (); dht22_s = 0; /* 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; setinput (); //__enable_irq (); } /* * Wait for the DHT22 to send the start bit ACK, after this we can read data. */ int DHT22::wait_start (void) { /* 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 8 bits of data, returns value [0-255] on success, -1 on error (timeout) */ int DHT22::read_byte (void) { 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; } d = wait_for_level (0, 100); if (d < 0) { /* timed out after 100us */ return -3; } if (d > DHT22_SIGNAL_HIGH_LOW_BOUNDARY) { v |= (1 << bit); #ifdef DEBUG_DHT22 debug = 1; } else { debug = 0; #endif } } return v; } /* * Reads a packet of DHT22 data. * * Param data: the packet to fill. returns 0 on success, < 0 on error (timeout of some kind) */ int DHT22::read (DHT22_data_t *data) { uint8_t buf[5]; uint16_t u_hum, u_tmp; int i; #ifdef DEBUG_DHT22 debug = 0; #endif __disable_irq (); // Send start bits send_start(); 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; } /* 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->checksum = buf[0]; #ifdef DEBUG_DHT22 debug = 0; #endif return i; }