STM32F103读取DHT22温湿度传感器参数

STM32F103读取DHT22温湿度传感器参数

1、首先通过DHT22的说明书获取操作流程 (觉得文字太多可直接向下翻,有完整.c和.h )

通信启动规则:
它有一条通信总线,空闲时总线为高电平,发送一次开始信号后,DHT22从低功耗模式转换到高速模式,通讯开始时主机(MCU)拉低总线500us后释放总线,延时20-40us后主机开始检测从机(DHT22)的响应信号。 从机的响应信号是一个80us左右的低电平,随后从机在拉高总线80us左右代表即将进入数据传送。

数据传送规则:
首先传送50us左右的低电平时隙,它代表数据位的起始,其后的高电平的长度决定数据位所代表的数值,70us的高电平代表1,26-28us的高电平代表0。 共40bit数据,当最后一Bit数据传送完毕后,从机将再次拉低总线50us左右。

下面进行分析:

(1)只有一条数据总线,所以端口既做输入也做输出,功能有拉高、拉低和读取

//其中CRH用来设置高8-15引脚,CRL用来设置0-7引脚,这里是PA0,选择CRL寄存器
#define DHT22_IO_IN()  {DHT22_PORT->CRL&=0XFFFFFFF0;DHT22_PORT->CRL|=8<<0;}//设为输入
#define DHT22_IO_OUT() {DHT22_PORT->CRL&=0XFFFFFFF0;DHT22_PORT->CRL|=3<<0;}//设为输出

#define DHT22_IO_HIGH()	GPIO_SetBits(DHT22_PORT,DHT22_PIN);    //输出1,拉高
#define DHT22_IO_LOW()	GPIO_ResetBits(DHT22_PORT,DHT22_PIN);    //输出0,拉低

#define DHT22_IO_READ (GPIO_ReadInputDataBit(DHT22_PORT,DHT22_PIN)) //读端口值

(2)空闲为高,初始化端口时让端口输出高电平。

void DHT22_Init(void)
{
    
    
 	GPIO_InitTypeDef  GPIO_InitStructure;
 	RCC_APB2PeriphClockCmd(DHT22_PORT_CLK, ENABLE);	 //使能PORTA口时钟 
 	GPIO_InitStructure.GPIO_Pin = DHT22_PIN;				//PORTA0 推挽输出
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		  
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(DHT22_PORT, &GPIO_InitStructure);
 	DHT22_IO_HIGH();    //输出1
} 

(3)开始信号,拉低500us,再拉高等待20到40us,等待传感器响应。

static void DHT22_Awake(void)//唤醒
{
    
    
	DHT22_IO_OUT();//设为输出
	DHT22_IO_LOW();//拉低500us,激活传感器
	delay_us(500);
	DHT22_IO_HIGH();//拉高,释放总线
	delay_us(30);
	DHT22_IO_IN();//等待20到40us设为输入,等待响应
}

(4)传感器响应,先拉低80us,再拉高80us

while(DHT22_IO_READ);//检测响应信号,传感器拉低80us
while((!DHT22_IO_READ));//传感器将总线拉高80us,标志马上进入数据传输

(5)传感器发送40bit的数据,根据规则进行读取

for(i = 0;i < 40;i ++)//获取40bit数据
	{
    
    
		while(DHT22_IO_READ);//等待50us低电平间隙到来

		while(!DHT22_IO_READ);//间隙结束,等待数据高电平到来

		//高电平保持26~28us表示低电平,保持70us表示高电平。
		delay_us(30);//这里等待30us,越过28us(但不能大于28+50),直接判断是不是1
		
		if(DHT22_IO_READ)//读取当前总线的状态,是不是为1
		{
    
    
		//为真则:
			data <<= 1;//右移1位空出末位
			data |= 1;//把1添入末位
		}
		else	
		//为假则:
			data <<= 1;右移1位空出末位,末位就是0
	}

(6)最后依旧释放总线,以便下次数据获取

	DHT22_IO_OUT();//设为输出
	DHT22_IO_HIGH();//拉高,释放总线

2、完整.c和.h

dht22.h

#ifndef __DHT22_H

#include "common.h"

#define DHT22_PORT 					GPIOA
#define DHT22_PIN   				GPIO_Pin_0
#define DHT22_PORT_CLK 			RCC_APB2Periph_GPIOA

//其中CRH用来设置高8-15引脚,CRL用来设置0-7引脚,这里是PA0,选择CRL寄存器
#define DHT22_IO_IN()  {DHT22_PORT->CRL&=0XFFFFFFF0;DHT22_PORT->CRL|=8<<0;}//设为输入
#define DHT22_IO_OUT() {DHT22_PORT->CRL&=0XFFFFFFF0;DHT22_PORT->CRL|=3<<0;}//设为输出


