【硬件模块】DHT11数字式温湿度传感器模块

前言

今天在这边新开一个系列,那就是硬件模块。

后续会把之前写过的硬件模块再写一遍,因为之前都是使用的STM32来驱动模块的,而现在我快速上手ESP32系列也快结束了,因此我在原本文章的基础上再加上使用ESP32来驱动的部分构成硬件模块这个系列。

当然了,也不是吃老本的,这个系列也会写一些之前都没用过的模块,今天就先以DHT11这个之前都没写过的模块来开个头。

DHT11

DHT11是一款数字式温湿度传感器,它采用了已校准的数字信号输出方式,使得测量结果更加准确可靠。该传感器集成了温度测量、湿度测量和数字信号输出等功能,可以实时监测环境的温度和湿度变化。

DHT11传感器内部包含一个湿度检测电容和一个NTC温度测量元件,以及一个高性能的8位微控制器来处理信号。当传感器暴露在环境中时,温度传感器和湿度传感器能够感知到环境的温度和湿度,并将其转换为电信号。随后,微控制器将这些电信号转换为数字信号,并通过单总线通信协议输出给微处理器。

DHT11传感器具有多种优点。首先,它采用数字信号输出,使得读取数据变得简单方便,只需通过一根数据线即可完成温湿度读取。其次,DHT11的价格相对较低,适合大规模应用和低成本项目。此外,它还支持多种平台和开发板,如Arduino、Raspberry Pi等,可以广泛应用于各种嵌入式系统和物联网设备。

然而,DHT11传感器也存在一些缺点。首先,其精度相对较低,温度精度为±2°C,湿度精度为±5%RH,可能无法满足一些高精度测量的需求。其次,DHT11的响应时间较慢,通常需要2秒以上才能完成一次温湿度测量。此外,其测量范围也有限制,温度测量范围为0°C~50°C,湿度测量范围为20%~90%RH。

在实际应用中,DHT11传感器常用于室内环境监测、气象站和气象监测、温湿度控制系统以及物联网项目等领域。例如,在家庭、办公室、实验室等室内环境中,DHT11可以帮助维持舒适的生活和工作环境,并及时采取调节措施。在构建小型气象站时,DHT11可用于监测当地的温度和湿度,为农业、气象学研究以及天气预报等提供重要数据。同时,在温室、温室大棚和养殖场等环境中,DHT11传感器可以实现温湿度的自动控制,提供适宜的环境条件。此外,在物联网项目中,DHT11也是常用的传感器之一,可以实时监测和传输温湿度数据。

综上所述,DHT11是一款功能强大、简单易用且成本较低的温湿度传感器,适用于多种应用场景。然而,在选择使用时需要根据具体需求考虑其精度、响应时间以及测量范围等因素。

以上介绍来自文心一言。

简单来说就是DHT11这个温湿度传感器相当便宜,但是代价就是精度很差。

引脚

其中1号引脚是VCC,2号引脚是数据线,3号引脚没有用,4号引脚是GND。

供电电压的范围是3.3~5.5V

使用的通信协议是1-Wire,所以只需要2号引脚一根数据线即可。

时序

第一步是DHT11上电后需要等待1s,然后处于一个上拉输入的状态。

对于我们的单片机(主机)来说,我们要做的就是等DHT11一秒钟,其他不用操作。

第二步就是我们主机发送起始信号告诉DHT11开始采集数据了。

我们先拉低数据线18~30ms,可以拉个20ms。

之后再拉高延时一会等待DTH11反应,然后改为上拉输入模式。

第三步是DHT11收到信号之后等待数据线的低电平结束后会再拉低数据线83us表示收到,然后再拉高数据线87us通知我们的主机接收数据。

对于我们主机来说,我们发送完上面的起始信号检测数据线是不是被拉低了,如果是,那么我们再等待数据线拉高回去。

DHT11一共会发送40位数据,这40位数据分别代表什么含义这个稍后再说。

我们先看看数据0和1的区别,它们一开始都是拉低54us,不一样的是数据0后面拉高23~27us,而数据1后面拉高了66~74us。

也就是说不管是什么数据,都是先拉低后拉高,不一样的是后面拉高的持续时间。

因此我们可以先等待数据线拉高,拉高之后延时30us,如果是数据0,那么我们读出的将会是低电平,如果是数据1,那么我们读出的是高电平。这样就算是读出了一个bit。

接下来为了时序能够接上,我们再等待数据线拉低(如果是数据0则不用等待,数据线就是拉低的状态)。

重复上面的步骤8次,我们就读出了一个Byte。

最后读完40个bit(5个Byte)之后,我们再来个结束信号。

实际上我们不需要什么操作,上面都是DTH11需要执行的。

我们只要在读出数据之后等待60us即可。

数据

