stm32驱动DHT11采集温湿度,可移植性强

一、DHT11温湿度传感器工作原理

1.单总线通信
2.DHT11工作过程:
(1)查看总线上是否存在DHT11设备以及DHT11的响应;
在这里插入图片描述
(2)DHT11发送数据
在这里插入图片描述
在这里插入图片描述
这个单总线数据的传输,类似下面的过程:
<确定传输是否可行>
老板问你:小D你在不在?(主机拉低30ms)
小 D: 老板我在?(拉低83us)
小 D: 老板收消息!(拉高87us)
<开始传输消息>
小D:传个0。 (先拉低54us,再拉高27us)
小D:再传个1哦~(先拉低54us,在拉高74us)

二、DHT11传感器驱动程序

  1. 以下两个文件是DHT11的驱动,需要后面的2、3、4步骤把它驱动起来;
//文件名:dht11.c
#include "dht11.h"
/*
tim2delay.h 使用定时做的延时函数的头文件,
可以查看博客:stm32使用定时器精确延时
*/
#include "tim2delay.h"
#define delay_ms Tim2Delayms
#define delay_us Tim2Delayus
      
//复位DHT11
void DHT11_Rst(void)	   
{                 
	DHT11_IO_OUT(GPIO_PIN_SET); 	//SET OUTPUT
    DHT11_DQ_OUT=0; 	//拉低DQ
    delay_ms(20);    	//拉低至少18ms
    DHT11_DQ_OUT=1; 	//DQ=1 
	delay_us(30);     	//主机拉高20~40us
}
//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
u8 DHT11_Check(void) 	   
{   
	u8 retry=0;
	DHT11_IO_IN();//SET INPUT	 
    while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
	{
		retry++;
		delay_us(1);
	};	 
	if(retry>=100)return 1;
	else retry=0;
    while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
	{
		retry++;
		delay_us(1);
	};
	if(retry>=100)return 1;	    
	return 0;
}
//从DHT11读取一个位
//返回值:1/0
u8 DHT11_Read_Bit(void) 			 
{
 	u8 retry=0;
	while(DHT11_DQ_IN&&retry<100)//等待变为低电平
	{
		retry++;
		delay_us(1);
	}
	retry=0;
	while(!DHT11_DQ_IN&&retry<100)//等待变高电平
	{
		retry++;
		delay_us(1);
	}
	delay_us(40);//等待40us
	if(DHT11_DQ_IN)return 1;
	else return 0;		   
}
//从DHT11读取一个字节
//返回值:读到的数据
u8 DHT11_Read_Byte(void)    
{        
    u8 i,dat;
    dat=0;
	for (i=0;i<8;i++) 
	{
   		dat<<=1; 
	    dat|=DHT11_Read_Bit();
    }						    
    return dat;
}
//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
u8 DHT11_Read_Data(u8 *temp,u8 *humi)    
{        
 	u8 buf[5];
	u8 i;
	DHT11_Rst();
	if(DHT11_Check()==0)
	{
		for(i=0;i<5;i++)//读取40位数据
		{
			buf[i]=DHT11_Read_Byte();
		}
		if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
		{
			*humi=buf[0];
			*temp=buf[2];
		}
	}else return 1;
	return 0;	    
}
//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在    	 
u8 DHT11_Init(void)
{	 
 	
 	GPIO_init_output(GPIO_PIN_SET);//初始化PB12
				    
	DHT11_Rst();  //复位DHT11
	return DHT11_Check();//等待DHT11的回应
} 

//文件名:dht11.h
#ifndef __DHT11_H
#define __DHT11_H 

#include "stdint.h"
#include "gpio.h"
//IO方向设置
#define DHT11_IO_IN()  {GPIO_init_input();}
#define DHT11_IO_OUT(STATE) {GPIO_init_output(STATE);}//state set gpio 0 or 1
//IO操作函数											   
#define	DHT11_DQ_OUT PAout(8) //数据端口	PA8
#define	DHT11_DQ_IN  PAin(8)  //数据端口	PA8


uint8_t DHT11_Init(void);//初始化DHT11
uint8_t DHT11_Read_Data(uint8_t *temp,uint8_t *humi);//读取温湿度
uint8_t DHT11_Read_Byte(void);//读出一个字节
uint8_t DHT11_Read_Bit(void);//读出一个位
uint8_t DHT11_Check(void);//检测是否存在DHT11
void DHT11_Rst(void);//复位DHT11    
#endif

  1. 因为使用的是一根引脚,但是在使用过程中做主机输出时需要为输出模式,在读取时需要为输入模式,所以宏定义DHT11_IO_IN();DHT11_IO_OUT(STATE);需要我们自己来写