#define DHT22_IO_HIGH()	GPIO_SetBits(DHT22_PORT,DHT22_PIN);    //输出1
#define DHT22_IO_LOW()	GPIO_ResetBits(DHT22_PORT,DHT22_PIN);    //输出0
#define DHT22_IO_READ (GPIO_ReadInputDataBit(DHT22_PORT,DHT22_PIN)) //读端口值

void DHT22_Init(void);

u8 DHT22_GetValue(int* temp,u16* humi);

#endif

dht22.c

#include "dht22.h"

/*************************
*作  用:初始化传感器引脚
*参  数:无
*返回值:无
**************************/
void DHT22_Init(void)
{
    
    
 	GPIO_InitTypeDef  GPIO_InitStructure;
 	
 	RCC_APB2PeriphClockCmd(DHT22_PORT_CLK, ENABLE);	 //使能PORTA口时钟 
	
 	GPIO_InitStructure.GPIO_Pin = DHT22_PIN;				//PORTA0 推挽输出
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		  
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(DHT22_PORT, &GPIO_InitStructure);

 	DHT22_IO_HIGH();    //输出1
} 

/**************************
*作  用:唤醒传感器
*参  数:无
*返回值:无
***************************/
static void DHT22_Awake(void)
{
    
    
	DHT22_IO_OUT();//设为输出
	DHT22_IO_LOW();//拉低500us,激活传感器
	delay_us(500);
	DHT22_IO_HIGH();//拉高,释放总线
	delay_us(30);
	DHT22_IO_IN();//等待20到40us设为输入,等待响应
}

/************************************************
*作  用:与DHT传感器通信,获取数据
*参  数:无
*返回值:返回获取的40位数据,小于0xff表示失败
*************************************************/
static uint64_t DHT22_ReadData(void)
{
    
    
	u8 waitTime = 0;//响应等待时间
	u16 i = 0;//循环变量
	uint64_t data = 0;//数据存储变量
	
	DHT22_Awake();//传感器唤醒
	
	waitTime = 100;//响应超时时间设定
	while(DHT22_IO_READ)//检测响应信号,传感器拉低80us
	{
    
    
		if((waitTime--) > 0)
			delay_us(1);
		else
			return 1;
	}
	
	waitTime = 100;//响应超时时间设定
	while((!DHT22_IO_READ))//传感器将总线拉高80us,标志马上进入数据传输
	{
    
    
		if((waitTime--) > 0)
			delay_us(1);
		else
			return 2;
	}

	for(i = 0;i < 40;i ++)//获取40bit数据
	{
    
    
		waitTime = 100;//响应超时时间设定
		while(DHT22_IO_READ)//等待50us低电平间隙到来
		{
    
    
			if((waitTime--) > 0)
				delay_us(1);
			else
				return 3;
		}
		
		waitTime = 50;//响应超时时间设定
		while(!DHT22_IO_READ)//间隙结束,等待数据高电平到来
		{
    
    
			if((waitTime--) > 0)
				delay_us(1);
			else
				return 3;
		}
		
		//高电平保持26~28us表示低电平,保持70us表示高电平。
		delay_us(30);//这里等待30us,越过28us(但不能大于28+50),直接判断是不是1
		
		if(DHT22_IO_READ)//读取当前总线的状态
		{
    
    
			data <<= 1;//右移1位空出末位
			data |= 1;//把1添入末位
		}
		else	
			data <<= 1;右移1位空出末位,末位就是0
	}
	
	DHT22_IO_OUT();//设为输出
	DHT22_IO_HIGH();//拉高,释放总线
	
	return data;
}


/*****************************************
*作  用:获取温湿度传感器的检测值
*参  数:temp:用于获取温度值的变量地址
			   humi:用于获取湿度值得变量地址
*返回值:返回0成功,非0获取失败
******************************************/
u8 DHT22_GetValue(int* temp,u16* humi)
{
    
    
	uint64_t data1 = 0;
	data1 =  DHT22_ReadData();
	
	if(data1 < 0xff)//判断数据接收是否成功,大于0xff代表成功
	{
    
    
		return (u8)data1;//
	}
	
	//去掉后24位数据保留16位湿度数据
	*humi = (u16)(data1 >> 24) & 0x00ffff;
	//去掉前16位湿度数据和后8位校验数据,保留16位温度数据
	*temp = (u16)(data1 >> 8) & 0x00ffff;
	
	return 0;
}

响应超时的设定是为了便于调试,若各位不需要可直接删除。

(有不足之处,还请各位老兄不吝赐教)

猜你喜欢

转载自blog.csdn.net/qq_45100839/article/details/109232297