STM32外设系列—DHT11

简介: 本文详细介绍了什么是DHT11,介绍了DHT11使用的单总线通信,并详细分析了与DHT11进行数据交互时的时序图。此外,给出了DHT11初始化,接收温湿度信息并校验的程序设计。


🎀 文章作者:二土电子
🐸 期待大家一起学习交流!


一、DHT11简介

DHT11是一款常用的数字温湿度传感器。传感器包括一个电容式感湿元件和一个 NTC 测温元件,能够测量皱纹环境的温湿度,常用于暖通空调、除湿器、农业、冷链仓储等方面。

02b666206c01d752523c013f3067de9c_e1f4410f12bc40fa9b417c31e4eec6d7.png

二、数据手册分析

2.1 接口说明

fd33024e6d15fbd0c72c69519279f926_1d2c018752cb43e297527b2b9ac705ce.png

2.2 串行通信说明

DHT11通过串行通信的方式,将采集到的环境温湿度信息传递给单片机。数据手册中,针对DHT11的串行通信做了详细介绍。

2.2.1 单总线通信

DHT11 器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。设备(主机或从机)通过一个漏极开路或三态端口连至数据线,以允许设备在不发送数据时能够释放总线,而让其它设备使用总线;单总线通常要求外接一个约 4.7kΩ 的上拉电阻,这样,当总线闲置时,其状态为高电平。由于它们是主从结构,只有主机呼叫从机时,从机才能应答,因此主机访问器件都必须严格遵循单总线序列,如果出现序列混乱,器件将不响应主机。

2.2.2 单总线传输数据位定义

DHT11的DATA引脚,用于单片机与 DHT11 之间的通讯和同步,采用单总线数据格式,一次传送 40 位数据,高位先出。数据格式

8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据 + 8bit 校验位

数据手册中写明,湿度的小数部分为0。8bit 校验位等于所得结果的末 8 位。

4c11d312028a57bb18399c672417cca3_d66d29b3a09348e1b93456e802e00bf6.png

对于校验位,数据手册中举例说明。比如接收到的40位数据为

image.png

计算 0011 0101 + 0000 0000 + 0001 1000 + 0000 0100 + 0101 0001 = 0101 0001,与接收到的校验位相等,校验通过。如果校验不通过,则将此次接收到的数据丢弃,重新接收数据。

2.2.3 时序图

根据上面的介绍,如果单片机想要读取数据,需要先发送一个起始信号。起始信号需要拉低数据线至少18ms。

951012f67d31b6718692fff057bf2ea6_9aaab06b7419456fbaaf82d37f82cfb5.png

DHT11检测到起始信号之后,等待起始信号低电平结束,然后输出应答信号。应答信号是先将数据线拉低83us,再拉高87us。

a6d4cc60598df0ec0259baacff41a0f9_ef5572769ab84e82808a959310756134.png

然后DHT11就开始输出数据了,“0”和“1”的时序图如下

98da931670c35e382b9dc139f80e4467_f5852c00c9c44c4faf9da72005e7606b.png

总时序图如下

2fc282af8a204a5418fdf627c79f5756_10a40667f8ec4350b9b1b87f80038d98.png

三、DHT11程序设计

3.1 初始化GPIO

根据上面的介绍,STM32的GPIO既需要用作输出,也需要用作输入。因此,STM32的GPIO需要有两种配置

/*
 *==============================================================================
 *函数名称:Drv_Dht11_Gpio_OutInSet
 *函数功能:DHT11引脚输出/输入设置
 *输入参数:state:OUT:输出(0);IN:输入(1)
 *返回值:无
 *备  注:无
 *==============================================================================
 */
void Drv_Dht11_Gpio_OutInSet (u8 state)
{
   
   
    // 结构体定义
     GPIO_InitTypeDef  GPIO_InitStructure;

    // 开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    // 初始化GPIO结构体
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    if (state)
    {
   
   
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   // 浮空输入
    }
    else
    {
   
   
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   // 推挽式输出
    }
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_Init(GPIOA,&GPIO_InitStructure);
}

.h文件添加下面程序

// GPIO模式
#define OUT   0   // 输出模式
#define IN    1   // 输入模式

3.2 复位DHT11

/*
 *==============================================================================
 *函数名称:Drv_Dht11_Reset 
 *函数功能:复位DHT11
 *输入参数:无
 *返回值:无
 *备  注:无
 *==============================================================================
 */
