新手必看:DHT11 温湿度模块零基础接入 STM32,代码直接抄

1.硬件介绍

本期将为大家介绍智能家居中常用的温湿度模块 ——DHT11。

DHT11 是一款集成了已校准数字信号输出的温湿度复合传感器,它采用专门的数字模块采集技术和温湿度传感技术,不仅稳定性可靠,还具备响应速度快、抗干扰能力强的特点。

传感器内部集成了高分子电阻式感湿元件和 NTC 测温元件,更关键的是,它仅需一根数据线即可与单片机连接,通过单总线协议实现与微处理器的通讯。

根据硬件说明书和产品参数,DHT11 的 VCC 引脚支持 3.3V 或 5V 供电(适配多数单片机,无需额外电平转换),DATA 引脚连接单片机用于单总线通讯,GND 引脚接地形成供电回路。”

1.1.测量范围

2.软件设计

2.1.STM32Cubemx配置

①配置我们用到的引脚PC3。

②配置引脚GPIO模式为推挽输出。

③配置为引脚为非上拉和下拉,浮空模式。

2.1.1.输入输出模式配置

void DH11_GPIO_Init_IN()
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // GPIO 端口时钟使能
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    // 配置 GPIO 引脚模式为输入
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}

void DH11_GPIO_Init_OUT() 
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // GPIO 端口时钟使能
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    // 配置 GPIO 引脚模式为输出
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}

2.2.单总线控制(单线双向)

单总线的意思是,STM32作为主机、DTH11温湿度模块作为从机,主机发送控制命令,以及获取传感器传输回来的数据,都只需要使用一根信号线。

2.2.1.通讯过程

DATA 线用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右。数据包含了小数部分和整数部分,不过根据产品说明书表示,当前小数部分用于以后扩展,现读出为零。

操作流程如下:

一次完整的数据传输为40bit,高位先出。数据格式:8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和。

数据传送正确时校验和数据等于“8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据”所得结果的末8位。

用单片机发送一次开始信号后,DHT11将从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集, 用户可选择读取部分数据。

从模式下,DHT11接收到开始信号触发一次温湿度采集, 如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集.采集数据后转换到低速模式。

//获取数据
void DHT11_REC_Data(void)
{
    unsigned int R_H,R_L,T_H,T_L;
    unsigned char RH,RL,TH,TL,CHECK;
    
    DHT11_Start(); //主机发送信号
    dht11_high; //拉高电平
    
    if( Read_Data == 0 ) //判断DHT11是否响应
    {
        while( Read_Data == 0); //低电平变高电平,等待低电平结束
        while( Read_Data == 1); //高电平变低电平,等待高电平结束
        
        R_H = DHT11_Rec_Byte();
        R_L = DHT11_Rec_Byte();
        T_H = DHT11_Rec_Byte();
        T_L = DHT11_Rec_Byte();
        CHECK = DHT11_Rec_Byte(); //接收5个数据
        
        dht11_low; //当最后一bit数据传送完毕后,DHT11拉低总线 50us
        delay_us(55); //这里延时55us
        dht11_high; //随后总线由上拉电阻拉高进入空闲状态。
    
        if(R_H + R_L + T_H + T_L == CHECK) //和检验位对比,判断校验接收到的数据是否正确
        {
            RH = R_H;
            RL = R_L;
            TH = T_H;
            TL = T_L;
        }
    }
	rec_data[0] = RH;
	rec_data[1] = RL;
	rec_data[2] = TH;
	rec_data[3] = TL;
}

2.2.2.起始信号表示

总线空闲状态下为高电平,主机把总线拉低等待DHT11响应,这个过程必须大于18毫秒,保证DHT11能检测到起始信号。

DHT11接收到主机的开始信号后, 等待主机开始信号结束,然后发送80us低电平响应信号,主机发送开始信号结束后,延时等待20-40us后,读取DHT11的响应信号。

主机发送开始信号后,可以切换到输入模式,或者输出高电平均可,总线由上拉电阻拉高。

总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高80us,准备发送数据。

//主机发送开始信号
void DHT11_Start(void)
{
    DH11_GPIO_Init_OUT(); //输出模式
    
	dht11_high; //先拉高
    delay_us(30);
	
    dht11_low; //拉低电平至少18us
    delay_ms(20);
    
    dht11_high; //拉高电平20~40us
    delay_us(30);
    
    DH11_GPIO_Init_IN(); //输入模式
}

