STM32 DHT11 温湿度检测

一、硬件

F103C8T6、DHT11温湿度传感器、OLED

二、DHT11的介绍

DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。 它应用专用的数字模块采集技术和温湿度传感技术, 确保产品具有极高的可靠性与卓越的长期稳定性。只有一个DO,输出数字量,可以根据数据手册的公式将单片机读到的数值转换成温度和湿度。

三、代码实现

1、引脚初始化,并设置输入模式和输出模式。因为单片机的引脚要发送信号给DHT11模块让其开始工作,也要读取DHT11返回的数据,所以要设置输入模式和输出模式来应对不同的情况。

代码如下,第一个代码是头文件,里面有一些参数的定义

#ifndef __DHT11_H
#define __DHT11_H



#define DHT11_GPIO_TYPE  GPIOB 
#define DHT11_GPIO_PIN   GPIO_Pin_11 // pb11 
#define DHT11_RCC        RCC_APB2Periph_GPIOB


#define DHT11_OUT_H GPIO_SetBits(DHT11_GPIO_TYPE, DHT11_GPIO_PIN) //将引脚设为高电平
#define DHT11_OUT_L GPIO_ResetBits(DHT11_GPIO_TYPE, DHT11_GPIO_PIN)//将引脚设为低电平
#define DHT11_IN    GPIO_ReadInputDataBit(DHT11_GPIO_TYPE, DHT11_GPIO_PIN)//读取指定的输入端口引脚,pb11

void dht11_gpio_inital(void);
void dht11_gpio_input(void);
void dht11_gpio_output(void);
u16 dht11_scan(void);
u16 dht11_read_bit(void);
u16 dht11_read_byte(void);
u16 dht11_read_data(u8 buffer[4]);


#endif

引脚设置加上输入输出模式的设置

void dht11_gpio_input(void) // 输入模式
{
    GPIO_InitTypeDef g;
    
    RCC_APB2PeriphClockCmd(DHT11_RCC, ENABLE);
    
    g.GPIO_Pin = DHT11_GPIO_PIN;
    g.GPIO_Speed = GPIO_Speed_50MHz;
    g.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
    
    GPIO_Init(DHT11_GPIO_TYPE, &g);
}

void dht11_gpio_output(void) // 输出模式
{
    GPIO_InitTypeDef g;
    
    RCC_APB2PeriphClockCmd(DHT11_RCC, ENABLE);
    
    g.GPIO_Pin = DHT11_GPIO_PIN;
    g.GPIO_Speed = GPIO_Speed_50MHz;
    g.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出

    GPIO_Init(DHT11_GPIO_TYPE, &g);
}

2、DHT11初始化函数

从数据手册得知,用户主机(MCU) 发送一次开始信号后, DHT11从低功耗模式转换到高速模式, 待主机开始信号结束后, DHT11发送响应信号, 送出40bit的数据, 并触发一次信采集。

时序图如下

数据手册的步骤原文如下:

步骤一:
DHT11上电后(DHT11上电后要等待1S以越过不稳定状态在此期间不能发送任何指令) , 测
试环境温湿度数据, 并记录数据, 同时DHT11的DATA数据线由上拉电阻拉高一直保持高电平;
此时DHT11的DATA引脚处于输入状态, 时刻检测外部信号。
步骤二:
微处理器的I/O设置为输出同时输出低电平, 且低电平保持时间不能小于18ms(最大不得
超过30ms) , 然后微处理器的I/O设置为输入状态, 由于上拉电阻, 微处理器的I/O即DHT11的
DATA数据线也随之变高, 等待DHT11作出回答信号。 发送信号如图4所示:

步骤三:
DHT11的DATA引脚检测到外部信号有低电平时, 等待外部信号低电平结束, 延迟后DHT11的
DATA引脚处于输出状态, 输出83微秒的低电平作为应答信号, 紧接着输出87微秒的高电平通知
外设准备接收数据, 微处理器的I/O此时处于输入状态, 检测到I/O有低电平(DHT11回应信号)
后, 等待87微秒的高电平后的数据接收, 发送信号如图5所示:
 