void Drv_Dht11_Reset (void)
{
   
   
    Drv_Dht11_Gpio_OutInSet(OUT);   // 设置数据线为输出模式
    DHT11_SDA_Clr();   // 拉低数据线
    delay_ms(20);   // 拉低至少18ms
    DHT11_SDA_Set();   // 拉高一小段时间
    delay_us(30);   // 拉高20~40us
}

3.3 DHT11连接检测

/*
 *==============================================================================
 *函数名称:Drv_Dht11_ConnectCheck
 *函数功能:检测DHT11是否连接
 *输入参数:无
 *返回值:0:已连接;1:未连接
 *备  注:无
 *==============================================================================
 */
u8 Drv_Dht11_ConnectCheck (void)
{
   
   
    u8 tempVar = 0;   // 定义临时变量

    Drv_Dht11_Gpio_OutInSet(IN);   // 设置数据线为输入模式
    while ((GPIO_ReadInputDataBit(GPIO_DHT11, GPIO_PIN_DHT11) == 1) && tempVar < 100)   // DHT11会拉低40~80us
    {
   
   
        tempVar++;
        delay_us(1);
    };
    if(tempVar >= 100)
        {
   
   
            return 1;
        }
    else
        {
   
   
            tempVar = 0;
        }
    while ((GPIO_ReadInputDataBit(GPIO_DHT11, GPIO_PIN_DHT11) == 0) && tempVar < 100)   // DHT11拉低后会再次拉高40~80us
    {
   
   
        tempVar++;
        delay_us(1);
    };
    if(tempVar >= 100)
        {
   
   
            return 1;
        }
    return 0;
}

3.4 发送起始信号

单片机的 I/O 设置为输出同时输出低电平,且低电平保持时间不能小于 18ms(最大不得超过 30ms),然后单片机的 I/O 设置为输入状态,由于上拉电阻,单片机器的 I/O 即 DHT11 的 DATA 数据线也随之变高,等待 DHT11 作出回答信号。程序设计如下

/*
 *==============================================================================
 *函数名称:Drv_Dht11_Start
 *函数功能:向DHT11发送起始信号
 *输入参数:state:OUT:输出(0);IN:输入(1)
 *返回值:无
 *备  注:无
 *==============================================================================
 */
void Drv_Dht11_Start (void)
{
   
   
    OLED_SDA_Set();   // 拉高一小段时间
    delay_us(30);

    Drv_Dht11_Gpio_OutInSet(OUT);   // GPIO配置为输出模式
    OLED_SDA_Clr();   // 拉低数据线
    delay_ms(20);   // 保持20ms

    OLED_SDA_Set();   // 拉高一小段时间
    delay_us(30);

    Drv_Dht11_Gpio_OutInSet(IN);   // GPIO配置为输入模式
}

3.5 DHT11初始化

/*
 *==============================================================================
 *函数名称:Drv_Dht11_Gpio_OutInSet
 *函数功能:DHT11引脚输出/输入设置
 *输入参数:state:OUT:输出(0);IN:输入(1)
 *返回值:无
 *备  注:这里的连接检测用的是while语句,如果DHT11一直连接异常,程序会一直卡在
                    在这里,如果有显示器件或者串口调试,建议这里添加一个异常信息的输出。
                    如果没有显示器件,建议不进行连接检测。
 *==============================================================================
 */
void Med_Dht11_Init (void)
{
   
   
    Drv_Dht11_Reset();   // 复位DHT11
    while(Drv_Dht11_ConnectCheck())   // DHT11连接检测
    {
   
   
        Med_Oled_ShowString(2,0,"DHT11 Error!",8);   // 在OLED上显示字符串
        Med_Oled_ShowString(4,2,"Please Check Connect!",8);   // 在OLED上显示字符串
    }
    Med_Oled_Clear();   // 清屏
    Med_Oled_ShowString(2,7,"ertu 2023.10.26",8);   // 在OLED上显示字符串
}

3.6 接收一个字节数据

/*
 *==============================================================================
 *函数名称:Med_Dht11_ReceOneByte
 *函数功能:接收一帧数据
 *输入参数:无
 *返回值:一字节接收数据
 *备  注:无
 *==============================================================================
 */
