STM32与DHT11传感器集成使用指南——速成教程

DHT11 是一款常用的数字温湿度传感器,它内部集成了 NTC 温度传感器电容式湿度传感器,并带有 单总线数字输出接口。采集温湿度的原理可以分为两个部分:

一、硬件测量原理

1. 湿度测量

  • DHT11 使用 电容式湿度传感器 来测量空气湿度。

  • 电容器的介质对空气中的水分敏感,湿度变化会导致电容值变化。

  • 传感器内部会将电容值变化转换成数字信号。

  • 2. 温度测量

  • 使用 NTC 热敏电阻(负温度系数),温度升高时电阻减小。

  • 模拟信号通过 A/D 转换器转换为数字温度值。

  • 二、硬件参数一览表

    1. DHT11模组

    如下图

    参数类别 项目 参数值
    电气特性 工作电压 3.3V ~ 5.5V(针对于DHT11模组)
    最大电流(采样时) ~2.5mA
    静态电流 ~60µA
    湿度测量 测量范围 20%RH ~ 90%RH
    精度 ±5%RH
    分辨率 1%RH
    响应时间 <5s
    温度测量 测量范围 0°C ~ 50°C
    精度 ±2°C
    分辨率 1°C
    响应时间 <5s
    输出 通信方式 单总线数字信号
    输出格式 40位(8湿度高 + 8湿度低 + 8温度高 + 8温度低 + 校验)
    其他 封装 4-pin 单排直插封装(蓝色外壳)
    尺寸 15.5mm x 12mm x 5.5mm
    推荐采样周期 ≥1秒
    使用寿命 ≥10 万次测量

    DHT11模组:数据线需接上拉电阻(建议 10kΩ)以实现单总线闲置时,其处于高电平状态

    2.注意事项

  • 读取间隔应 ≥1 秒,频繁读取会导致数据错误

  • 湿度和温度精度相对较低,不适合对精度要求高的场合

  • 避免在强腐蚀、强磁场、高静电等环境下使用

  • 三、数据通信原理(单总线协议)

    1. 主机启动信号(MCU → DHT11)

    动作 参数 注意事项
    MCU拉低数据线 18~30ms(推荐20ms) 确保DHT11检测到启动信号(时间不足可能导致无响应)
    MCU释放总线(拉高) 20~40μs(推荐30us) 释放后需切换GPIO为输入模式(否则无法接收DHT11响应)

    目的:MCU通过输出启动信号唤醒DHT11并触发数据采集;MCU再切换至输入模式等待DHT11的自检测

    /****************************************************************************
    函数名称:void DHT11_Start(void)
    函数参数:无
    函数返回值:无
    描述:MCU启动DHT11+MCU等待DHT11的数据输入
    ****************************************************************************/
    void DHT11_Start(void)
    {
        DHT11_OUT();		//设置为推挽输出模式
        DHT11_DQ_L;			//设置输出模式为0
        Delay_ms(20);       // 拉低至少18ms
        DHT11_DQ_H;			//设置输出模式为1,确保0输出的时间维持在18~30ms之间
        Delay_us(30);       // 拉高 20~40us
        DHT11_IN();         // 切换为输入模式,等待响应
    }

    2. DHT11自检阶段(DHT11 → MCU)

    主机检测到:

    1. 数据线被 DHT11 拉低(约 80us)

    2. 然后数据线被拉高(约 80us)

    这两个阶段构成了完整的 “自检测信号”

    DHT11 的自检测信号就是“80us低 + 80us高”的响应时序

    也就是说DHT11在响应阶段一直给MCU发送一个周期为160us的周期信号

    主机在发送起始信号后必须正确检测这个过程,否则说明模块未连接或损坏。这个过程是数据传输的关键前提。

    信号变化 时间 检测方法
    DHT11拉低总线 持续约80μs DHT11 会拉低表示响应主机,主机需检测到低电平
    DHT11拉高总线 持续约80μs DHT11 拉高准备发送数据;主机需检测到高低电平

    目的:DHT11自检测功能,确保DHT11能稳定输出高低电平并且在输出一定时长的高电平后进行数据传输

    /****************************************************************************
    函数名称:uint8_t DHT11_Check(void)
    函数参数:无
    函数返回值:返回值:1:失败     0:成功
    描述:
    	第一个 while:目的是等待DHT11对MCU响应的低电平
    	1.在启动信号发出后,若高电平持续时长>=100us,即DHT11未对MCU响应的低电平,DHT11自检失败;返回1
    	2.在启动信号发出后,若高电平持续时长<=100us,即DHT11对MCU响应的低电平
    	  
    
    	第二个 while:目的是等待DHT11对MCU响应的高电平
    	1.在DHT11对MCU响应的低电平后,若低电平持续时长>=100us,即DHT11自检失败;返回1
    	2.在DHT11对MCU响应的低电平后,若低电平持续时长<=100us,即DHT11对MCU响应的高电平,自检成功;返回0
    ****************************************************************************/
    uint8_t DHT11_Check(void)
    {
        uint8_t retry = 0;
        while(DHT11_READ     &&     retry < 100)  // 等待 DHT11 拉低响应
        {
            retry++;
            Delay_us(1);
        }
        if(retry >= 100) return 1;
    
        retry = 0;
        while(!DHT11_READ     &&     retry < 100)  // 等待 DHT11 拉高
        {
            retry++;
            Delay_us(1);
        }
        return (retry >= 100) ? 1 : 0;
    }

    3. 数据传输阶段(DHT11 → MCU)

    (1)数据帧分析

    DHT11 一次传输共 40 位数据,即 5 个字节,按照如下顺序发送:

    数据帧构成:

    [ 8位湿度整数 ] + [ 8位湿度小数 ] + [ 8位温度整数 ] + [ 8位温度小数 ] + [ 8位校验和 ]

    数据格式说明:

    字节序号 名称 内容示例
    Byte 1 湿度整数部分 25(即 25%RH)
    Byte 2 湿度小数部分 0(通常为 0)
    Byte 3 温度整数部分 26(即 26°C)
    Byte 4 温度小数部分 0(通常为 0)
    Byte 5 校验和(Checksum) Byte1+Byte2+Byte3+Byte4 的和,对 256 取余
    举个例子:
    
    如果 DHT11 发送以下 5 个字节数据(十六进制):
    
    湿度整数    湿度小数    温度整数    温度小数    校验和
    0x19       0x00        0x1A        0x00        0x33
    
    换算后:
    
    湿度:0x19 = 25%RH
    
    温度:0x1A = 26°C
    
    校验:0x19 + 0x00 + 0x1A + 0x00 = 0x33

    注意:如果接收到的数据和与校验和不一致,说明本次通信有误,应丢弃本次数据。

    (2)数据传输分析

    DHT11 的单个位传输时序

    每一位数据的时序如下:

    阶段 状态 持续时间
    DHT11 拉低 固定为 50μs 表示准备发送一个 bit
    DHT11 拉高 26~28μs 表示 0;70μs 表示 1 主机据此判断是 0 还是 1
    /****************************************************************************
    函数名称:uint8_t DHT11_Read_Bit(void),从DHT11的数据线上读取1位数据
    函数参数:无;
    函数返回值:0:该位数据为0    1:该位数据为1    0XFF:超时,返回错误标志(非法值)
    描述:
    	第一个 while:目的等待50us的低电平作为数据传输的初始信号
    	1.在DHT11自检测成功后,若高电平持续时长>=100us,
    	  即为超时,DHT11未对MCU响应的低电平,DHT11未准备发送一个 bit,返回0XFF非法值
    	2.在DHT11自检测成功后,若高电平持续时长<=100us,
    	  即DHT11未对MCU响应的低电平,(执行下一个while)来确保输入的数据是1还是0
    
    	第二个 while:目的确定高电平信号的持续时间来判断输入的数据是1还是0
    	1.等待接收高电平信号,若低电平持续时长>=100us,即为超时,该数据有问题,返回0XFF非法值
    	2.等待接收高电平信号,若低电平持续时长<=100us,则接收到到高电平信号,
    	  在40us后再次测量此电平信号来确定改位的数据是0还是1,返回0或1
    ****************************************************************************/
    uint8_t DHT11_Read_Bit(void)
    {
        uint8_t retry = 0;
    
        // 1. 等待 DHT11 拉低(开始发送位)
        while(DHT11_READ)
        {
            if (++retry > 100)
                return 0xFF;  // 低电平等待超时
            Delay_us(1);
        }
    
        // 2. 等待 DHT11 拉高(开始计时)
        retry = 0;
        while(!DHT11_READ)
        {
            if (++retry > 100)
                return 0xFF;  // 高电平等待超时
            Delay_us(1);
        }
    
        // 3. 延迟 40us 后读取电平判断是 0 还是 1
        Delay_us(40);
    
        return DHT11_READ ? 1 : 0;
    }

    进阶整理到一个字节接收

    /****************************************************************************
    函数名称:uint8_t DHT11_Read_Byte(void)
    函数参数:0XFF数据采集失败
    函数返回值:无
    描述:采集一个字节的数据
    ****************************************************************************/
    uint8_t DHT11_Read_Byte(void)
    {	
    	uint8_t i, data = 0,bit;
        for(i = 0; i < 8; i++)
        {
    		bit = DHT11_Read_Bit();       // 读取一位
            if(bit == 0xFF) return 0xFF;  // 超时错误
            data <<= 1;				      // 左移准备放下一个 bit
            data |= bit;			      // 累加当前 bit 到低位
        }
        return data;
    }

    关于器件的原理就是这些,剩下的就是基本功了。

    完整代码:https://github.com/SusuperPeng/STM32_Commonly_Used_Sensors/tree/STM32-DHT11

    作者:<<梅干菜

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32与DHT11传感器集成使用指南——速成教程

    发表回复