嵌入式学习 | STM32 裸板驱动开发(Day06) | DHT11温湿度传感器超详解(单总线时序+全套驱动代码+智能温湿度报警项目)

哈喽大家好!本篇为 STM32 嵌入式入门 Day06 学习笔记。

本节课我们重点学习 DHT11 数字温湿度传感器 ,掌握 单总线 1-Wire 通信协议 、完整时序解析、GPIO 动态输入输出切换、DHT11 驱动手写开发,最后完成综合大作业:基于 STM32 的智能温湿度监控与声光报警系统

全文知识点细致、代码完整、逻辑清晰,适合新手学习、期末复习、CSDN 发文、面试背诵。


一、DHT11 传感器整体介绍

1.1 什么是 DHT11?

DHT11 是一款低成本、超低功耗、单总线数字式温湿度复合传感器 。内部集成湿度感应元件、温度感应元件、AD 转换电路、数字逻辑电路,直接输出数字信号,无需单片机做模数转换,极大降低开发难度。

广泛用于:智能家居、室内环境监测、仓库温湿度监控、农业大棚、设备机箱温度监测等场景。

1.2 通信方式:单总线 1-Wire

DHT11 采用标准 单总线通信协议(1-Wire)

  • 仅需 一根 DATA 数据线 与 MCU 通信

  • 搭配 VCC、GND 即可正常工作

  • 数据线为 双向半双工通信

  • MCU 需要动态切换 GPIO 输出、输入模式,实现收发通信

单总线最大特点:一根线实现主机发、从机收、从机发、主机收

1.3 DHT11 官方参数规格(重点考点)

参数类型 测量范围 测量精度/误差 备注
温度测量 0℃ ~ 50℃ ±2℃ 室内环境完全够用
湿度测量 10%RH ~ 90%RH ±5%RH RH 代表相对湿度
工作电压 3.3V ~ 5V ------ STM32 3.3V 可直接驱动
采集周期 最小 2S ------ 禁止高频采集,否则死机乱码

**补充知识点:**DHT11 的小数位永远为 0,精度较低;高精度项目建议使用 DHT22(AM2302)。


二、DHT11 完整通信时序(全网最细解析)

DHT11 通信严格依赖微秒级精准时序,时序错1us就会读取失败、全是0、乱码、校验错误。

完整通信四大阶段:

起始信号(MCU) → 响应信号(DHT11) → 40bit 数据传输 → 停止信号(MCU)

2.1 起始信号(主机 MCU 发起)

MCU 主动发起通信,告诉 DHT11"我要读取数据"

  • 步骤1:MCU 拉低 DATA 引脚,持续 至少 18ms

  • 步骤2:MCU 释放总线,拉高电平,保持 20~40us

作用:低速长拉低唤醒传感器,短暂拉高等待从机应答。

2.2 响应信号(从机 DHT11 应答)

DHT11 检测到起始信号后,返回应答握手信号:

  • 步骤1:DHT11 拉低总线 80us

  • 步骤2:DHT11 拉高总线 80us

握手成功后,DHT11 正式开始上传 40bit 温湿度数据。

2.3 40bit 数据帧格式(核心重点)

一次通信固定传输 40bit = 5Byte数据

数据顺序:湿度整数 + 湿度小数 + 温度整数 + 温度小数 + 校验和

字节序号 含义 说明
Data0 湿度整数 实际有效湿度值
Data1 湿度小数 DHT11 固定为 0
Data2 温度整数 实际有效温度值
Data3 温度小数 DHT11 固定为 0
Data4 校验和 校验和=前4字节相加

2.4 位数据时序(区分 0 和 1)

每一位数据都以 50us 低电平 作为起始基准,靠高电平时长区分 0/1

逻辑 0 时序

  • 拉低 50us

  • 拉高 26~28us

逻辑 1 时序

  • 拉低 50us

  • 拉高 70us

开发黄金技巧: 等待电平跳变后 延时 45us 再读取引脚电平,低为0、高为1,时序最稳!

2.5 停止信号

  • DHT11 发送完 40bit 数据后,自动拉低总线 50us

  • MCU 主动拉高总线,结束本次通信

单次采集彻底结束,等待下一次 2S 周期采集。


三、DHT11 驱动函数架构逐行解析

硬件接线:DHT11 DATA ------> STM32 PC10

3.1 dht11_init() 初始化函数

功能:初始化 GPIO、开启时钟、默认推挽输出

  • 开启 GPIOC 时钟

  • PC10 设置为推挽输出模式

  • 默认高电平,等待发起通信

3.2 dht11_wait_ack() 等待应答函数

功能:切换引脚为输入模式,检测 DHT11 是否正常应答

  • PC10 改为浮空输入

  • 等待从机拉低、再拉高

  • 应答成功代表传感器正常在线

3.3 dht11_get_value() 数据读取核心函数

核心逻辑:循环读取 5 字节、共 40 位数据,逐位采集、拼接字节、最终解析温湿度。

  • 定义 u8 data5 存储原始数据

  • 循环读取每一位时序

  • 45us 延时采样判断 0/1

  • 最终赋值:湿度=data0,温度=data2

3.4 dht11_stop() 通信停止函数

  • 恢复 PC10 为推挽输出

  • 等待时序结束

  • MCU 拉高总线,结束通信


四、完整可直接编译 DHT11 驱动代码

dht11.c 驱动源码

cpp 复制代码
#include "dht11.h"
#include "delay.h"

// 初始化DHT11引脚
void dht11_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStruct);

    GPIO_SetBits(GPIOC,GPIO_Pin_10); // 默认高电平
}

// 等待DHT11应答
u8 dht11_wait_ack(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    // 切换为输入模式
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOC, &GPIO_InitStruct);

    delay_us(40);
    if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_10)==0)
    {
        // 等待拉低结束
        while(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_10)==0);
        // 等待拉高结束
        while(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_10)==1);
        return 1; // 应答成功
    }
    return 0; // 应答失败
}

// 读取40bit数据
void dht11_get_value(u8 *temp,u8 *humi)
{
    u8 data[5] = {0};
    GPIO_InitTypeDef GPIO_InitStruct;

    // 起始信号
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOC, &GPIO_InitStruct);

    GPIO_ResetBits(GPIOC,GPIO_Pin_10);
    delay_ms(20);   // 拉低18ms以上
    GPIO_SetBits(GPIOC,GPIO_Pin_10);
    delay_us(30);

    // 等待应答
    if(dht11_wait_ack()==1)
    {
        // 循环读取5字节40位
        for(int i=0;i<5;i++)
        {
            for(int j=0;j<8;j++)
            {
                while(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_10)==0);
                while(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_10)==1);
                delay_us(45);

                if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_10))
                {
                    data[i] |= (1<<(7-j));
                }
            }
        }
    }

    // 数据赋值
    *humi = data[0];
    *temp = data[2];
}

五、Day06 课后大作业:智能温湿度监控与安全提醒系统

5.1 硬件设备

STM32开发板 + DHT11温湿度传感器 + LED指示灯 + 蜂鸣器 + 独立按键 + USART串口

5.2 应用场景

室内环境智能监测、仓库温湿度安全监控、设备过热低温预警、桌面智能环境助手,是非常典型的嵌入式综合实训项目。

5.3 核心功能需求(必做)

1、DHT11 定时采集功能

  • 固定 2秒采集一次 温湿度数据

  • 数据稳定、无乱码、无跳变

  • 支持串口实时上传上位机显示

2、智能阈值报警逻辑

环境状态 判定条件
正常安全状态 10℃ ≤ 温度 ≤ 30℃ 且 湿度 ≤ 70%RH
温度过高报警 温度 > 30℃
温度过低报警 温度 < 10℃
湿度过高报警 湿度 > 70%RH

3、LED 分级状态指示

LED编号 状态 系统含义
LED0 常亮 环境温湿度正常,安全状态
LED1 闪烁 温湿度轻微异常,预警状态
LED2 常亮 温湿度严重超标,危险提醒

5.4 可选拓展功能(加分项)

  • 蜂鸣器分级报警:预警间歇响、严重超标常响

  • 按键开启/关闭报警提醒功能

  • 串口实时打印温度、湿度、系统状态

  • 上位机指令修改报警阈值


六、DHT11 开发高频踩坑总结(面试必背)

  • 禁止高频采集:必须间隔 2S,否则传感器死机

  • GPIO 必须动态切换输入输出,单总线双向通信核心

  • 延时必须精准,微秒延时不准直接读不到数据

  • 必须做数据校验,防止干扰导致数据错乱

  • DHT11 小数位永远为 0,不要浪费代码解析小数

  • 每次通信结束必须停止总线,复位电平状态

七、本章思考题(巩固提升)

  1. DHT11 为什么需要不断切换 GPIO 输入/输出模式?

  2. 读取数据位时,为什么固定延时 45us 采样?

  3. 如果不做校验和判断,项目会出现什么问题?

  4. 死循环延时 2S 采集有什么弊端?如何优化?

相关推荐
FellAveal2 小时前
【Go语言入门学习笔记】Part19.速率控制、原子计数器、互斥锁(Mutex)、状态协程
笔记·学习·golang
你怎么知道我是队长2 小时前
经典蓝牙(Bluetooth Classic / BR/EDR)学习计划
学习
极地野狼 音乐哔哔2 小时前
[MAF预定义的AIContextProvider-03]ChatHistoryMemoryProvider——赋予Agent从经验中学习的能力
学习·microsoft
振南的单片机世界3 小时前
3.5T静默分帧,CRC16校验:Modbus-RTU帧结构解析
arm开发·stm32·单片机·嵌入式硬件
0x3F(小茶)4 小时前
STM32 SPI的5种方向模式
c语言·stm32·单片机·嵌入式硬件
oier_Asad.Chen4 小时前
【洛谷题解/AcWing题解】洛谷P4011 孤岛营救问题/AcWing1131拯救大兵瑞恩
数据结构·笔记·学习·算法·动态规划·图论·宽度优先
xxwl5854 小时前
Git 完整学习笔记:从入门到团队协作
笔记·git·学习
minglie15 小时前
zynq的xlnx_rebase_v5.4_2020.2分支打patch-5.4.3-rt1.patch.xz补丁
学习
醉城夜风~5 小时前
HTML常用标签详解学习博客:从基础标签到页面结构完整掌握
前端·学习·html