u8 Med_Dht11_ReceOneByte (void)
{
   
   
    u8 tempVar = 0;   // 临时循环变量
    u8 receData = 0;   // 接收数据

    for (tempVar = 0;tempVar < 8;tempVar ++)
    {
   
   
        receData <<= 1;   // 左移

        while (DHT11_SDA_DATA);   // 等待高电平过去
        while (!DHT11_SDA_DATA);   // 等待54us的低电平过去
        delay_us(40);   // 延时30us之后判断是0还是1

        // 如果30us之后依旧为高电平
        if (DHT11_SDA_DATA)
        {
   
   
            receData |= 1;   // 接收数据为1
        }
        else
        {
   
   
            receData |= 0;   // 接收数据为0
        }
    }
    return receData;
}

3.7 接收温湿度信息并校准

/*
 *==============================================================================
 *函数名称:Med_Dht11_GetData
 *函数功能:获取温湿度数据
 *输入参数:*temp:存储温度数据变量地址;*humi:存储湿度数据变量地址
 *返回值:0:读取成功;1:读取失败
 *备  注:无
 *==============================================================================
 */
u8 Med_Dht11_GetData (u8 *temp, u8 *humi)
{
   
   
    u8 buf[5];
    u8 i;
    Drv_Dht11_Reset();   // 复位DHT11

    if(Drv_Dht11_ConnectCheck() == 0)
    {
   
   
        for(i = 0; i < 5; i++) //读取40位数据
        {
   
   
            buf[i] = Med_Dht11_ReceOneByte();
        }
        if((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
        {
   
   
            *humi = buf[0];
            *temp = buf[2];
        }
    }
    else
        {
   
   
            return 1;
        }
    return 0;
}

四、总结

实际上面的程序设计有一些不足,比如某些地方不需要再拉高SDA线,在等到时使用了while语句但是没有超时检测。但是由于博主的DHT11坏了,目前买的新的还没到,无法继续调试,因此这里说明一下。后续会修改完善程序,补充应用实例。——2023年6月26日

相关文章
|
6月前
|
传感器 芯片 内存技术
STM32F103标准外设库——认识STM32(一)
STM32F103标准外设库——认识STM32(一)
186 0
STM32F103标准外设库——认识STM32(一)
|
数据格式
STM32外设系列—红外遥控
本文详细介绍了红外通信的应用,原理。介绍了一种常用的二进制脉冲码形式。最后,给出了红外遥控的实现思路和程序设计。
386 2
STM32外设系列—红外遥控
|
3月前
|
传感器
手把手在STM32F103C8T6上构建可扩展可移植的DHT11驱动
【8月更文挑战第29天】本文详细介绍在STM32F103C8T6上构建可扩展且可移植的DHT11温湿度传感器驱动的步骤,包括硬件与软件准备、硬件连接、驱动代码编写及测试。通过这些步骤,可根据实际项目需求优化和扩展代码。
108 0
|
4月前
|
传感器 数据安全/隐私保护 数据格式
STM32CubeMX DHT11温湿度传感器
STM32CubeMX DHT11温湿度传感器
248 11
|
传感器 芯片
STM32外设系列—HC-SR04(超声波)
本文主要介绍了超声波测距的原理,常用的超声波传感器。并且针对HC-SR04给出了使用思路和程序设计。最后,简单进行了思路拓展。
357 1
STM32外设系列—HC-SR04(超声波)
|
芯片
STM32外设系列—sg90(舵机)
本文介绍了什么是舵机,舵机的控制原理。以sg90为例,介绍了180°舵机的控制方法,给出了详细的程序设计。最后,介绍了360°舵机的控制方法。
1958 1
STM32外设系列—sg90(舵机)
|
5月前
|
开发者
【经典案例】使用HAL库配置STM32F407的SPI外设
在嵌入式系统开发中,STM32F407是一款广泛应用的微控制器,而SPI(Serial Peripheral Interface)是一种常用的通信接口。本文将详细介绍如何使用STM32的硬件抽象层(HAL)库配置STM32F407的SPI外设,并提供完整的代码示例。
558 1
|
5月前
|
传感器 数据格式
【STM32】DHT11温湿度模块传感器详解&代码
【STM32】DHT11温湿度模块传感器详解&代码
|
存储 传感器 编解码
STM32外设系列—BH1750
本文详细介绍了BH1750的特点,原理图,IIC通信协议。给出了BH1750程序设计,能够实时获取周围环境光照强度。最后,给出了两种拓展应用,并说明了实现思路。
1255 0
STM32外设系列—BH1750
|
6月前
|
传感器 存储 缓存
STM32--MPU6050与I2C外设
STM32--MPU6050与I2C外设
157 1