ESP8266或ESP32使用ESP-IDF开发读取DHT12温度湿度

DHT12支持温度湿度读取,精度高于DHT11
DHT12支持单总线和I2C两种方式读取,在使用过程中, I2C通信时需要加上拉电阻, 这一点尤为重要

  • 以下代码在ESP8266_RTOS_SDK及ESP-IDF 3.x测试通过
  • 单总线通信方式也支持DHT11,只是精度下降
  • 设置管脚电平的函数可自行实现, 我这里是封装过的, 非常简单
  • 代码有点冗余, 还可以优化一下
/* dht12.h */
#ifndef DHT12_H
#define DHT12_H
#include "common.h"
#include "core.h"

int Dht12Init(sNormalMod* pMod);

void Dht12Thread(sNormalMod* pMod);

float TempGet(void);

float HumGet(void);

typedef struct {
    u8 State;
    float Hum;
    float Temp;
} sDht12Data;

sDht12Data Dht12DataGet(void);

#endif
/* dht12.c */
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "common.h"
#include "dht12.h"
#include "driver/i2c.h"
#include "driver/gpio.h"
#include "config.h"
#include "gpio.h"

#if CONFIG_BOARD_MODAL == BOARD_NODEMCU ||  CONFIG_BOARD_MODAL == BOARD_GOKIT3
#define DHT12_DATA_IO_NUM       5
#define READ_SDA() IoGet(DHT12_DATA_IO_NUM)
#define SEND_SDA(value) IoSet(DHT12_DATA_IO_NUM, value)
#elif CONFIG_BOARD_MODAL == BOARD_ESP32
#define DHT12_SDA_IO_NUM        18
#define DHT12_SCL_IO_NUM        19
#define CONFIG_DHT12_I2C_FREQ   100000
#endif

#define DHT12_OK                0
#define DHT12_ERROR_CHECKSUM    -10
#define DHT12_ERROR_CONNECT     -11
#define DHT12_MISSING_BYTES     -12
#define DHT12_ADDRESS           ((u8)0xB8)

#define MOD_TAG                 "DHT1X"

#if CONFIG_BOARD_MODAL == BOARD_NODEMCU || CONFIG_BOARD_MODAL == BOARD_GOKIT3
#define ENTER_CRITICAL() portENTER_CRITICAL()
#define EXIT_CRITICAL() portEXIT_CRITICAL()
#define delay_us ets_delay_us
#endif



static struct {
    float Temp;
    float Hum;
    u8 SensorAnswerFlag;
    u8 SensorErrorFlag;
} Dht12State;

static sDht12Data Dht12Data;

SemaphoreHandle_t   Lock;

sDht12Data Dht12DataGet(void)
{
    sDht12Data Temp;
    xSemaphoreTake(Lock, portMAX_DELAY);
    memcpy(&Temp, &Dht12Data, sizeof(Dht12Data));
    xSemaphoreGive(Lock);
    return Temp;
}


int Dht12Init(sNormalMod* pMod)
{

    int Ret = -1;

#if CONFIG_BOARD_MODAL == BOARD_NODEMCU || CONFIG_BOARD_MODAL == BOARD_GOKIT3
    Ret = CfgIo(DHT12_DATA_IO_NUM, GPIO_MODE_OUTPUT_OD, GPIO_PULLUP_ONLY, GPIO_INTR_DISABLE);
    if(Ret) {
        ESP_LOGE(MOD_TAG, "Set GPIO mode failed");
        return -1;
    }
    IoSet(DHT12_DATA_IO_NUM, 0);
    #ifdef DHT12_SCL_IO_NUM
    Ret = CfgIo(DHT12_SCL_IO_NUM, GPIO_MODE_OUTPUT_OD, GPIO_PULLUP_ONLY, GPIO_INTR_DISABLE);
    if(Ret) {
        ESP_LOGE(MOD_TAG, "Set GPIO mode failed");
        return -1;
    }
    IoSet(DHT12_SCL_IO_NUM, 0);
    #endif
#elif CONFIG_BOARD_MODAL == BOARD_ESP32

    i2c_config_t I2cConfig = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = DHT12_SDA_IO_NUM,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_io_num = DHT12_SCL_IO_NUM,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = CONFIG_DHT12_I2C_FREQ
    };

    Ret = i2c_param_config(I2C_NUM_1, &I2cConfig);

    if(Ret != ESP_OK) {
        ESP_LOGE(MOD_TAG, "I2C config failed");
        return -1;
    }

    Ret = i2c_driver_install(I2C_NUM_1, I2cConfig.mode, 0, 0, 0);

    if(Ret != ESP_OK) {
        ESP_LOGE(MOD_TAG, "I2C driver install failed");
        return -1;
    }

