feat: Adiciona suporte para sensor de temperatura e umidade DHT11 com integração Zigbee
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
/* DHT11 Temperature and Humidity Sensor Driver Implementation */
|
||||
|
||||
#include "dht11_driver.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
static const char *TAG = "DHT11";
|
||||
|
||||
static gpio_num_t dht_gpio;
|
||||
static int64_t last_read_time = -2000000; // Inicializa para permitir primeira leitura
|
||||
|
||||
/* Timeout para espera de resposta (em microsegundos) */
|
||||
#define DHT11_TIMEOUT_US 85
|
||||
|
||||
/* Tempo mínimo entre leituras (1 segundo) */
|
||||
#define DHT11_MIN_INTERVAL_US 1000000
|
||||
|
||||
/**
|
||||
* @brief Espera o pino mudar para o nível especificado
|
||||
*
|
||||
* @param level Nível esperado (0 ou 1)
|
||||
* @param timeout_us Timeout em microsegundos
|
||||
* @return Tempo de espera em us, ou -1 se timeout
|
||||
*/
|
||||
static int dht11_wait_for_level(int level, int timeout_us)
|
||||
{
|
||||
int elapsed = 0;
|
||||
|
||||
while (gpio_get_level(dht_gpio) != level) {
|
||||
if (elapsed++ > timeout_us) {
|
||||
return -1;
|
||||
}
|
||||
ets_delay_us(1);
|
||||
}
|
||||
|
||||
return elapsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Envia sinal de start para o DHT11
|
||||
*/
|
||||
static esp_err_t dht11_send_start_signal(void)
|
||||
{
|
||||
/* Configura GPIO como saída */
|
||||
gpio_set_direction(dht_gpio, GPIO_MODE_OUTPUT_OD);
|
||||
|
||||
/* Envia sinal de start: LOW por 18ms */
|
||||
gpio_set_level(dht_gpio, 0);
|
||||
ets_delay_us(20000); // 20ms para garantir
|
||||
|
||||
/* Libera o barramento (pull-up externo fará HIGH) */
|
||||
gpio_set_level(dht_gpio, 1);
|
||||
ets_delay_us(40);
|
||||
|
||||
/* Configura GPIO como entrada */
|
||||
gpio_set_direction(dht_gpio, GPIO_MODE_INPUT);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Lê 1 byte de dados do DHT11
|
||||
*/
|
||||
static uint8_t dht11_read_byte(void)
|
||||
{
|
||||
uint8_t byte = 0;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
/* Espera sinal LOW (início do bit) */
|
||||
if (dht11_wait_for_level(0, DHT11_TIMEOUT_US) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Espera sinal HIGH (duração determina bit 0 ou 1) */
|
||||
if (dht11_wait_for_level(1, DHT11_TIMEOUT_US) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Mede duração do HIGH */
|
||||
ets_delay_us(30);
|
||||
|
||||
/* Se ainda HIGH após 30us, é bit 1, senão é bit 0 */
|
||||
if (gpio_get_level(dht_gpio) == 1) {
|
||||
byte |= (1 << (7 - i));
|
||||
}
|
||||
}
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
esp_err_t dht11_init(gpio_num_t gpio_num)
|
||||
{
|
||||
dht_gpio = gpio_num;
|
||||
|
||||
/* Configura GPIO com pull-up */
|
||||
gpio_config_t io_conf = {
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pin_bit_mask = (1ULL << dht_gpio),
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
};
|
||||
|
||||
esp_err_t ret = gpio_config(&io_conf);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to configure GPIO %d", dht_gpio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "DHT11 initialized on GPIO %d", dht_gpio);
|
||||
|
||||
/* Aguarda sensor estabilizar (1 segundo) */
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dht11_read(dht11_reading_t *reading)
|
||||
{
|
||||
if (reading == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* Inicializa leitura como inválida */
|
||||
reading->valid = false;
|
||||
reading->temperature = 0.0f;
|
||||
reading->humidity = 0.0f;
|
||||
|
||||
/* Verifica intervalo mínimo entre leituras */
|
||||
int64_t current_time = esp_timer_get_time();
|
||||
if ((current_time - last_read_time) < DHT11_MIN_INTERVAL_US) {
|
||||
ESP_LOGW(TAG, "Read too soon, wait at least 1 second between reads");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
/* Desabilita interrupções temporariamente para timing preciso */
|
||||
portDISABLE_INTERRUPTS();
|
||||
|
||||
/* Envia sinal de start */
|
||||
dht11_send_start_signal();
|
||||
|
||||
/* Espera resposta do sensor (LOW por 80us) */
|
||||
if (dht11_wait_for_level(0, DHT11_TIMEOUT_US) < 0) {
|
||||
portENABLE_INTERRUPTS();
|
||||
ESP_LOGE(TAG, "Timeout waiting for response LOW");
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
/* Espera HIGH de resposta (80us) */
|
||||
if (dht11_wait_for_level(1, DHT11_TIMEOUT_US) < 0) {
|
||||
portENABLE_INTERRUPTS();
|
||||
ESP_LOGE(TAG, "Timeout waiting for response HIGH");
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
/* Espera início dos dados (LOW) */
|
||||
if (dht11_wait_for_level(0, DHT11_TIMEOUT_US) < 0) {
|
||||
portENABLE_INTERRUPTS();
|
||||
ESP_LOGE(TAG, "Timeout waiting for data start");
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
/* Lê 5 bytes de dados (umidade_int, umidade_dec, temp_int, temp_dec, checksum) */
|
||||
uint8_t data[5] = {0};
|
||||
for (int i = 0; i < 5; i++) {
|
||||
data[i] = dht11_read_byte();
|
||||
}
|
||||
|
||||
portENABLE_INTERRUPTS();
|
||||
|
||||
/* Atualiza timestamp da última leitura */
|
||||
last_read_time = esp_timer_get_time();
|
||||
|
||||
/* Verifica checksum */
|
||||
uint8_t checksum = data[0] + data[1] + data[2] + data[3];
|
||||
if (checksum != data[4]) {
|
||||
ESP_LOGE(TAG, "Checksum error: calculated=0x%02X, received=0x%02X",
|
||||
checksum, data[4]);
|
||||
return ESP_ERR_INVALID_CRC;
|
||||
}
|
||||
|
||||
/* DHT11 retorna valores inteiros (sem parte decimal) */
|
||||
reading->humidity = (float)data[0];
|
||||
reading->temperature = (float)data[2];
|
||||
reading->valid = true;
|
||||
|
||||
ESP_LOGI(TAG, "Temperature: %.1f°C, Humidity: %.1f%%",
|
||||
reading->temperature, reading->humidity);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t dht11_read_temperature(float *temperature)
|
||||
{
|
||||
dht11_reading_t reading;
|
||||
esp_err_t ret = dht11_read(&reading);
|
||||
|
||||
if (ret == ESP_OK && reading.valid) {
|
||||
*temperature = reading.temperature;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t dht11_read_humidity(float *humidity)
|
||||
{
|
||||
dht11_reading_t reading;
|
||||
esp_err_t ret = dht11_read(&reading);
|
||||
|
||||
if (ret == ESP_OK && reading.valid) {
|
||||
*humidity = reading.humidity;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user