当前位置: 代码迷 >> 综合 >> STM32F103 HAL库 DHT11温度传感器实验
  详细解决方案

STM32F103 HAL库 DHT11温度传感器实验

热度:45   发布时间:2023-11-22 08:20:47.0

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; 	//拉低DQHAL_Delay(20);    	//拉低至少18msDHT11_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;//如果一切正常,默认返回值为0return 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)# endifmain.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 */*/

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

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