#endif

    Lock = xSemaphoreCreateMutex();
    if (!Lock) {
        return -1;
    }

    ESP_LOGW(MOD_TAG, "Inited.");
    
    return 0;
}


#if CONFIG_BOARD_MODAL == BOARD_NODEMCU || CONFIG_BOARD_MODAL == BOARD_GOKIT3
/* 单总线 */
u8 Dht12ReadByte(void)
{
    u16 j = 0;
    u8 data = 0, bit = 0;
    
    for(u8 i = 0; i < 8; i++) {
        // 检测上次低电平是否结束
        while(!READ_SDA()) {
            // 防止进入死循环
            if(++j>=50000) {
                break;
            }
        }
        // 延时Min=26us Max70us 跳过数据"0" 的高电平       
        delay_us(30);

        // 判断传感器发送数据位
        bit = READ_SDA();
        j = 0;
        // 等待高电平结束
        while(READ_SDA()) {
            // 防止进入死循环
            if(++j >= 50000) {
                break;
            }       
        }
        data <<= 1;
        data |= bit;
    }
    return data;
}
static esp_err_t Dht11Read()
{
    u32 j;
    u8 HumHigh, HumLow, TempHigh, TempLow, TempChecksum, Temp;

    // 进入临界区, 防止调度干扰数据读取
    ENTER_CRITICAL();

    SEND_SDA(0);    // 主机把数据总线(SDA)拉低
    delay_us(20000);    // 拉低一段时间(至少18ms), 通知传感器准备数据
    SEND_SDA(1);    // 释放总线
    delay_us(30);   // 延时30us

    Dht12State.SensorAnswerFlag = 0;
    // 判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行
    if(READ_SDA() == 0) {
        Dht12State.SensorAnswerFlag = 1;    //收到起始信号
        j = 0;
        // 判断从机发出 80us 的低电平响应信号是否结束 
        while((!READ_SDA())) {
            // 防止进入死循环
            if(++j >= 500) {
                Dht12State.SensorErrorFlag = 1;
                break;
            }
        }

        j = 0;
        // 判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
        while(READ_SDA()) {
            // 防止进入死循环
            if(++j >= 800) {
                Dht12State.SensorErrorFlag = 1;
                break;
            }
        }
        // 接收数据
        HumHigh = Dht12ReadByte();
        HumLow = Dht12ReadByte();
        TempHigh = Dht12ReadByte(); 
        TempLow = Dht12ReadByte();
        TempChecksum = Dht12ReadByte();
        EXIT_CRITICAL();

        // ets_printf("%02x", HumHigh);
        // ets_printf("%02x", HumLow);
        // ets_printf("%02x", TempHigh);
        // ets_printf("%02x", TempLow);
        // ets_printf("%02x", TempChecksum);

        Temp = (u8)(HumHigh + HumLow + TempHigh + TempLow);

        //如果校验成功,往下运行
        if(TempChecksum == Temp) {
            Dht12State.Hum = HumHigh * 10 + HumLow; //湿度
    
            // 为负温度
            if(TempLow & 0x80) {
                Dht12State.Temp = 0 - (TempHigh * 10 + ((TempLow & 0x7F)));
            }
            else {
                Dht12State.Temp = TempHigh * 10 + TempLow; //为正温度
            }
            // 判断数据是否超过量程(温度:-20℃~60℃,湿度20%RH~95%RH)
            if(Dht12State.Hum > 950) {
                Dht12State.Hum = 950;
            }
            if(Dht12State.Hum < 200) {
                Dht12State.Hum = 200;
            }
            if(Dht12State.Temp > 600) {
                Dht12State.Temp = 600;
            }
            if(Dht12State.Temp < -200) {
                Dht12State.Temp = -200;
            }
            Dht12State.Temp /= 10; // 计算为温度值
            Dht12State.Hum /= 10; // 计算为湿度值
            // ESP_LOGW(MOD_TAG, "TEMP:  %.2f", Dht12State.Temp);
            // ESP_LOGW(MOD_TAG, "HUM:   %.2f", Dht12State.Hum);
            Dht12Data.Temp = Dht12State.Temp;
            Dht12Data.Hum = Dht12State.Hum;
            Dht12Data.State = 0;
        }
        else {
            Dht12Data.State = 1;
            ESP_LOGE(MOD_TAG, "Checksum Error!");
        }
    }
    else {
        Dht12State.SensorErrorFlag = 0;  //未收到传感器响应
        Dht12Data.State = 2;
        ESP_LOGE(MOD_TAG, "Sensor Error!");
        return ESP_FAIL;
    }

    return ESP_OK;

}

