DHT11/22 library fix
Support DHT11/DHT22 modules. Data representation fix. Library refactoring.
This commit is contained in:
		
							parent
							
								
									78c5b43a40
								
							
						
					
					
						commit
						a41407e3d1
					
				
					 3 changed files with 181 additions and 106 deletions
				
			
		|  | @ -2,6 +2,8 @@ | |||
|  * | ||||
|  * This sample code is in the public domain. | ||||
|  */ | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include "espressif/esp_common.h" | ||||
| #include "esp/uart.h" | ||||
| #include "FreeRTOS.h" | ||||
|  | @ -13,12 +15,12 @@ | |||
|  * to read and print a new temperature and humidity measurement | ||||
|  * from a sensor attached to GPIO pin 4. | ||||
|  */ | ||||
| int const dht_gpio = 4; | ||||
| uint8_t const dht_gpio = 12; | ||||
| 
 | ||||
| void dhtMeasurementTask(void *pvParameters) | ||||
| { | ||||
|   int8_t temperature = 0; | ||||
|   int8_t humidity = 0; | ||||
|     int16_t temperature = 0; | ||||
|     int16_t humidity = 0; | ||||
| 
 | ||||
|     // DHT sensors that come mounted on a PCB generally have
 | ||||
|     // pull-up resistors on the data pin.  It is recommended
 | ||||
|  | @ -26,11 +28,12 @@ void dhtMeasurementTask(void *pvParameters) | |||
|     gpio_set_pullup(dht_gpio, false, false); | ||||
| 
 | ||||
|     while(1) { | ||||
| 
 | ||||
|     if (dht_fetch_data(dht_gpio, &humidity, &temperature)) { | ||||
|       printf("Humidity: %i%% Temp: %iC\n", humidity, temperature); | ||||
|         if (dht_read_data(dht_gpio, &humidity, &temperature)) { | ||||
|             printf("Humidity: %d.%d%% Temp: %d.%dC\n",  | ||||
|                     humidity / 10, humidity % 10,  | ||||
|                     temperature / 10, abs(temperature) % 10); | ||||
|         } else { | ||||
|       printf("Could not read data from sensor..."); | ||||
|             printf("Could not read data from sensor\n"); | ||||
|         } | ||||
| 
 | ||||
|         // Three second delay...
 | ||||
|  |  | |||
							
								
								
									
										213
									
								
								extras/dht/dht.c
									
										
									
									
									
								
							
							
						
						
									
										213
									
								
								extras/dht/dht.c
									
										
									
									
									
								
							|  | @ -6,17 +6,20 @@ | |||
|  */ | ||||
| 
 | ||||
| #include "dht.h" | ||||
| #include "FreeRTOS.h" | ||||
| #include "string.h" | ||||
| #include "task.h" | ||||
| #include "esp/gpio.h" | ||||
| 
 | ||||
| #include <espressif/esp_misc.h> // sdk_os_delay_us | ||||
| 
 | ||||
| #ifndef DEBUG_DHT | ||||
| #define DEBUG_DHT 0 | ||||
| #endif | ||||
| // DHT timer precision in microseconds
 | ||||
| #define DHT_TIMER_INTERVAL   2 | ||||
| #define DHT_DATA_BITS  40 | ||||
| 
 | ||||
| #if DEBUG_DHT | ||||
| // #define DEBUG_DHT
 | ||||
| 
 | ||||
| #ifdef DEBUG_DHT | ||||
| #define debug(fmt, ...) printf("%s" fmt "\n", "dht: ", ## __VA_ARGS__); | ||||
| #else | ||||
| #define debug(fmt, ...) /* (do nothing) */ | ||||
|  | @ -42,7 +45,7 @@ | |||
|  *  and then letting it float back high for a period of time that depends on the data bit. | ||||
|  *  duration_data_high is shorter than 50us for a logic '0' and longer than 50us for logic '1'. | ||||
|  * | ||||
|  *  There are a total of 40 data bits trasnmitted sequentially. These bits are read into a byte array | ||||
|  *  There are a total of 40 data bits transmitted sequentially. These bits are read into a byte array | ||||
|  *  of length 5.  The first and third bytes are humidity (%) and temperature (C), respectively.  Bytes 2 and 4 | ||||
|  *  are zero-filled and the fifth is a checksum such that: | ||||
|  * | ||||
|  | @ -50,95 +53,143 @@ | |||
|  * | ||||
| */ | ||||
| 
 | ||||
| /*  
 | ||||
|  *  @pin                    the selected GPIO pin | ||||
|  *  @interval               how frequently the pin state is checked in microseconds | ||||
|  *  @timeout                maximum length of time to wait for the expected pin state | ||||
|  *  @expected_pin_state     high (true) or low (false) pin state | ||||
|  *  @counter                pointer to external uint8_t for tallying the duration waited for the pin state | ||||
| 
 | ||||
| /**
 | ||||
|  * Wait specified time for pin to go to a specified state. | ||||
|  * If timeout is reached and pin doesn't go to a requested state | ||||
|  * false is returned. | ||||
|  * The elapsed time is returned in pointer 'duration' if it is not NULL. | ||||
|  */ | ||||
| 
 | ||||
| bool dht_await_pin_state(uint8_t pin, uint8_t interval, uint8_t timeout, bool expected_pin_state, uint8_t * counter) { | ||||
| 
 | ||||
|     for (*counter = 0; *counter < timeout; *counter+=interval) { | ||||
|         if (gpio_read(pin) == expected_pin_state) return true; | ||||
|         sdk_os_delay_us(interval); | ||||
| static bool dht_await_pin_state(uint8_t pin, uint32_t timeout, | ||||
|         bool expected_pin_state, uint32_t *duration) | ||||
| { | ||||
|     for (uint32_t i = 0; i < timeout; i += DHT_TIMER_INTERVAL) { | ||||
|         if (gpio_read(pin) == expected_pin_state) { | ||||
|             if (duration) { | ||||
|                 *duration = i; | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
|         sdk_os_delay_us(DHT_TIMER_INTERVAL); | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| /*  
 | ||||
|  *   | ||||
|  *   | ||||
|  *  @pin                    the selected GPIO pin | ||||
|  *  @humidity               pointer to external int8_t to store resulting humidity value | ||||
|  *  @temperature            pointer to external int8_t to store resulting temperature value | ||||
| /**
 | ||||
|  * Request data from DHT and read raw bit stream. | ||||
|  * The function call should be protected from task switching. | ||||
|  * Return false if error occurred. | ||||
|  */ | ||||
| 
 | ||||
| bool dht_fetch_data(int8_t pin, int8_t * humidity, int8_t * temperature) { | ||||
|     int8_t data[40] = {0}; | ||||
|     int8_t result[5] = {0}; | ||||
|     uint8_t i = 0; | ||||
| 
 | ||||
|     uint8_t init_phase_duration = 0; | ||||
|     uint8_t duration_data_low = 0; | ||||
|     uint8_t duration_data_high = 0; | ||||
| 
 | ||||
|     gpio_enable(pin, GPIO_OUT_OPEN_DRAIN); | ||||
| 
 | ||||
|     taskENTER_CRITICAL(); | ||||
| static inline bool dht_fetch_data(uint8_t pin, bool bits[DHT_DATA_BITS]) | ||||
| { | ||||
|     uint32_t low_duration; | ||||
|     uint32_t high_duration; | ||||
| 
 | ||||
|     // Phase 'A' pulling signal low to initiate read sequence
 | ||||
|     gpio_write(pin, 0); | ||||
|     sdk_os_delay_us(20000); | ||||
|     gpio_write(pin, 1); | ||||
| 
 | ||||
|     // Step through Phase 'B' at 2us intervals, 40us max
 | ||||
|     if (dht_await_pin_state(pin, 2, 40, false, &init_phase_duration)) { | ||||
|         // Step through Phase 'C ' at 2us intervals, 88us max
 | ||||
|         if (dht_await_pin_state(pin, 2, 88, true, &init_phase_duration)) { | ||||
|             // Step through Phase 'D' at 2us intervals, 88us max
 | ||||
|             if (dht_await_pin_state(pin, 2, 88, false, &init_phase_duration)) { | ||||
| 
 | ||||
|                 // Read in each of the 40 bits of data...
 | ||||
|                 for (i = 0; i < 40; i++) { | ||||
|                     if (dht_await_pin_state(pin, 2, 60, true, &duration_data_low)) { | ||||
|                         if (dht_await_pin_state(pin, 2, 75, false, &duration_data_high)) { | ||||
|                             data[i] = duration_data_high > duration_data_low; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 taskEXIT_CRITICAL(); | ||||
| 
 | ||||
|                 for (i = 0; i < 40; i++) { | ||||
|                     // Read each bit into 'result' byte array...
 | ||||
|                     result[i/8] <<= 1; | ||||
|                     result[i/8] |= data[i]; | ||||
|                 } | ||||
| 
 | ||||
|                 if (result[4] == ((result[0] + result[1] + result[2] + result[3]) & 0xFF)) { | ||||
|                     // Data valid, checksum succeeded...
 | ||||
|                     *humidity = result[0]; | ||||
|                     *temperature = result[2]; | ||||
|                     debug("Successfully retrieved sensor data..."); | ||||
|                     return true; | ||||
|                 } else { | ||||
|                     debug("Checksum failed, invalid data received from sensor..."); | ||||
|                 } | ||||
| 
 | ||||
|             } else { | ||||
|                 debug("Initialization error, problem in phase 'D'..."); | ||||
|             } | ||||
|         } else { | ||||
|             debug("Initialization error, problem in phase 'C'..."); | ||||
|         } | ||||
|     } else { | ||||
|         debug("Initialization error, problem in phase 'B'..."); | ||||
|     } | ||||
|      | ||||
|     taskEXIT_CRITICAL(); | ||||
|     // Step through Phase 'B', 40us
 | ||||
|     if (!dht_await_pin_state(pin, 40, false, NULL)) { | ||||
|         debug("Initialization error, problem in phase 'B'\n"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     // Step through Phase 'C', 88us
 | ||||
|     if (!dht_await_pin_state(pin, 88, true, NULL)) { | ||||
|         debug("Initialization error, problem in phase 'C'\n"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     // Step through Phase 'D', 88us
 | ||||
|     if (!dht_await_pin_state(pin, 88, false, NULL)) { | ||||
|         debug("Initialization error, problem in phase 'D'\n"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     // Read in each of the 40 bits of data...
 | ||||
|     for (int i = 0; i < DHT_DATA_BITS; i++) { | ||||
|         if (!dht_await_pin_state(pin, 65, true, &low_duration)) { | ||||
|             debug("LOW bit timeout\n"); | ||||
|             return false; | ||||
|         } | ||||
|         if (!dht_await_pin_state(pin, 75, false, &high_duration)){ | ||||
|             debug("HIGHT bit timeout\n"); | ||||
|             return false; | ||||
|         } | ||||
|         bits[i] = high_duration > low_duration; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Pack two data bytes into single value and take into account sign bit. | ||||
|  */ | ||||
| static inline int16_t dht_convert_data(uint8_t msb, uint8_t lsb) | ||||
| { | ||||
|     int16_t data; | ||||
| 
 | ||||
| #if DHT_TYPE == DHT22 | ||||
|     data = msb & 0x7F; | ||||
|     data <<= 8; | ||||
|     data |= lsb; | ||||
|     if (msb & BIT(15)) { | ||||
|         data = 0 - data;       // convert it to negative
 | ||||
|     } | ||||
| #elif DHT_TYPE == DHT11 | ||||
|     data = msb * 10; | ||||
| #else | ||||
| #error "Unsupported DHT type" | ||||
| #endif | ||||
| 
 | ||||
|     return data; | ||||
| } | ||||
| 
 | ||||
| bool dht_read_data(uint8_t pin, int16_t *humidity, int16_t *temperature) | ||||
| { | ||||
|     bool bits[DHT_DATA_BITS]; | ||||
|     uint8_t data[DHT_DATA_BITS/8] = {0}; | ||||
|     bool result; | ||||
| 
 | ||||
|     gpio_enable(pin, GPIO_OUT_OPEN_DRAIN); | ||||
| 
 | ||||
|     taskENTER_CRITICAL(); | ||||
|     result = dht_fetch_data(pin, bits); | ||||
|     taskEXIT_CRITICAL(); | ||||
| 
 | ||||
|     if (!result) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     for (uint8_t i = 0; i < DHT_DATA_BITS; i++) { | ||||
|         // Read each bit into 'result' byte array...
 | ||||
|         data[i/8] <<= 1; | ||||
|         data[i/8] |= bits[i]; | ||||
|     } | ||||
| 
 | ||||
|     if (data[4] != (data[0] + data[1] + data[2] + data[3])) { | ||||
|         debug("Checksum failed, invalid data received from sensor\n"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     *humidity = dht_convert_data(data[0], data[1]); | ||||
|     *temperature = dht_convert_data(data[2], data[3]); | ||||
| 
 | ||||
|     debug("Sensor data: humidity=%d, temp=%d\n", *humidity, *temperature); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool dht_read_float_data(uint8_t pin, float *humidity, float *temperature) | ||||
| { | ||||
|     int16_t i_humidity, i_temp; | ||||
| 
 | ||||
|     if (dht_read_data(pin, &i_humidity, &i_temp)) { | ||||
|         *humidity = (float)i_humidity / 10; | ||||
|         *temperature = (float)i_temp / 10; | ||||
|         return true; | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
|  |  | |||
|  | @ -5,13 +5,34 @@ | |||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __DTH_H__ | ||||
| #ifndef __DHT_H__ | ||||
| #define __DHT_H__ | ||||
| 
 | ||||
| #include "FreeRTOS.h" | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| bool dht_wait_for_pin_state(uint8_t pin, uint8_t interval, uint8_t timeout, bool expected_pin_sate, uint8_t * counter); | ||||
| bool dht_fetch_data(int8_t pin, int8_t * humidity, int8_t * temperature); | ||||
| #define DHT11       11 | ||||
| #define DHT22       22 | ||||
| 
 | ||||
| #endif | ||||
| // Type of sensor to use
 | ||||
| #define DHT_TYPE    DHT22 | ||||
| 
 | ||||
| /**
 | ||||
|  * Read data from sensor on specified pin. | ||||
|  * | ||||
|  * Humidity and temperature is returned as integers. | ||||
|  * For example: humidity=625 is 62.5 % | ||||
|  *              temperature=24.4 is 24.4 degrees Celsius | ||||
|  * | ||||
|  */ | ||||
| bool dht_read_data(uint8_t pin, int16_t *humidity, int16_t *temperature); | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|  * Float version of dht_read_data. | ||||
|  * | ||||
|  * Return values as floating point values. | ||||
|  */ | ||||
| bool dht_read_float_data(uint8_t pin, float *humidity, float *temperature); | ||||
| 
 | ||||
| #endif  // __DHT_H__
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue