MCU单片机 - STM32F103C8T6 驱动 DHT11 温湿度传感器详解

Peter_Deng. Peter_Deng. 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要 + 加入社区

DHT11 是一种数字温湿度传感器,采用单总线协议通信,结构简单,易于使用,非常适合STM32微控制器进行学习和开发。本文基于STM32F103C8T6单片机,使用PB3口连接DHT11,详细讲解硬件连接、GPIO配置、单总线通信时序、数据接收与校验,并配备超详细注释代码和自定义延时函数。

一、硬件连接

  • DHT11数据线连接STM32的PB3引脚
  • VCC接5V或3.3V,GND接地
  • 注意:数据线上最好加一个4.7kΩ的上拉电阻,确保总线空闲时处于高电平

二、单总线通信协议简介

DHT11的数据通信只有一根数据线,采用开漏结构,主机和从机通过电平的高低及持续时间传递信息:

在这里插入图片描述

三、关键代码详解(含自定义延时)

DHT11数据时序图如下:

数据时序图

1. 微秒延时函数(基于SysTick)

/*****************************************
函数功能:微秒级延时函数
参    数:xus - 延时的微秒数
返 回 值:无
备    注:使用SysTick计数器,时钟为72MHz/8=9MHz
          计数器每个tick约0.111us,LOAD=9*xus-1实现xus微秒延时
******************************************/
void delay_us(u32 xus)
{
    SysTick->CTRL &= ~(1 << 2);          // 选择内部时钟HCLK/8(9MHz)
    SysTick->LOAD = 9 * xus - 1;         // 设定重装载值,计数9*xus个tick
    SysTick->VAL = 0;                    // 清空当前计数值
    SysTick->CTRL &= ~(1 << 1);          // 禁止SysTick中断
    SysTick->CTRL |= (1 << 0);           // 启动SysTick计数器

    while (!(SysTick->CTRL & (1 << 16))); // 等待计数器计数到0,自动清标志
    SysTick->CTRL &= ~(1 << 0);          // 关闭计数器
}

/*****************************************
函数功能:毫秒级延时函数
参    数:xms - 延时的毫秒数
返 回 值:无
备    注:循环调用delay_us实现毫秒延时
******************************************/
void delay_ms(u32 xms)
{
    while (xms--)
    {
       delay_us(1000);                  // 1ms = 1000us
    }
}

2. GPIO初始化及模式切换

#include "stm32f10x.h"  // STM32F10x 标准库头文件

/*****************************************
函数功能:配置PB3为开漏输出模式(主机驱动数据线)
参    数:无
返 回 值:无
备    注:开漏输出允许总线被多个设备共享,未驱动时线被上拉
******************************************/
void DHT11_SetOutput(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0}; // 初始化结构体清零

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;        // 选择PB3引脚
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD; // 开漏输出模式
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // 最高输出速度50MHz

    GPIO_Init(GPIOB, &GPIO_InitStruct);            // 初始化GPIOB口
}

/*****************************************
函数功能:配置PB3为浮空输入模式(接收数据线电平)
参    数:无
返 回 值:无
备    注:用于检测DHT11拉低或拉高状态,浮空输入避免内部上拉影响电平
******************************************/
void DHT11_SetInput(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0}; // 初始化结构体清零

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;        // 选择PB3引脚
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入模式
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;    // 速度参数无实际意义

    GPIO_Init(GPIOB, &GPIO_InitStruct);            // 初始化GPIOB口
}

3. DHT11初始化函数

/*****************************************
函数功能:DHT11初始化,开启GPIO时钟,配置PB3引脚,默认拉高总线
参    数:无
返 回 值:无
备    注:禁用JTAG复用,释放PB3,保证引脚可用
          使用开漏输出,延时1秒,等待DHT11稳定
******************************************/
void DHT11_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 使能GPIOB时钟

    // 禁用JTAG复用,保留SWD调试,释放PB3引脚,避免复用冲突
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

    DHT11_SetOutput();      // 配置PB3为开漏输出
    GPIO_SetBits(GPIOB, GPIO_Pin_3);  // 拉高数据线,释放总线

    delay_ms(1000);         // 延时1秒,等待传感器稳定
}

4. 发送起始信号

/*****************************************
函数功能:主机发送起始信号,通知DHT11开始传输
参    数:无
返 回 值:无
备    注:拉低至少18ms,然后拉高,等待DHT11响应
******************************************/
void DHT11_StartSignal(void)
{
    DHT11_SetOutput();      // 配置为开漏输出

    GPIO_ResetBits(GPIOB, GPIO_Pin_3); // 拉低数据线,主机驱动
    delay_ms(20);            // 保持20ms以上,满足18ms最低要求

    GPIO_SetBits(GPIOB, GPIO_Pin_3);   // 释放总线,拉高数据线
    delay_us(30);            // 等待20~40us,为DHT11响应做准备
}

5. 等待DHT11响应信号

/*****************************************
函数功能:等待DHT11拉低再拉高响应信号
参    数:无
返 回 值:0 - 响应成功
          1 - 无响应(拉低超时)
          2 - 拉低持续超时(等待低电平超时)
          3 - 拉高持续超时(等待高电平超时)
备    注:防止程序死循环卡死
******************************************/
u8 DHT11_WaitResponse(void)
{
    u16 timeout = 0;

    DHT11_SetInput();       // 切换为输入,监听数据线

    // 等待DHT11拉低开始响应,低电平持续约80us
    while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3))
    {
        delay_us(1);
        if (++timeout > 100) return 1; // 超时,未检测到拉低信号
    }

    timeout = 0;
    // 等待DHT11释放低电平,开始拉高
    while (!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3))
    {
        delay_us(1);
        if (++timeout > 100) return 2; // 低电平持续超时
    }

    timeout = 0;
    // 等待DHT11拉高结束
    while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3))
    {
        delay_us(1);
        if (++timeout > 100) return 3; // 高电平持续超时
    }

    return 0; // 响应成功
}

6. 接收40位数据(5字节)

/*****************************************
函数功能:接收DHT11传来的40位数据
参    数:data - 长度为5的数组,用于存放接收的5字节数据
返 回 值:无
备    注:通过高电平宽度判别0或1,高电平持续时间长为1,短为0
          高位优先传输,循环按字节和位读取
******************************************/
void DHT11_ReceiveData(u8* data)
{
    u8 i, j;

    for (i = 0; i < 5; i++)    // 5字节循环
    {
       u8 byte = 0;

       for (j = 0; j < 8; j++) // 8位循环
       {
           // 等待低电平结束(确保是新一位开始)
           while (!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3));

           delay_us(40); // 延时40us判断电平持续时间

           // 判断当前高电平状态
           if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3))
           {
              // 高电平持续时间长,认为是1
              byte |= (1 << (7 - j)); // 按位设置,高位先传

              // 等待高电平结束,防止干扰下一位
              while (GPIO\_ReadInputDataBit(GPIOB, GPIO\_Pin\_3));
           }
           // 若40us后低电平,认为0,不需设置位
       }

      data[i] = byte; // 存入对应字节
    }
}

7. 读取温湿度数据

/*****************************************
函数功能:读取温湿度数据(整数部分)
参    数:temp_int - 指向温度整数变量指针
          humi_int - 指向湿度整数变量指针
返 回 值:0 - 读取成功
          1 - 无响应
          2 - 校验失败
备    注:忽略小数部分和负温度,可根据需要扩展
******************************************/
u8 DHT11_Read(u8* temp_int, u8* humi_int)
{
    u8 buf[5];
    u8 sum;

    DHT11_StartSignal();          // 主机发送起始信号

    if (DHT11_WaitResponse())     // 等待DHT11响应,非0为失败
        return 1;

    DHT11_ReceiveData(buf);       // 接收5字节数据

    sum = buf[0] + buf[1] + buf[2] + buf[3];  // 计算校验和
    if (sum != buf[4])            // 校验和错误
        return 2;

    *humi_int = buf[0];           // 湿度整数部分
    *temp_int = buf[2];           // 温度整数部分

    return 0;                     // 成功
}

四、主函数示例:串口实时打印温湿度,2秒刷新

#include "stm32f10x.h"
#include "dht11.h"
#include <stdio.h>

// 重定向printf到串口1
int fputc(int ch, FILE *f)
{
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    USART_SendData(USART1, (uint8_t)ch);
    return ch;
}