步骤四:
由DHT11的DATA引脚输出40位数据, 微处理器根据I/O电平的变化接收40位数据, 位数据
“0” 的格式为: 54微秒的低电平和23-27微秒的高电平, 位数据“1” 的格式为: 54微秒的低
电平加68-74微秒的高电平。 位数据“0” 、 “1” 格式信号如图6所示:
 

结束信号:
DHT11的DATA引脚输出40位数据后, 继续输出低电平54微秒后转为输入状态, 由于上拉电
阻随之变为高电平。 但DHT11内部重测环境温湿度数据, 并记录数据, 等待外部信号的到来。
 

我所理解的要读取DHT11的数据的步骤如下:

1、有时序图得知,单片机先设置为输出模式,输出一个低平(不小于18ms,不大于30ms),然后转为高平,发送给DHT11一个开始信号

2、因为DHT11接收到开始信号后要过83+87us的时间后才发数据,因此我们延时一段时间后设为输入模式来读取发送来的数据

代码如下

void dht11_reset(void)
{
    // 按照DHT11手册步骤,时序图
    dht11_gpio_output();//微处理器(32单片机)输出
    DHT11_OUT_L;//pb11 低电平
    Delay_us(19000);
    DHT11_OUT_H;//转到高电平
	Delay_us(30);
    dht11_gpio_input();//输入
}


3、读取温湿度的数据

 

传入的数据也是一端0101的二进制代码,因此我们编写的代码也要一位一位的读入,八位一个字节,每两个字节组合保存温度或湿度的数据

读取时注意,0的高平时间23,1的高平时间68,所以代码里按位读取时,延时40us,若还是高平怎是发送1,否则就是发送0,别的就没有什么了。 

//读的是当 IO 口设置为输入状态时候的 IO 口电平状态值,set = 高电平, reset = 低电平
u16 dht11_scan(void)
{
    return DHT11_IN;
}


//dht11 的数据有四十位,分别包含不同的信息
u16 dht11_read_bit(void)
{
    while (DHT11_IN == RESET);
    Delay_us(40);
    if (DHT11_IN == SET)
    {
        while (DHT11_IN == SET);
        return 1;
    }
    else
    {
        return 0;
    }
}

u16 dht11_read_byte(void)
{
    u16 i;
    u16 data = 0;
    for (i = 0; i < 8; i++)
    {
        data <<= 1;//向左进一位
        data |= dht11_read_bit();
    }
    return data;
}


u16 dht11_read_data(u8 buffer[5])
{
    u16 i = 0;
    
    dht11_reset();
    if (dht11_scan() == RESET)
    {
        //检测到DHT11响应
        while (dht11_scan() == RESET);
        while (dht11_scan() == SET);
        for (i = 0; i < 5; i++)
        {
            buffer[i] = dht11_read_byte();
        }
        //dht11 输出的40位数据
        while (dht11_scan() == RESET);
        dht11_gpio_output();
        DHT11_OUT_H;
        
        u8 checksum = buffer[0] + buffer[1] + buffer[2] + buffer[3];
        if (checksum != buffer[4])
        {
            // checksum error,数据出错,
            return 1;
        }
    }
    
    return 0;
}

 4.主函数部分,OLED显示温湿度

u8 buffer[5];
double hum;
double temp;
if (dht11_read_data(buffer) == 0)//读取正常
{
	hum = buffer[0] + buffer[1] / 10.0;
    temp = buffer[2] + buffer[3] / 10.0;
		
		
}
OLED_ShowString(2,1,"humity");
OLED_ShowNum(2,8,hum,3);
OLED_ShowString(3,1,"temperature");
OLED_ShowNum(3,13,temp,3);

  • 2
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值