#elif CONFIG_BOARD_MODAL == BOARD_ESP32
/* I2C */
static esp_err_t Dht11Read()
{
    int Ret = -1;
    u8 Buffer[10];
    memset(Buffer, 0, 10);
    i2c_cmd_handle_t I2cHandle = i2c_cmd_link_create();
    i2c_master_start(I2cHandle);
    i2c_master_write_byte(I2cHandle, (u8)0xB8, I2C_MASTER_ACK);
    i2c_master_write_byte(I2cHandle, (u8)0x0, I2C_MASTER_ACK);

    i2c_master_start(I2cHandle);
    i2c_master_write_byte(I2cHandle, (u8)0xB9, I2C_MASTER_ACK);
    i2c_master_read_byte(I2cHandle, &Buffer[0], I2C_MASTER_ACK);
    i2c_master_read_byte(I2cHandle, &Buffer[1], I2C_MASTER_ACK);
    i2c_master_read_byte(I2cHandle, &Buffer[2], I2C_MASTER_ACK);
    i2c_master_read_byte(I2cHandle, &Buffer[3], I2C_MASTER_ACK);
    i2c_master_read_byte(I2cHandle, &Buffer[4], I2C_MASTER_NACK);
    i2c_master_stop(I2cHandle);
    Ret = i2c_master_cmd_begin(I2C_NUM_1, I2cHandle, 100 / portTICK_RATE_MS);
    i2c_cmd_link_delete(I2cHandle);

    if(Ret != ESP_OK) {
        Dht12Data.State = 1;
        ESP_LOGE(MOD_TAG, "Data was not vaild");
        return -1;
    }

    u8 Checksum = Buffer[0] + Buffer[1] + Buffer[2] + Buffer[3];
    if (Buffer[4] != Checksum) {
        Dht12Data.State = 1;
        ESP_LOGE(MOD_TAG, "Data was not vaild");
        return -1;
    } else {
        Dht12State.Hum = Buffer[0] + Buffer[1] * 0.1;
        Dht12State.Temp = Buffer[2] + (Buffer[3] & 0x7F) * 0.1;
        if (Buffer[4] & 0x80) {
            Dht12State.Temp = -Dht12State.Temp;
        }
        Dht12Data.State = 0;
        Dht12Data.Temp = Dht12State.Temp;
        Dht12Data.Hum = Dht12State.Hum;
        return 0;
    }
}
#endif

void Dht12Thread(sNormalMod* pMod)
{   
    int Ret = 0;
    while(1) {
        vTaskDelay(5000 / portTICK_RATE_MS);
        xSemaphoreTake(Lock, portMAX_DELAY);
        Ret = Dht11Read();
        xSemaphoreGive(Lock);
        if (Ret != ESP_OK) {
            ESP_LOGE(MOD_TAG, "Dht11 data was not vaild");
        } else {
            ESP_LOGI(MOD_TAG, "Hum: %.2f, Temp: %.2f", Dht12State.Hum, Dht12State.Temp);
        }
        
    }
}

猜你喜欢

转载自www.cnblogs.com/rootming/p/10854243.html