int main(void)
{
    u8 ret;
    u8 temperature = 0, humidity = 0;

    SystemInit();
    delay_init();        // 初始化延时函数
    DHT11_Init();        // 初始化DHT11
    USART1_Init(115200); // 初始化串口1

    printf("System Init Complete, Starting DHT11 Reading...\r\n");

    while (1)
    {
        ret = DHT11_Read(&temperature, &humidity);

        if (ret == 0)
        {
            printf("Temperature: %d C, Humidity: %d%%\r\n", temperature, humidity);
        }
        else if (ret == 1)
        {
            printf("DHT11 no response!\r\n");
        }
        else if (ret == 2)
        {
            printf("DHT11 checksum error!\r\n");
        }

        delay_ms(2000); // 2秒刷新一次
    }
}

五、总结

  • DHT11的通信关键是开漏单线双向控制和严格的时序。
  • GPIO模式切换为开漏输出与浮空输入,实现总线控制与监听。
  • 延时函数保证微秒级准确延时,避免数据传输错误。
  • 采用超时机制防止函数死循环。
  • 校验和验证保证数据正确性。
  • 主函数通过串口实时打印读取结果,方便调试和监控。

这套代码适合STM32F103C8T6开发板,用PB3口接DHT11,实测稳定可靠,代码注释详细,欢迎读者复制粘贴调试


(完)

...全文

相关推荐

基于STM32的智能家居控制系统设计.pdf

基于STM32的智能家居控制系统设计.pdf

数据资源

STM32F103c8t6驱动DHT11温湿度在串口上打印温湿度(其它f103系列都可以用,直接移植这个库,修改下引脚就行)STM32驱动DHT11的库,可以直接移植

在物联网和嵌入式系统开发中,温湿度监测是常见的基础功能需求。本文将详细介绍如何使用STM32F103c8t6单片机驱动DHT11数字温湿度传感器,并提供完整的代码解析,源码每条都进行了注释。资源链接包含了整个代码工程和DHT11的数据手册,需要自行下载单总线数字信号输出湿度测量范围:20-90%RH(±5%RH)温度测量范围:0-50℃(±2℃)供电电压:3.3-5.5V典型功耗:0.5mA(测量时)

阿伟OvO

STM32宿舍防火防盗系统[项目源码]

本文介绍了一个基于STM32单片机的宿舍防火防盗控制系统设计,该系统通过STM32单片机结合LCD1602显示屏、DHT11温湿度传感器、电机、电位器、蜂鸣器、LED和开关等组件实现多功能监控。系统能够实时监测烟雾浓度(通过电位器模拟),当浓度超过设定阈值(如50)时,触发声光报警并自动启动灭火水泵。同时,布防开关可模拟红外人体检测,检测到入侵时同样触发报警并在LCD上显示状态。此外,系统还能采集并显示宿舍的实时温湿度数据。设计使用C语言编程,Keil5编写代码,Proteus进行仿真,适合新手学习。资料包含仿真视频、源程序(含中文注释)及相关软件包,方便用户下载和使用。

dell8

32单片机温湿度光敏检测系统[项目代码]

本文介绍了一个基于STM32单片机的温湿度光敏检测系统设计。系统通过DHT11温湿度传感器和光敏传感器实时检测环境参数,并通过LCD1602显示模块展示数据。系统具备温湿度阈值设置功能,当温度或湿度超过设定上限时,启动降温除湿模块并触发报警;低于下限时,启动升温增湿模块并报警。光照强度低于阈值时自动开灯,高于阈值则关灯。硬件部分包括32单片机核心模块、按键模块、传感器模块、蜂鸣器模块、继电器模块和LCD显示模块。软件设计部分详细介绍了外部中断处理、数据显示、阈值设置和报警功能的具体实现。系统通过仿真验证了其功能,能够有效监测和控制环境参数。

放屁带闪电

stm32单片机项目资料课程设计文档C语言程序代码原理图电路PCB实例无线数据传输系统的设计与实现

stm32单片机项目资料课程设计文档C语言程序代码原理图电路PCB实例无线数据传输系统的设计与实现

codedadi
评论
收藏 已收藏
分享
返回顶部