void GPIO_init_input(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	/*Configure GPIO pin : PA8 */
	GPIO_InitStruct.Pin = GPIO_PIN_8;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
		
}

/*
函数名:GPIO_init_output(GPIO_PinState state)
功能:设置IO口为输出模式,state是输出高电平还是低电平
*/
void GPIO_init_output(GPIO_PinState state)
{
	
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	/*Configure GPIO pin : PB8 */
	GPIO_InitStruct.Pin = GPIO_PIN_8;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, state);
		
}


  1. 需要sys.h文件
    在这里插入图片描述
//文件名:sys.h
#ifndef _SYS_H
#define _SYS_H
#include "stm32f4xx_hal.h"

//0,²»Ö§³Öos
//1,Ö§³Öos
#define SYSTEM_SUPPORT_OS		1		//¶¨ÒåϵͳÎļþ¼ÐÊÇ·ñÖ§³ÖOS
///
//¶¨ÒåһЩ³£ÓõÄÊý¾ÝÀàÐͶ̹ؼü×Ö 
typedef int32_t  s32;
typedef int16_t s16;
typedef int8_t  s8;

typedef const int32_t sc32;  
typedef const int16_t sc16;  
typedef const int8_t sc8;  

typedef __IO int32_t  vs32;
typedef __IO int16_t  vs16;
typedef __IO int8_t   vs8;

typedef __I int32_t vsc32;  
typedef __I int16_t vsc16; 
typedef __I int8_t vsc8;   

typedef uint32_t  u32;
typedef uint16_t u16;
typedef uint8_t  u8;

typedef const uint32_t uc32;  
typedef const uint16_t uc16;  
typedef const uint8_t uc8; 

typedef __IO uint32_t  vu32;
typedef __IO uint16_t vu16;
typedef __IO uint8_t  vu8;

typedef __I uint32_t vuc32;  
typedef __I uint16_t vuc16; 
typedef __I uint8_t vuc8;  
	 
//λ´ø²Ù×÷,ʵÏÖ51ÀàËƵÄGPIO¿ØÖƹ¦ÄÜ
//IO¿Ú²Ù×÷ºê¶¨Òå
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO¿ÚµØÖ·Ó³Éä
#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014 
#define GPIOJ_ODR_ADDr    (GPIOJ_BASE+20) //0x40022414
#define GPIOK_ODR_ADDr    (GPIOK_BASE+20) //0x40022814

#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 


//IO¿Ú²Ù×÷,Ö»¶Ôµ¥Ò»µÄIO¿Ú!
//È·±£nµÄֵСÓÚ16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //Êä³ö 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //ÊäÈë 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //Êä³ö 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //ÊäÈë 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //Êä³ö 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //ÊäÈë 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //Êä³ö 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //ÊäÈë 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //Êä³ö 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //ÊäÈë

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //Êä³ö 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //ÊäÈë

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //Êä³ö 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //ÊäÈë

#define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //Êä³ö 
#define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //ÊäÈë

#define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  //Êä³ö 
#define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  //ÊäÈë

//ÒÔÏÂΪ»ã±àº¯Êý
void WFI_SET(void);		//Ö´ÐÐWFIÖ¸Áî
void INTX_DISABLE(void);//¹Ø±ÕËùÓÐÖжÏ
void INTX_ENABLE(void);	//¿ªÆôËùÓÐÖжÏ
void MSR_MSP(u32 addr);	//ÉèÖöÑÕ»µØÖ· 
#endif

4.使用定时器的延时函数,因为在使用过程中与其他模块共用延时函数,导致启动其它模块之后,DHT11就不能正常的输出温湿度数据,所以,最好使用一个独立的定时器来做延时,然后修改下面宏定义就可以了。使用独立的定时器来做精确延时见博客:

在这里插入图片描述

三、主函数调用

把下面的函数放在主函数中运行。

void Dht11GetData(void)
{
	uint8_t datapost[128];
	//strcpy((char *)datapost,"hello world");
	int flag = DHT11_Read_Data(&temp,&buf);
	
	if(flag == 0)
	{
		//printf("T:%d, H:%d\r\n",temp,buf);
		
		dataPacking(datapost,tempture,temp);
		uart2DataSend(datapost,sizeof(datapost));
		dataPacking(datapost,shidu,buf);
		uart2DataSend(datapost,sizeof(datapost));	
	}
	else
	{
		printf("err:%d\r\n",flag);
	}
	HAL_Delay(2000);
}	
  • 5
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jun8086

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值