STM32F103 HAL库 DHT11温度传感器实验


STM32F103 HAL库 DHT11温度传感器实验


写在前面
绝对不坑人,保证有用,亲测有效。
作为刚刚接触STM32的小白,我深知找不到非常有效的参考资料的痛苦,同时也避免以后忘记相关的方法,因此写下这篇博客,作为学习笔记。
元器件准备:由于我使用的是野火的STM32F103mini开发板,因此没有购买单独的温度传感器模块,使用了自带的温度传感器。
对于DHT11的资料介绍就不在这里赘述,我相信你肯定已经找到了许多相关资料,我们废话少说,直接上代码。
第一部分:CUBEMX 配置
在这里插入图片描述

KEY1,KEY2 用于产生按键中断
LED1,LED2 是开发板上的LED,用于按键中断实验,也用于发送提示信息
Beep 是蜂鸣器的引脚,蜂鸣器用于在温度异常的时候发出报警信号
实验需要使用串口,用户指令通过串口发送到单片机,单片机的信息通过串口发送到上位机,串口的具体配置如下:
在这里插入图片描述
这部分保持默认配置即可。
在这里插入图片描述
需要使能串口接收中断。用于处理用户指令。
在这里插入图片描述
DHT11引脚的配置。
其他的引脚只需要配置为默认的推挽输出即可。
时钟以及工程配置不在赘述。
接下来是代码部分。


/*
/*DHT11.C文件*/
 # include "DHT11.h"
 # include "tim.h"

/*根据DHT11的工作特性,需要改变引脚的工作状态*/
// 输入模式
void DHT11_IO_IN(void)
{
    
    
	GPIO_InitTypeDef GPIO_InitStructure;
	
	GPIO_InitStructure.Pin = GPIO_PIN_0;
	GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
	HAL_GPIO_Init(GPIOC,&GPIO_InitStructure);
}

// 输出模式
void DHT11_IO_OUT(void)
{
    
    
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.Pin = GPIO_PIN_0;
	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOC,&GPIO_InitStructure);
}


/* 触发DHT11工作状态的信号,涉及到IO口电平的拉高以及拉低,
 一次在.h文件中进行宏定义,方便程序移植*/
void DHT11_Start (void)	   
{
    
                     
	DHT11_IO_OUT(); 	//设置为输出
	DHT11_DQ_OUT_LOW; 	//拉低DQ
	HAL_Delay(20);    	//拉低至少18ms
	DHT11_DQ_OUT_HIGH; 	//DQ=1 
	Delay_us (30);    	//主机拉高20~40us
}
/*为了确保DHT11处于工作状态,这里需要定义一个函数,用于检测DHT11是否处于工作状态*/
/*检测原理:DHT11收到触发信号后可以正常工作,将会产生80us的低电平,80us 的高电平*/
/*通过检测电平状态,确定是否处于工作状态,返回值为0 表示正常工作,返回值为1,表示工作异常*/
uint8_t  DHT11_Check (void)
{
    
    
	//避免程序被卡死在某一个循环
	uint8_t Retry = 0 ;
	//设置为输入模式
	DHT11_IO_IN ();
	//需要读取电平,为了方便程序移植,使用宏定义
	//通过循环等待低电平结束,如果超过等待期限,则跳出循环
	while (DHT11_IN == GPIO_PIN_RESET && Retry < 100)
	{
    
    
		Retry ++ ;
		Delay_us (1);
	};
	//通过判断Retry 的值来判断是否有DHT11
	//如果大于100,直接结束函数,返回工作异常
	if(Retry >= 100) 
	{
    
    
		return 1;
	}
	//如果小于100,说明正常工作,Retry = 0 ;进入高电平检测阶段
	else Retry = 0 ;
	/*低电平检测完成之后进入高电平检测*/
	while (DHT11_IN == GPIO_PIN_SET && Retry < 100)
	{
    
    
		Retry ++ ;
		Delay_us (1);
	}
	//通过判断Retry 的值来判断是否有DHT11
	//如果大于100,直接结束函数,返回工作异常
	if(Retry >= 100) return 1;
	//如果一切正常,默认返回值为0
	return 0 ;
	
}

/*完成以上阶段之后,进入数据读取阶段,数据读取的方式为:读取一个字->读取一个字节->读取完整数据*/
/*读取一个字节*/
uint8_t DHT11_ReadBit(void)
{
    
    
	uint8_t Retry = 0;
	/*数据读取都是以50us 的低电平开始,然后进入高电平,如果高电平持续时间为26-28us则为数据“0”*/
	/*如果高电平为70us 则为数据“1”*/
	//等待高电平结束.这里的高电平为响应信号的80us 高电平
	while(DHT11_IN == GPIO_PIN_SET && Retry<100)
	{
    
    
		Retry++;
		Delay_us(1);
	};
	Retry = 0 ;
	//等待低电平结束(数据传输之前的50us低电平)
	while (DHT11_IN == GPIO_PIN_RESET && Retry < 100)
	{
    
    
		Retry ++ ;
		Delay_us (1);
	};
	//延时等待
	Delay_us (40);
	//延时结束仍然为高电平
	if(DHT11_IN == GPIO_PIN_SET ) return 1 ;
	//延时结束已经变成低电平
	else return 0 ;
}