每一bit数据都以50us低电平时隙开始,高电平的长短定了数据位是0还是1。

2.2.3.数据0信号表示

格式见下面图示.如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常。

当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。

2.2.4.数据1信号表示

//获取一个字节
char DHT11_Rec_Byte(void)
{
    unsigned char i = 0;
    unsigned char data;
    
    for(i=0;i<8;i++) //1个数据就是1个字节byte,1个字节byte有8位bit
    {
        while(Read_Data == 0); //从1bit开始,低电平变高电平,等待低电平结束
        delay_us(30); //延迟30us是为了区别数据0和数据1,0只有26~28us
        
        data <<= 1; //左移
        
        if( Read_Data == 1 ) //如果过了30us还是高电平的话就是数据1
        {
            data |= 1; //数据+1
        }
        
        while( Read_Data == 1 ); //高电平变低电平,等待高电平结束
    }

    return data;
}

2.3.完整代码实现

2.3.1.dth11.c

#include "dth11.h"
#include  "delay.h"

unsigned int rec_data[4];//数据

void DH11_GPIO_Init_IN()
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // GPIO 端口时钟使能
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    // 配置 GPIO 引脚模式为输入
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}

void DH11_GPIO_Init_OUT() 
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // GPIO 端口时钟使能
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    // 配置 GPIO 引脚模式为输出
    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}

//主机发送开始信号
void DHT11_Start(void)
{
    DH11_GPIO_Init_OUT(); //输出模式
    
    dht11_high; //先拉高
    delay_us(30);
    
    dht11_low; //拉低电平至少18us
    delay_ms(20);
    
    dht11_high; //拉高电平20~40us
    delay_us(30);
    
    DH11_GPIO_Init_IN(); //输入模式
}


//获取一个字节
char DHT11_Rec_Byte(void)
{
    unsigned char i = 0;
    unsigned char data;
    
    for(i=0;i<8;i++) //1个数据就是1个字节byte,1个字节byte有8位bit
    {
        while( Read_Data == 0); //从1bit开始,低电平变高电平,等待低电平结束
        delay_us(30); //延迟30us是为了区别数据0和数据1,0只有26~28us
    
        data <<= 1; //左移
    
        if( Read_Data == 1 ) //如果过了30us还是高电平的话就是数据1
        {
        data |= 1; //数据+1
        }
    
        while( Read_Data == 1 ); //高电平变低电平,等待高电平结束
    }
    return data;
}

//获取数据
void DHT11_REC_Data(void)
{
    unsigned int R_H,R_L,T_H,T_L;
    unsigned char RH,RL,TH,TL,CHECK;
    
    DHT11_Start(); //主机发送信号
	dht11_high; //拉高电平
	
    if( Read_Data == 0 ) //判断DHT11是否响应
    {
        while( Read_Data == 0); //低电平变高电平,等待低电平结束
        while( Read_Data == 1); //高电平变低电平,等待高电平结束
        
        R_H = DHT11_Rec_Byte();
        R_L = DHT11_Rec_Byte();
        T_H = DHT11_Rec_Byte();
        T_L = DHT11_Rec_Byte();
        CHECK = DHT11_Rec_Byte(); //接收5个数据
        
        dht11_low; //当最后一bit数据传送完毕后,DHT11拉低总线 50us
        delay_us(55); //这里延时55us
        dht11_high; //随后总线由上拉电阻拉高进入空闲状态。
        
        if(R_H + R_L + T_H + T_L == CHECK) //和检验位对比,判断校验接收到的数据是否正确
        {
            RH = R_H;
            RL = R_L;
            TH = T_H;
            TL = T_L;
        }
    }
	rec_data[0] = RH;
	rec_data[1] = RL;
	rec_data[2] = TH;
	rec_data[3] = TL;
}

2.3.2.dth11.h

#ifndef _DTH11_H_
#define _DTH11_H_

#include "main.h"

#define dht11_high HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_SET)
#define dht11_low  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_RESET)
#define Read_Data  HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_3)

void DHT11_GPIO_Init_OUT(void);
void DHT11_GPIO_Init_IN(void);
void DHT11_Start(void);
unsigned char DHT11_REC_Byte(void);
void DHT11_REC_Data(void);

#endif

2.3.3.main.c

int main()
{
    DHT11_REC_Data();
    delay_ms(1000);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值