#include "dht22_sensor.h" #include "esp_log.h" #include "esp_rom_sys.h" #include "freertos/FreeRTOS.h" #include "freertos/portmacro.h" #include static const char *TAG = "DHT22_SENSOR"; // Default DHT22 timing constants (microseconds) #define DHT22_DEFAULT_START_SIGNAL_US 18000 // 18ms start signal #define DHT22_DEFAULT_RESPONSE_TIMEOUT_US 500 // 500us timeout for response #define DHT22_DEFAULT_DATA_TIMEOUT_US 150 // 150us timeout for data bits #define DHT22_DEFAULT_BIT_THRESHOLD_US 40 // Threshold for 0/1 detection // Global configuration static dht22_config_t current_config = {0}; static bool is_initialized = false; // Internal function to read from DHT22 static dht22_result_t dht22_read_internal(int gpio_pin, float *temperature, float *humidity, const dht22_config_t *config); esp_err_t dht22_init(int gpio_pin) { dht22_config_t default_config = { .gpio_pin = gpio_pin, .start_signal_us = DHT22_DEFAULT_START_SIGNAL_US, .response_timeout_us = DHT22_DEFAULT_RESPONSE_TIMEOUT_US, .data_timeout_us = DHT22_DEFAULT_DATA_TIMEOUT_US, .bit_threshold_us = DHT22_DEFAULT_BIT_THRESHOLD_US}; return dht22_init_with_config(&default_config); } esp_err_t dht22_init_with_config(const dht22_config_t *config) { if (config == NULL) { ESP_LOGE(TAG, "DHT22 config cannot be NULL"); return ESP_ERR_INVALID_ARG; } if (config->gpio_pin < 0) { ESP_LOGE(TAG, "Invalid GPIO pin: %d", config->gpio_pin); return ESP_ERR_INVALID_ARG; } ESP_LOGI(TAG, "Initializing DHT22 on GPIO %d", config->gpio_pin); // Store configuration memcpy(¤t_config, config, sizeof(dht22_config_t)); is_initialized = true; ESP_LOGI(TAG, "DHT22 initialized successfully"); return ESP_OK; } dht22_result_t dht22_read(float *temperature, float *humidity) { if (!is_initialized) { ESP_LOGE(TAG, "DHT22 not initialized"); return DHT22_TIMEOUT_ERROR; } return dht22_read_internal(current_config.gpio_pin, temperature, humidity, ¤t_config); } dht22_result_t dht22_read_data(dht22_data_t *data) { if (data == NULL) { ESP_LOGE(TAG, "DHT22 data pointer cannot be NULL"); return DHT22_TIMEOUT_ERROR; } return dht22_read(&data->temperature, &data->humidity); } dht22_result_t dht22_read_from_pin(int gpio_pin, float *temperature, float *humidity) { dht22_config_t temp_config = { .gpio_pin = gpio_pin, .start_signal_us = DHT22_DEFAULT_START_SIGNAL_US, .response_timeout_us = DHT22_DEFAULT_RESPONSE_TIMEOUT_US, .data_timeout_us = DHT22_DEFAULT_DATA_TIMEOUT_US, .bit_threshold_us = DHT22_DEFAULT_BIT_THRESHOLD_US}; return dht22_read_internal(gpio_pin, temperature, humidity, &temp_config); } static dht22_result_t dht22_read_internal(int gpio_pin, float *temperature, float *humidity, const dht22_config_t *config) { if (temperature == NULL || humidity == NULL) { ESP_LOGE(TAG, "Temperature and humidity pointers cannot be NULL"); return DHT22_TIMEOUT_ERROR; } uint8_t data[5] = {0}; int counter = 0; ESP_LOGD(TAG, "Reading DHT22 from GPIO %d", gpio_pin); // Disable interrupts during critical timing portDISABLE_INTERRUPTS(); // Configure GPIO gpio_config_t io_conf = { .pin_bit_mask = (1ULL << gpio_pin), .mode = GPIO_MODE_OUTPUT_OD, .pull_up_en = GPIO_PULLUP_ENABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE, .intr_type = GPIO_INTR_DISABLE, }; gpio_config(&io_conf); // Send start signal gpio_set_level(gpio_pin, 0); esp_rom_delay_us(config->start_signal_us); gpio_set_level(gpio_pin, 1); esp_rom_delay_us(40); // Switch to input mode io_conf.mode = GPIO_MODE_INPUT; gpio_config(&io_conf); // Wait for DHT22 response (should go low then high) counter = 0; while (gpio_get_level(gpio_pin) == 1) { esp_rom_delay_us(1); if (++counter > config->response_timeout_us) { portENABLE_INTERRUPTS(); ESP_LOGD(TAG, "DHT22 timeout waiting for initial response"); return DHT22_TIMEOUT_ERROR; } } // Wait for response signal to go high counter = 0; while (gpio_get_level(gpio_pin) == 0) { esp_rom_delay_us(1); if (++counter > config->response_timeout_us) { portENABLE_INTERRUPTS(); ESP_LOGD(TAG, "DHT22 timeout waiting for response high"); return DHT22_TIMEOUT_ERROR; } } // Wait for response signal to go low (start of data) counter = 0; while (gpio_get_level(gpio_pin) == 1) { esp_rom_delay_us(1); if (++counter > config->response_timeout_us) { portENABLE_INTERRUPTS(); ESP_LOGD(TAG, "DHT22 timeout waiting for data start"); return DHT22_TIMEOUT_ERROR; } } // Read 40 bits of data for (int i = 0; i < 40; i++) { // Wait for signal to go high counter = 0; while (gpio_get_level(gpio_pin) == 0) { esp_rom_delay_us(1); if (++counter > config->data_timeout_us) { portENABLE_INTERRUPTS(); ESP_LOGD(TAG, "DHT22 timeout waiting for bit %d high signal", i); return DHT22_TIMEOUT_ERROR; } } // Measure high pulse duration counter = 0; while (gpio_get_level(gpio_pin) == 1) { esp_rom_delay_us(1); if (++counter > config->data_timeout_us) { portENABLE_INTERRUPTS(); ESP_LOGD(TAG, "DHT22 timeout during bit %d high pulse", i); return DHT22_TIMEOUT_ERROR; } } // DHT22 protocol: '0' = ~26-28us high, '1' = ~70us high data[i / 8] <<= 1; if (counter > config->bit_threshold_us) { data[i / 8] |= 1; } // Debug first few bits if we're getting all zeros if (i < 8) { ESP_LOGD(TAG, "Bit %d: pulse=%dus, value=%d", i, counter, (counter > config->bit_threshold_us) ? 1 : 0); } } // Re-enable interrupts portENABLE_INTERRUPTS(); // Verify checksum uint8_t checksum = data[0] + data[1] + data[2] + data[3]; // Debug output for problematic readings if ((data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 0) || checksum != data[4]) { ESP_LOGD(TAG, "DHT22 raw data: %02X %02X %02X %02X %02X", data[0], data[1], data[2], data[3], data[4]); ESP_LOGD(TAG, "Calculated checksum: %02X, Received: %02X", checksum, data[4]); } if (checksum != data[4]) { ESP_LOGD(TAG, "DHT22 checksum mismatch"); return DHT22_CHECKSUM_ERROR; } // Check for all-zero data (sensor not responding properly) if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] == 0) { ESP_LOGD(TAG, "DHT22 returned all zeros - sensor may not be connected"); return DHT22_TIMEOUT_ERROR; // Treat as timeout to trigger retry } // Convert data to temperature and humidity *humidity = ((data[0] << 8) | data[1]) / 10.0f; int temp_raw = (data[2] << 8) | data[3]; if (temp_raw & 0x8000) { *temperature = -(temp_raw & 0x7FFF) / 10.0f; } else { *temperature = temp_raw / 10.0f; } ESP_LOGD(TAG, "DHT22 read successful: T=%.2f°C, H=%.2f%%", *temperature, *humidity); return DHT22_OK; } const char *dht22_get_error_string(dht22_result_t result) { switch (result) { case DHT22_OK: return "Success"; case DHT22_TIMEOUT_ERROR: return "Timeout error"; case DHT22_CHECKSUM_ERROR: return "Checksum error"; default: return "Unknown error"; } } bool dht22_test_connection(void) { if (!is_initialized) { ESP_LOGW(TAG, "DHT22 not initialized for connection test"); return false; } float temp, humid; dht22_result_t result = dht22_read(&temp, &humid); if (result == DHT22_OK) { ESP_LOGI(TAG, "DHT22 connection test successful: T=%.2f°C, H=%.2f%%", temp, humid); return true; } else { ESP_LOGW(TAG, "DHT22 connection test failed: %s", dht22_get_error_string(result)); return false; } } esp_err_t dht22_deinit(void) { if (!is_initialized) { ESP_LOGW(TAG, "DHT22 not initialized"); return ESP_OK; } ESP_LOGI(TAG, "Deinitializing DHT22 sensor"); is_initialized = false; memset(¤t_config, 0, sizeof(dht22_config_t)); ESP_LOGI(TAG, "DHT22 sensor deinitialized"); return ESP_OK; }