/*读取一字节:循环调用八次读取一字的函数,将读取到的数据放在一字节的存储空间中*/
uint8_t DHT11_ReadByte(void)
{
    
    
	uint8_t i, Data = 0 ;
	//循环八次
	for(i = 0 ;i < 8 ;i ++)
	{
    
    
		Data <<=1 ; 
	  Data |=  DHT11_ReadBit() ;
	}
	return Data ;
	
}


//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
uint8_t DHT11_ReadData(uint16_t *temp,uint16_t *humi)    
{
    
    
	//定义五位数组,用于存放读取的数据
 	uint8_t buf[5];
	uint8_t i;
	
	//发送开始信号
	DHT11_Start ();
	
	if(DHT11_Check()==0)
	{
    
    
		for(i=0;i<5;i++)//读取40位数据
		{
    
    
			buf[i]=DHT11_ReadByte();
		}
		if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
		{
    
    
			*humi=(buf[0]<<8) + buf[1];
			*temp=(buf[2]<<8) + buf[3];
		}
	}
	//如果检测到DHT11工作异常,返回异常信号
	else return 1;
	
	return 0;	    
}


//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在     	 
uint8_t DHT11_Init(void)
{
    
     
  DHT11_Start ();
	return DHT11_Check();
}

DHT11.h文件
 # ifndef __DHT11_H
 # define __DHT11_H


#include "main.h"
 /*IO电平高低状态宏定义*/
 //拉高
 # define DHT11_DQ_OUT_HIGH  HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0,GPIO_PIN_SET)
//拉低
 # define DHT11_DQ_OUT_LOW 	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0,GPIO_PIN_RESET)
/*电平读取宏定义*/
 # define DHT11_IN           HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_0)

// 输入模式
void DHT11_IO_IN(void);

// 输出模式
void DHT11_IO_OUT(void);

/* 触发DHT11工作状态的信号,涉及到IO口电平的拉高以及拉低,
 一次在.h文件中进行宏定义,方便程序移植*/
void DHT11_Start (void);

/*延时函数申明,在tim.c文件中定义,如果此处不申明,会有警告*/
 void Delay_us (uint32_t us);
	
/*一字数据读取*/
uint8_t DHT11_ReadBit(void);
	
/*读取一字节数据*/	
 uint8_t DHT11_ReadByte(void);
	
/*读取一次完整数据*/
uint8_t DHT11_ReadData(uint16_t *temp,uint16_t *humi);
	
/*DHT11状态检测函数*/
uint8_t  DHT11_Check (void);

//初始化DHT11的IO口 DQ 同时检测DHT11的存在
uint8_t DHT11_Init(void)# endif

main.c 

/*用户变量定义,需要放在最开始部分*/
/*定义接收缓冲区*/
	uint8_t Rx_Data = 0 ;
	/*定义温度全局变量*/
	uint16_t temperature;
	/*定义湿度全局变量*/
	uint16_t humidity;
	/*用于发送起始信号*/
	uint8_t START = 0 ;
	/*用于程序的循环结构变量*/
	uint8_t i = 0 ;


/*	用户宏定义*/
 # define Beep_Start       	HAL_GPIO_WritePin (Beep_GPIO_Port ,Beep_Pin ,GPIO_PIN_SET );
 # define Beep_Stop       	  HAL_GPIO_WritePin (Beep_GPIO_Port ,Beep_Pin ,GPIO_PIN_RESET );

