Skip to content

DHT11 CODE

Component Architecture

- driver
    - mpu6050
        - include
            - mpu6050.h
        - mpu6050.c
        - CMakeLists.txt

driver/rng/CMakeLists.txt

set(src_dirs
    .
)

set(include_dirs
    include
)

set(requires
    driver
    unity
    i2c
)

idf_component_register(SRC_DIRS ${src_dirs} INCLUDE_DIRS ${include_dirs} REQUIRES ${requires})

dht.h

/**
   Copyright 2024 Achim Pieters | StudioPieters®

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   for more information visit https://www.studiopieters.nl
 **/

 #ifndef __DHT_H__
 #define __DHT_H__

 #include <driver/gpio.h>
 #include <esp_err.h>

 #ifdef __cplusplus
 extern "C" {
 #endif

 typedef enum
 {
         DHT_TYPE_DHT11 = 0,
         DHT_TYPE_AM2301,
         DHT_TYPE_SI7021
 } dht_sensor_type_t;

 esp_err_t dht_read_data(dht_sensor_type_t sensor_type, gpio_num_t pin, int16_t *humidity, int16_t *temperature);
 esp_err_t dht_read_float_data(dht_sensor_type_t sensor_type, gpio_num_t pin, float *humidity, float *temperature);

 #ifdef __cplusplus
 }
 #endif

 #endif  // __DHT_H__

dht.c

/**
   Copyright 2024 Achim Pieters | StudioPieters®

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

   for more information visit https://www.studiopieters.nl
 **/

 #include "dht.h"

 #include <freertos/FreeRTOS.h>
 #include <freertos/task.h>
 #include <string.h>
 #include <esp_log.h>
 #include <esp_rom_sys.h>
 #include <driver/gpio.h>

// DHT timer precision in microseconds
 #define DHT_TIMER_INTERVAL 2
 #define DHT_DATA_BITS 40
 #define DHT_DATA_BYTES (DHT_DATA_BITS / 8)

static const char *TAG = "dht";

static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
 #define PORT_ENTER_CRITICAL() portENTER_CRITICAL(&mux)
 #define PORT_EXIT_CRITICAL() portEXIT_CRITICAL(&mux)

 #define CHECK_ARG(VAL) do { if (!(VAL)) return ESP_ERR_INVALID_ARG; } while (0)

 #define CHECK_LOGE(x, msg, ...) do { \
                esp_err_t __err = (x); \
                if (__err != ESP_OK) { \
                        PORT_EXIT_CRITICAL(); \
                        ESP_LOGE(TAG, msg, ## __VA_ARGS__); \
                        return __err; \
                } \
} while (0)

static esp_err_t dht_await_pin_state(gpio_num_t pin, uint32_t timeout, int expected_pin_state, uint32_t *duration)
{
        gpio_set_direction(pin, GPIO_MODE_INPUT);
        for (uint32_t i = 0; i < timeout; i += DHT_TIMER_INTERVAL)
        {
                esp_rom_delay_us(DHT_TIMER_INTERVAL);
                if (gpio_get_level(pin) == expected_pin_state)
                {
                        if (duration) *duration = i;
                        return ESP_OK;
                }
        }
        return ESP_ERR_TIMEOUT;
}

static esp_err_t dht_fetch_data(dht_sensor_type_t sensor_type, gpio_num_t pin, uint8_t data[DHT_DATA_BYTES])
{
        uint32_t low_duration, high_duration;

        gpio_set_direction(pin, GPIO_MODE_OUTPUT_OD);
        gpio_set_level(pin, 0);
        esp_rom_delay_us(sensor_type == DHT_TYPE_SI7021 ? 500 : 20000);
        gpio_set_level(pin, 1);

        CHECK_LOGE(dht_await_pin_state(pin, 40, 0, NULL), "Phase 'B' timeout");
        CHECK_LOGE(dht_await_pin_state(pin, 88, 1, NULL), "Phase 'C' timeout");
        CHECK_LOGE(dht_await_pin_state(pin, 88, 0, NULL), "Phase 'D' timeout");

        for (int i = 0; i < DHT_DATA_BITS; i++)
        {
                CHECK_LOGE(dht_await_pin_state(pin, 65, 1, &low_duration), "Low duration timeout");
                CHECK_LOGE(dht_await_pin_state(pin, 75, 0, &high_duration), "High duration timeout");

                uint8_t byte_index = i / 8;
                uint8_t bit_index = i % 8;
                if (!bit_index) data[byte_index] = 0;

                data[byte_index] |= (high_duration > low_duration) << (7 - bit_index);
        }

        return ESP_OK;
}

static inline int16_t dht_convert_data(dht_sensor_type_t sensor_type, uint8_t msb, uint8_t lsb)
{
        int16_t result;
        if (sensor_type == DHT_TYPE_DHT11)
        {
                result = msb * 10;
        }
        else
        {
                result = (msb & 0x7F) << 8 | lsb;
                if (msb & 0x80) result = -result;
        }
        return result;
}

esp_err_t dht_read_data(dht_sensor_type_t sensor_type, gpio_num_t pin, int16_t *humidity, int16_t *temperature)
{
        CHECK_ARG(humidity || temperature);

        uint8_t data[DHT_DATA_BYTES] = { 0 };

        gpio_set_direction(pin, GPIO_MODE_OUTPUT_OD);
        gpio_set_level(pin, 1);

        PORT_ENTER_CRITICAL();
        esp_err_t result = dht_fetch_data(sensor_type, pin, data);
        PORT_EXIT_CRITICAL();

        gpio_set_direction(pin, GPIO_MODE_OUTPUT_OD);
        gpio_set_level(pin, 1);

        if (result != ESP_OK) return result;

        if (data[4] != ((data[0] + data[1] + data[2] + data[3]) & 0xFF))
        {
                ESP_LOGE(TAG, "Checksum failed");
                return ESP_ERR_INVALID_CRC;
        }

        if (humidity) *humidity = dht_convert_data(sensor_type, data[0], data[1]);
        if (temperature) *temperature = dht_convert_data(sensor_type, data[2], data[3]);

        ESP_LOGD(TAG, "Humidity: %d, Temperature: %d", *humidity, *temperature);

        return ESP_OK;
}

