STM32
直播中

石利军

8年用户 983经验值
私信 关注
[问答]

如何对基于STM32F103 HAL库的DHT11温度传感器进行试验


如何对基于STM32F103 HAL库的DHT11温度传感器进行试验?
如何对DHT11温度传感器的引脚进行配置呢?

回帖(1)

刘萍

2021-12-8 14:44:22
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=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 ("**************************************rn");
        printf ("Hello! Welcome to use this system!rn");
        printf ("**************************************rn");
       
        /*用于检测DHT11是否正常工作,初始化失败不断提醒用户 DHT11 Checked failed!!!*/
        while(DHT11_Init())
        {
                printf("DHT11 Checked failed!!!rn");
                HAL_Delay(1000);
        };
       
        /*初始化成功*/
        printf ("**************************************rn");
        printf ("DHT11 Checked Sucess!!!rn");
        printf ("**************************************rn");
       
        /*用户需要开启温度湿度异常警告时,输入指令*/
        printf ("If you need to send an alert message, please enter 0xA0 !rn ");
        printf ("**************************************rn");
       
        /*关闭异常警告*/
        printf ("If you need to stop alert message, please enter 0xA1 !rn ");
        printf ("**************************************rn");
       
        /*温湿度输出指令*/
        printf ("If you need to view the current indoor temperature, please enter 0xA2 !rn ");
        printf ("**************************************rn");
        /*按键中断指令*/
        printf ("If you need to turn on LED1, please press KEY 1! rn");
        printf ("**************************************rn");
        printf ("If you need to toggle  LED2, please press KEY 2! rn");
        printf ("**************************************rn");
       
        /*使能串口通信接收中断*/
        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 degreern",temperature>>8,temperature&0xff);
               
                        //打印出湿度
                        printf("DHT11 Humidity = %d.%d%%rn",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 ("**************************************rn");
                printf ("Indoor temperature and humidity have been printed! rn");
                printf ("**************************************rn");
                }
  /* 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 ("**************************************rn");
                        printf ("Beep Open !rn");
                        printf ("**************************************rn");
                        /*处理完毕,再次开启接收中断*/
                        HAL_UART_Receive_IT (&huart1 ,&Rx_Data ,1);
                }
                else if (Rx_Data == 0xA1)
                {
                        /*具体的中断处理任务*/
                        Beep_Stop ;
                        printf ("**************************************rn");
                        printf ("Beep Off !rn");
                        printf ("**************************************rn");
                        /*处理完毕,再次开启接收中断*/
                        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 ("**************************************rn");
                        printf ("Input Error!rn");
                        printf ("**************************************rn");
                        /*处理完毕,再次开启接收中断*/
                        HAL_UART_Receive_IT (&huart1 ,&Rx_Data ,1);
                }


        }


}


/* USER CODE END 4 */


*/
  

  

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

更多回帖

×
20
完善资料,
赚取积分