博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ESP8266或ESP32使用ESP-IDF开发读取DHT12温度湿度
阅读量:4573 次
发布时间:2019-06-08

本文共 8626 字,大约阅读时间需要 28 分钟。

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#endifstatic 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;    }}#endifvoid 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);        }            }}

转载于:https://www.cnblogs.com/rootming/p/10854243.html

你可能感兴趣的文章
五 搭建kafka集群
查看>>
Linux 内核即插即用规范
查看>>
【规范】javascript 变量命名规则
查看>>
数据适配 DataAdapter对象
查看>>
有序列表ol和定义列表dl,dt,dd
查看>>
联想小新Air 15 安装黑苹果macOS High Sierra 10.13.6过程
查看>>
公共POI导出Excel方法–java
查看>>
次短路——Dijkstra
查看>>
C++ compile issue
查看>>
安卓中的shape
查看>>
站立会议总结08
查看>>
C++ stat判断路径是文件还是目录
查看>>
动态代理
查看>>
ie11下,接受postmessage返回的信息
查看>>
阶段1 语言基础+高级_1-3-Java语言高级_02-继承与多态_第1节 继承_13-Java继承的三个特点...
查看>>
中小企业实施OA的意义
查看>>
es6 数组
查看>>
JS判断是否在微信浏览器打开
查看>>
javascript中typeof和instanceof的区别
查看>>
数据结构-数组1
查看>>