/*用户代码*/
/* USER CODE BEGIN 2 */
	
	/*打印开启系统提示,提高系统的人机交互体验*/
	printf ("**************************************\r\n");
	printf ("Hello! Welcome to use this system!\r\n");
	printf ("**************************************\r\n");
	
	/*用于检测DHT11是否正常工作,初始化失败不断提醒用户 DHT11 Checked failed!!!*/
	while(DHT11_Init())
	{
    
    
		printf("DHT11 Checked failed!!!\r\n");
		HAL_Delay(1000);
	};
	
	/*初始化成功*/
	printf ("**************************************\r\n");
	printf ("DHT11 Checked Sucess!!!\r\n");
	printf ("**************************************\r\n");
	
	/*用户需要开启温度湿度异常警告时,输入指令*/
	printf ("If you need to send an alert message, please enter 0xA0 !\r\n ");
	printf ("**************************************\r\n");
	
	/*关闭异常警告*/
	printf ("If you need to stop alert message, please enter 0xA1 !\r\n ");
	printf ("**************************************\r\n");
	
	/*温湿度输出指令*/
	printf ("If you need to view the current indoor temperature, please enter 0xA2 !\r\n ");
	printf ("**************************************\r\n");
	/*按键中断指令*/
	printf ("If you need to turn on LED1, please press KEY 1! \r\n");
	printf ("**************************************\r\n");
	printf ("If you need to toggle  LED2, please press KEY 2! \r\n");
	printf ("**************************************\r\n");
	
	/*使能串口通信接收中断*/
	HAL_UART_Receive_IT (&huart1 ,&Rx_Data ,1);
	
  /* USER CODE END 2 */
while (1)
  {
    
    
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		
		/*用于等待用户输入指令*/
		while(!START );
		START = 0 ;
		
		/*五次打印出实时温度与湿度*/
		while(i<5)
		{
    
    
			//调用数据读取函数,读取完整数据
			DHT11_ReadData (&temperature,&humidity);
		
			//打印出温度
			printf("DHT11 Temperature = %d.%d degree\r\n",temperature>>8,temperature&0xff);
		
			//打印出湿度
			printf("DHT11 Humidity = %d.%d%%\r\n",humidity>>8,humidity&0xff);
		
			//翻转电平,提示打印完成
			HAL_GPIO_TogglePin(LED1_GPIO_Port ,LED1_Pin );
			HAL_Delay(1000);
			HAL_GPIO_TogglePin(LED1_GPIO_Port ,LED1_Pin );
			/*循环体变量自加*/
			i++;
		}
		/*提示用户温度打印完毕*/
		printf ("**************************************\r\n");
		printf ("Indoor temperature and humidity have been printed! \r\n");
		printf ("**************************************\r\n");
		}
  /* USER CODE END 3 */
}


/* USER CODE BEGIN 4 */

/*按键中断回调函数*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    
    
	uint8_t i ;
	/*判断中断来源*/
	if(GPIO_Pin == KEY1_Pin )
	{
    
    
		/*中断处理任务,翻转电平*/
			HAL_GPIO_TogglePin (LED1_GPIO_Port ,LED1_Pin );
		__HAL_GPIO_EXTI_CLEAR_IT (KEY1_Pin );
	}
	
	else if (GPIO_Pin == KEY2_Pin )
	{
    
    
		for(i = 0;i<10;i++)
		{
    
    
			HAL_GPIO_TogglePin (LED2_GPIO_Port ,LED2_Pin );
			HAL_Delay (500);
			__HAL_GPIO_EXTI_CLEAR_IT (KEY1_Pin );
		}
			
	}
		
}

/*串口接收与发送中断回调函数*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    
    
	/*判断具体的接受中断来源*/
	if(huart == &huart1 )
	{
    
    
		/*判断接收指令*/
		if(Rx_Data == 0xA0)
		{
    
    
			/*具体的中断处理任务*/
			Beep_Start ;
			printf ("**************************************\r\n");
			printf ("Beep Open !\r\n");
			printf ("**************************************\r\n");
			/*处理完毕,再次开启接收中断*/
			HAL_UART_Receive_IT (&huart1 ,&Rx_Data ,1);
		}
		else if (Rx_Data == 0xA1)
		{
    
    
			/*具体的中断处理任务*/
			Beep_Stop ;
			printf ("**************************************\r\n");
			printf ("Beep Off !\r\n");
			printf ("**************************************\r\n");
			/*处理完毕,再次开启接收中断*/
			HAL_UART_Receive_IT (&huart1 ,&Rx_Data ,1);
		}
			
		else if (Rx_Data == 0xA2) 
		{
    
    
			/*具体的中断处理任务*/
			START = 1 ;//输入指令0xA2,开启温湿度采集
			/*处理完毕,再次开启接收中断*/
			HAL_UART_Receive_IT (&huart1 ,&Rx_Data ,1);
		}
		else 
		{
    
    
			/*输入错误提示*/
			printf ("**************************************\r\n");
			printf ("Input Error!\r\n");
			printf ("**************************************\r\n");
			/*处理完毕,再次开启接收中断*/
			HAL_UART_Receive_IT (&huart1 ,&Rx_Data ,1);
		}

	}

}

/* USER CODE END 4 */

*/

在这里插入图片描述
效果图如上。

只要建立相对应的文件,把代码复制到正确的位置,保证能够运行,亲测有效。
如果有不到位的地方还请大佬批评指正。

猜你喜欢

转载自blog.csdn.net/qq_52111026/article/details/117447013