Basics of Embedded Programming | DHT11 Driver Code for ESP32 Based on ESP-IDF (C Language, C++ Language)

Basics of Embedded Programming | DHT11 Driver Code for ESP32 Based on ESP-IDF (C Language, C++ Language)Basics of Embedded Programming | DHT11 Driver Code for ESP32 Based on ESP-IDF (C Language, C++ Language)01Introduction:

Let’s get straight to the point.

02Content

1. C Language Implementation

#include <stdio.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define DHT11_GPIO 4   // Use GPIO4
#define DHT_TIMEOUT 10000  // 10μs timeout

// Data storage structure
typedef struct {
    int humidity;
    int temperature;
    bool checksum_ok;
} dht11_data;

// Initialize GPIO
void dht11_init() {
    gpio_set_direction(DHT11_GPIO, GPIO_MODE_OUTPUT);
    gpio_set_level(DHT11_GPIO, 1);
}

// Read a single bit of data
static bool read_bit() {
    int count = 0;
    
    // Wait for 50μs low level
    while (gpio_get_level(DHT11_GPIO) == 0) {
        if (count++ > DHT_TIMEOUT) return false;
    }
    
    // Measure high level duration
    count = 0;
    while (gpio_get_level(DHT11_GPIO) == 1) {
        if (count++ > DHT_TIMEOUT) return false;
    }
    return (count > 40); // More than 40μs is 1, otherwise 0
}

// Read complete data packet
bool dht11_read(dht11_data *data) {
    uint8_t buffer[5] = {0};
    
    // Send start signal
    gpio_set_direction(DHT11_GPIO, GPIO_MODE_OUTPUT);
    gpio_set_level(DHT11_GPIO, 0);
    ets_delay_us(18000);  // Hold for at least 18ms
    gpio_set_level(DHT11_GPIO, 1);
    ets_delay_us(40);
    
    // Switch to input mode
    gpio_set_direction(DHT11_GPIO, GPIO_MODE_INPUT);
    
    // Wait for sensor response
    int count = 0;
    while (gpio_get_level(DHT11_GPIO) == 1) {
        if (count++ > DHT_TIMEOUT) return false;
    }
    
    // Read 40 bits of data
    for (int i=0; i<40; i++) {
        buffer[i/8] <<= 1;
        if (read_bit()) buffer[i/8] |= 1;
    }
    
    // Validate data
    data->humidity = buffer[0];
    data->temperature = buffer[2];
    data->checksum_ok = (buffer[4] == (buffer[0] + buffer[1] + buffer[2] + buffer[3]));
    
    return data->checksum_ok;
}

void app_main() {
    dht11_init();
    dht11_data sensor_data;
    
    while(1) {
        if(dht11_read(&sensor_data)) {
            printf("Humidity: %d%%, Temperature: %d℃\n", 
                  sensor_data.humidity, 
                  sensor_data.temperature);
        } else {
            printf("Sensor read failed\n");
        }
        vTaskDelay(2000 / portTICK_PERIOD_MS);  // 2 seconds interval
    }
}

2. C++ Implementation

#include <driver/gpio.h>
#include <esp_log.h>
#include <esp_timer.h>

class DHT11 {
private:
    gpio_num_t gpio_pin;
    static constexpr const char* TAG = "DHT11";

    // Microsecond precision delay
    void delay_us(uint64_t us) {
        uint64_t start = esp_timer_get_time();
        while (esp_timer_get_time() - start < us);
    }

    // Read a single bit
    bool readBit() {
        uint32_t count = 0;
        
        // Wait for low level to end (max 80μs)
        while (gpio_get_level(gpio_pin) == 0) {
            if (count++ > 100) return false; // Timeout protection
        }
        
        // Measure high level duration
        count = 0;
        uint64_t start = esp_timer_get_time();
        while (gpio_get_level(gpio_pin) == 1) {
            if (esp_timer_get_time() - start > 100) break; // Timeout protection
        }
        return (esp_timer_get_time() - start) > 40; // >40μs is 1
    }

public:
    struct SensorData {
        float temperature;
        float humidity;
        bool valid;
    };

    // Constructor initializes GPIO
    DHT11(gpio_num_t pin) : gpio_pin(pin) {
        gpio_reset_pin(gpio_pin);
        gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT);
        gpio_set_level(gpio_pin, 1);
        ESP_LOGI(TAG, "DHT11 initialized on GPIO%d", gpio_pin);
    }

    // Read sensor data
    SensorData readData() {
        uint8_t data[5] = {0};
        SensorData result = {.valid = false};

        // Send start signal
        gpio_set_direction(gpio_pin, GPIO_MODE_OUTPUT);
        gpio_set_level(gpio_pin, 0);
        delay_us(18000);  // 18ms low level
        gpio_set_level(gpio_pin, 1);
        delay_us(40);
        
        // Switch to input mode and wait for response
        gpio_set_direction(gpio_pin, GPIO_MODE_INPUT);
        delay_us(10);
        
        // Detect DHT response signal
        if (gpio_get_level(gpio_pin) != 0) {
            ESP_LOGE(TAG, "No response from sensor");
            return result;
        }
        
        // Read 40 bits of data
        for (int i = 0; i < 40; i++) {
            data[i/8] <<= 1;
            if (readBit()) data[i/8] |= 1;
        }
        
        // Validate data
        if (data[4] == (data[0] + data[1] + data[2] + data[3])) {
            result.humidity = data[0] + data[1] * 0.1f;
            result.temperature = data[2] + data[3] * 0.1f;
            result.valid = true;
        }
        return result;
    }
};

// Usage example
extern "C" void app_main() {
    DHT11 sensor(GPIO_NUM_4);
    
    while (1) {
        auto data = sensor.readData();
        if (data.valid) {
            ESP_LOGI("MAIN", "Humidity: %.1f%%, Temperature: %.1f℃", 
                    data.humidity, data.temperature);
        } else {
            ESP_LOGW("MAIN", "Invalid data");
        }
        vTaskDelay(pdMS_TO_TICKS(2000));
    }
}

03ConclusionBasics of Embedded Programming | DHT11 Driver Code for ESP32 Based on ESP-IDF (C Language, C++ Language)

Leave a Comment