现在我们来看看五个Byte都是些什么含义。

从头到尾依次是湿度的整数,湿度的小数(一直都是0,不需要管它),温度的整数,温度的小数,校验位。

一共有两个数据,湿度和温度。

其中湿度的小数一直都是0。温度的小数对应的值乘上0.1度就是对应的温度。

最后一个校验位是前四位加起来的值。如果前四位加起来不等于校验位,那么表示数据出错了。

需要注意的是前四位数相加的值需要强转成8bit的类型才能和校验位进行比较。

STM32驱动代码

下面的代码里涉及OLED显示和Delay延时函数的部分需要自己实现。

 OLED只是为了展示读取的数据,没有的小伙伴用串口通信打印到电脑上也可以。

延时函数网上随便一搜就有,也可以翻一下我之前的文章,直接复制粘贴也行。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"

#define DHT11_DATE_PROT GPIO_Pin_0

void Z_DHT11_Init(void);
void Z_DHT11_Output(void);
void Z_DHT11_Input(void);
void Z_DHT11_SetDate(BitAction val);
uint8_t Z_DHT11_GetDate(void);
uint8_t Z_DHT11_GetByte(void);
void Z_DHT11_GetTemperatureAndHumidity(void);

//初始化DHT11
void Z_DHT11_Init(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    Z_DHT11_Output();
    Z_DHT11_SetDate(1);
    Delay_s(1);
}

//将数据线配置为输出模式
void Z_DHT11_Output(void){
    GPIO_InitTypeDef itd;
    itd.GPIO_Mode=GPIO_Mode_Out_PP;         //推挽输出
    itd.GPIO_Pin=DHT11_DATE_PROT;
    itd.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&itd);
}

//将数据线配置为输入模式
void Z_DHT11_Input(void){
    GPIO_InitTypeDef itd;
    itd.GPIO_Mode=GPIO_Mode_IPU;            //上拉输入
    itd.GPIO_Pin=DHT11_DATE_PROT;
    itd.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&itd);
}

void Z_DHT11_SetDate(BitAction val){
    GPIO_WriteBit(GPIOA,DHT11_DATE_PROT,val);
}
 
uint8_t Z_DHT11_GetDate(void){
    return GPIO_ReadInputDataBit(GPIOA,DHT11_DATE_PROT);
}

//读取一个Byte
uint8_t Z_DHT11_GetByte(void){
    uint8_t data;
    
    for(uint8_t i=0;i<8;i++){
        while(Z_DHT11_GetDate()==0);
        Delay_us(30);
        data<<=1;
        if(Z_DHT11_GetDate()==1) data|=1;
        while(Z_DHT11_GetDate()==1);
    }
    return data;
}

uint8_t DTH11_Data[5];
//获取温湿度
void Z_DHT11_GetTemperatureAndHumidity(void){
    Z_DHT11_Output();
    Z_DHT11_SetDate(0);
    Delay_ms(20);
    Z_DHT11_SetDate(1);
    Delay_us(30);
    Z_DHT11_Input();
    
    if(Z_DHT11_GetDate()!=0) return;
    while(Z_DHT11_GetDate()==0);
    while(Z_DHT11_GetDate()==1);
    
    DTH11_Data[0]=Z_DHT11_GetByte();
    DTH11_Data[1]=Z_DHT11_GetByte();
    DTH11_Data[2]=Z_DHT11_GetByte();
    DTH11_Data[3]=Z_DHT11_GetByte();
    DTH11_Data[4]=Z_DHT11_GetByte();
    
    Delay_us(60);
}

int main(void){
    OLED_Init();
    Z_DHT11_Init();
    while(1){
        Z_DHT11_GetTemperatureAndHumidity();
        if((uint8_t)(DTH11_Data[0]+DTH11_Data[2]+DTH11_Data[3])!=DTH11_Data[4]) continue;
        OLED_ShowNum(1,1,DTH11_Data[0],2);
        OLED_ShowNum(1,4,DTH11_Data[1],2);
        OLED_ShowNum(2,1,DTH11_Data[2],2);
        OLED_ShowNum(2,4,DTH11_Data[3],2);
        OLED_ShowNum(3,1,DTH11_Data[4],2);
        Delay_ms(500);
    }
}


数据可以正常读取,就是精度确实有点低。

ESP32驱动代码

其实只需要把STM32的代码改改就行了,差别不大。

ESP32的代码相比较STM32会更简洁一些。

因为ESP32可以将GPIO口初始化成既可以输入也可以输出,因此不需要像STM32那样切换GPIO口的模式。我们只需要初始化一次GPIO口的模式即可,记得加上上拉电阻。

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

#define DHT11_DATE_PROT 18