esp_err_t dht_read_float_data(dht_sensor_type_t sensor_type, gpio_num_t pin, float *humidity, float *temperature)
{
        CHECK_ARG(humidity || temperature);

        int16_t int_humidity, int_temperature;
        esp_err_t result = dht_read_data(sensor_type, pin, humidity ? &int_humidity : NULL, temperature ? &int_temperature : NULL);
        if (result != ESP_OK) return result;

        if (humidity) *humidity = int_humidity / 10.0f;
        if (temperature) *temperature = int_temperature / 10.0f;

        return ESP_OK;
}

main.cpp

/**
 * @file main.c
 * @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg)
 * @brief 
 * @version 1.0
 * @date 2024-11-17
 * 
 * @copyright Copyright (c) 2024
 * 
 */

/* DEPENDENCIES */
// ESP
#include "esp_system.h" // ESP32 System
#include "nvs_flash.h"  // ESP32 NVS
#include "esp_chip_info.h" // ESP32 Chip Info
#include "esp_psram.h" // ESP32 PSRAM
#include "esp_flash.h" // ESP32 Flash
#include "esp_log.h" // ESP32 Logging

// BSP
#include "led.h"
#include "exit.h"
#include "spi.h"
#include "lcd.h"
#include "tim.h"
#include "esp_rtc.h"
#include "spi_sdcard.h"
#include "wifi_wpa2_enterprise.h"
#include "mqtt.h"
#include "dht.h"

/* Variables */
const char *TAG = "NEXNODE";

extern "C" void app_main();
/**
 * @brief Entry point of the program
 * @param None
 * @retval None
 */
void app_main()
{
    esp_err_t ret;
    uint32_t flash_size;
    esp_chip_info_t chip_info;

    char mqtt_pub_buff[64];
    int count = 0;

    // DHT SENSOR
    dht_sensor_type_t sensor_type;
    sensor_type = DHT_TYPE_DHT11;
    gpio_num_t gpio_num = (gpio_num_t)6;

    // Initialize NVS
    ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase()); // Erase if needed
        ret = nvs_flash_init();
    }

    // Get FLASH size
    esp_flash_get_size(NULL, &flash_size);
    esp_chip_info(&chip_info);

    // Display CPU core count
    printf("CPU Cores: %d\n", chip_info.cores);

    // Display FLASH size
    printf("Flash size: %ld MB flash\n", flash_size / (1024 * 1024));

    // Display PSRAM size
    printf("PSRAM size: %d bytes\n", esp_psram_get_size());

    // BSP Initialization
    led_init();
    exit_init();
    spi2_init();
    lcd_init();

    // spiffs_test();                                                  /* Run SPIFFS test */
    while (sd_card_init())                               /* SD card not detected */
    {
        lcd_show_string(0, 0, 200, 16, 16, "SD Card Error!", RED);
        vTaskDelay(500);
        lcd_show_string(0, 20, 200, 16, 16, "Please Check!", RED);
        vTaskDelay(500);
    }

    // clean the screen
    lcd_clear(WHITE);

    lcd_show_string(0, 0, 200, 16, 16, "SD Initialized!", RED);

    sd_card_test_filesystem();                                        /* Run SD card test */

    lcd_show_string(0, 0, 200, 16, 16, "SD Tested CSW! ", RED);

    // sd_card_unmount();

    vTaskDelay(3000);

    lcd_show_string(0, 0, lcd_self.width, 16, 16, "WiFi STA Test  ", RED);

    ret = wifi_sta_wpa2_init();
    if(ret == ESP_OK)
    {
        ESP_LOGI(TAG_WIFI, "WiFi STA Init OK");
        lcd_show_string(0, 0, lcd_self.width, 16, 16, "WiFi STA Test OK", RED);
    }
    else
    {
        ESP_LOGE(TAG_WIFI, "WiFi STA Init Failed");
    }

    // only when the ip is obtained, start mqtt
    EventBits_t ev = 0;
    ev = xEventGroupWaitBits(wifi_event_group,CONNECTED_BIT,pdTRUE,pdFALSE,portMAX_DELAY);
    if(ev & CONNECTED_BIT)
    {
        mqtt_app_start();
    }

    // DHT
    gpio_pullup_en(gpio_num);

    while (true)
    {
        float humidity = 0, temperature = 0;
        esp_err_t result = dht_read_float_data(sensor_type, gpio_num, &humidity, &temperature);
        if (result == ESP_OK)
        {
            ESP_LOGI(TAG, "Humidity: %.1f%% Temperature: %.1f°C", humidity, temperature);
            char mqtt_msg[128];
            snprintf(mqtt_msg, sizeof(mqtt_msg), "{\"temperature\":%.1f,\"humidity\":%.1f}", temperature, humidity);
            if (s_is_mqtt_connected)
            {
                esp_mqtt_client_publish(s_mqtt_client, MQTT_PUBLIC_TOPIC, mqtt_msg, strlen(mqtt_msg), 1, 0);
            }
        }
        else
        {
            ESP_LOGE(TAG, "Failed to read sensor data: %s", esp_err_to_name(result));
        }
        vTaskDelay(pdMS_TO_TICKS(2000)); // Delay for 2 seconds
    }

}