void Z_DHT11_Init(void);
void Z_DHT11_SetDate(uint8_t val);
uint8_t Z_DHT11_GetDate(void);
uint8_t Z_DHT11_GetByte(void);
void Z_DHT11_GetTemperatureAndHumidity(void);

// 初始化DHT11
void Z_DHT11_Init(void){
    gpio_config_t init = {
        .intr_type = GPIO_INTR_DISABLE,         // 失能中断;
        .mode = GPIO_MODE_INPUT_OUTPUT,         // 输出模式
        .pin_bit_mask = (1ULL << DHT11_DATE_PROT),
        .pull_down_en = GPIO_PULLDOWN_DISABLE,  // 失能下拉模式
        .pull_up_en = GPIO_PULLUP_ENABLE,      // 使能上拉模式
    };
    gpio_config(&init);
    Z_DHT11_SetDate(1);
    vTaskDelay(1000/portTICK_PERIOD_MS);
}

void Z_DHT11_SetDate(uint8_t val){
    gpio_set_level(DHT11_DATE_PROT,val);
}

uint8_t Z_DHT11_GetDate(void){
    return gpio_get_level(DHT11_DATE_PROT);
}

// 读取一个Byte
uint8_t Z_DHT11_GetByte(void){
    uint8_t data = 0;

    for (uint8_t i = 0; i < 8; i++){
        while (Z_DHT11_GetDate() == 0);
        usleep(30);
        data <<= 1;
        if (Z_DHT11_GetDate() == 1)     data |= 1;
        while (Z_DHT11_GetDate() == 1);
    }
    return data;
}

uint8_t DTH11_Data[5];
// 获取温湿度
void Z_DHT11_GetTemperatureAndHumidity(void){
    Z_DHT11_SetDate(0);
    vTaskDelay(20/portTICK_PERIOD_MS);
    Z_DHT11_SetDate(1);
    usleep(30);

    if (Z_DHT11_GetDate() != 0) return;
    while (Z_DHT11_GetDate() == 0);
    while (Z_DHT11_GetDate() == 1);

    DTH11_Data[0] = Z_DHT11_GetByte();
    DTH11_Data[1] = Z_DHT11_GetByte();
    DTH11_Data[2] = Z_DHT11_GetByte();
    DTH11_Data[3] = Z_DHT11_GetByte();
    DTH11_Data[4] = Z_DHT11_GetByte();

    usleep(60);
}

void app_main(void){
    Z_DHT11_Init();
    while (1){
        Z_DHT11_GetTemperatureAndHumidity();
        if ((uint8_t)(DTH11_Data[0] + DTH11_Data[2] + DTH11_Data[3]) != DTH11_Data[4])  continue;
        printf("%d,%d,%d,%d,%d\r\n",DTH11_Data[0],DTH11_Data[1],DTH11_Data[2],DTH11_Data[3],DTH11_Data[4]);
        vTaskDelay(1000/portTICK_PERIOD_MS);
    }
}

ESP32移植STM32代码成功,并且还可以直接通过printf打印到电脑上方便我们查看数据。

说好听一点叫移植,说不好听一点那就是把代码抄过来改改能跑就行。

我们在改代码的时候,函数声明什么的都可以不改,只需要把每个函数里的逻辑适配成我们要移植的芯片的逻辑就行。

相关推荐

  1. DHT11温湿传感器要点和难点实际应用

    2024-05-04 10:40:01       12 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-04 10:40:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-04 10:40:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-04 10:40:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-04 10:40:01       20 阅读

热门阅读

  1. Python进阶之-ast使用详解

    2024-05-04 10:40:01       11 阅读
  2. 前端 TS

    2024-05-04 10:40:01       10 阅读
  3. 时间复杂度和空间复杂度

    2024-05-04 10:40:01       10 阅读
  4. C# do...while循环

    2024-05-04 10:40:01       12 阅读
  5. 富格林:了解黑幕套路正规方法预防

    2024-05-04 10:40:01       10 阅读
  6. 算法--回溯法

    2024-05-04 10:40:01       10 阅读
  7. 第十三节:Vben Admin实战-系统管理之菜单管理

    2024-05-04 10:40:01       11 阅读
  8. 动态sql

    动态sql

    2024-05-04 10:40:01      10 阅读
  9. vue2 + antvx6 实现流程图功能

    2024-05-04 10:40:01       9 阅读
  10. 如何判断嵌入式平台OpenCV在使用硬件编解码器?

    2024-05-04 10:40:01       9 阅读
  11. UNIAPP&小程序从入门到精通

    2024-05-04 10:40:01       9 阅读
  12. 15. 三数之和 - 力扣(LeetCode)

    2024-05-04 10:40:01       12 阅读
  13. 等保测评试题(一)

    2024-05-04 10:40:01       13 阅读
  14. 【C语言】/*printf 函数*/

    2024-05-04 10:40:01       10 阅读