xzy610030

一起探讨,一起进步,一起分享!

stm32F4----DHT22(AM2302)数字温湿度传感器读取(六)

1
阅读(5250)

经过了自己用FPGA来驱动DHT22,http://blog.chinaaet.com/xzy610030/p/5100051014

下面开始用STM32F4来读取温湿度了。

首先非常感谢他人的原创,受益匪浅:http://blog.csdn.net/xiayufeng520/article/details/46292899

最后实现如下:

am2302.h

#ifndef   _AM2302_H
#define   _AM2302_H
#ifdef  _cplusplus
   extern "C" {
#endif

#include "stm32f4xx.h"

//AM2302  IO  define
#define  AM2302_GPIO_PORT  GPIOG
#define  AM2302_PIN        GPIO_Pin_0		 
#define  AM2302_GPIO_CLK   RCC_AHB1Periph_GPIOG
		 
//
#define  HIGH    1
#define  LOW     0

typedef  struct
{
  uint8_t   humiHighByte;
	uint8_t   humiLowByte;
	uint8_t   temmHighByte;
	uint8_t   temmLowByte;
	uint8_t   check_num;
}AM2302_Data_TypeDef;
		 
//带参宏,可以像内联函数一样使用,输出高电平或低电平  
#define  AM2302_DATA_OUT(a) if (a)  \
                    GPIO_SetBits(AM2302_GPIO_PORT,AM2302_PIN);\
                    else        \
                    GPIO_ResetBits(AM2302_GPIO_PORT,AM2302_PIN)  
 //读取引脚的电平  
#define  AM2302_DATA_IN()      GPIO_ReadInputDataBit(AM2302_GPIO_PORT,AM2302_PIN)  		 
		 
void AM2302_GPIO_Config(void);  
static void AM2302_Mode_IPU(void);  
static void AM2302_Mode_Out_PP(void);  
uint8_t Read_AM2302(AM2302_Data_TypeDef *AM2302_Data);  
static uint8_t Read_Byte(void);  
										
										
#ifdef  _cplusplus
   }
#endif
   
#endif


am2302.c如下:

#include "am2302.h"
#include "delay.h"
/*
 *函数名:
 *描述  :
 *输入  :
 *输出  :
*/
void AM2302_GPIO_Config(void)
{
  //定义一个GPIO_InitTypeDef类型结构体
	GPIO_InitTypeDef   GPIO_InitStructure;
	
	//开启GPIO 外设时钟
	 RCC_AHB1PeriphClockCmd(AM2302_GPIO_CLK, ENABLE);
	
	//选择要控制的GPIO 引脚
	GPIO_InitStructure.GPIO_Pin  =  AM2302_PIN;
	
	//设置引脚模式为通用推挽输出
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_OUT;
	
	//设置引脚速率为50MHz 
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
       
  //调用库函数,初始化GPIO_AM2302  
  GPIO_Init(AM2302_GPIO_PORT, &GPIO_InitStructure);            
       
	//拉高PIN_AM2302 
  GPIO_SetBits(AM2302_GPIO_PORT, AM2302_PIN);    
	
	
}

/* 
 * 函数名:AM2302_Mode_IPU 
 * 描述  :使AM2302-DATA引脚变为输入模式 
 * 输入  :无 
 * 输出  :无 
 */  
static void AM2302_Mode_IPU(void)  
{  
      GPIO_InitTypeDef GPIO_InitStructure;  
       
        /*选择要控制的GPIOD引脚*/    
      GPIO_InitStructure.GPIO_Pin = AM2302_PIN;  
       
       /*设置引脚模式为浮空输入模式*/  
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN ;   
       
      /*调用库函数,初始化GPIOD*/  
      GPIO_Init(AM2302_GPIO_PORT, &GPIO_InitStructure);     
}  

/* 
 * 函数名:AM2302_Mode_Out_PP 
 * 描述  :使AM2302-DATA引脚变为输出模式 
 * 输入  :无 
 * 输出  :无 
 */  
static void AM2302_Mode_Out_PP(void)  
{  
    GPIO_InitTypeDef GPIO_InitStructure;  
       
        /*选择要控制的GPIOD引脚*/                                                               
    GPIO_InitStructure.GPIO_Pin = AM2302_PIN;     
       
    /*设置引脚模式为通用推挽输出*/  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;     
       
    /*设置引脚速率为50MHz */    
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
       
    /*调用库函数,初始化GPIOD*/  
    GPIO_Init(AM2302_GPIO_PORT, &GPIO_InitStructure);           
} 

static uint8_t Read_Byte(void)  
{       
       
   uint8_t i, temp=0;  
       
     for(i=0;i<8;i++)      
     {  
            
       /*每bit以50us低电平标置开始,轮询直到从机发出 的50us 低电平 结束*/   
        while(AM2302_DATA_IN()  ==  Bit_RESET) {} 
                
         /*AM2302 以22~30us的高电平表示“0”,以68~75us高电平表示“1”, 
             通过检测60us后的电平即可区别这两个状态*/  
       
         Delay_us(30); //延时50us              
           
          if(AM2302_DATA_IN() == Bit_SET)//60us后仍为高电平表示数据“1”  
           {  
              /*轮询直到从机发出的剩余的 30us 高电平结束*/  
                 while(AM2302_DATA_IN()==Bit_SET);  
       
                 temp|=(uint8_t)(0x01<<(7-i));  //把第7-i位置1   
                   
           }  
           else  //60us后为低电平表示数据“0”  
           {                 
              temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0  
           }  
     }  
     return temp;  
}  

uint8_t Read_AM2302(AM2302_Data_TypeDef *AM2302_Data)  
{    
    /*输出模式*/  
    unsigned char tmp;
   AM2302_Mode_Out_PP();  
   AM2302_DATA_OUT(HIGH);  
	 Delay_ms(2); 
   /*主机拉低*/  
   AM2302_DATA_OUT(LOW);  
   /*延时2ms*/  
   Delay_ms(2);  
       
   /*总线拉高 主机延时30us*/  
   AM2302_DATA_OUT(HIGH);   
       
   Delay_us(30);   //延时30us  
          
    /*主机设为输入 判断从机响应信号*/  
   AM2302_Mode_IPU();  
       
 /*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/    
   if(AM2302_DATA_IN()==Bit_RESET)   //T !     
    {  
                
      /*轮询直到从机发出 的80us 低电平 响应信号结束*/   
        while(AM2302_DATA_IN()==Bit_RESET){}  
                
      /*轮询直到从机发出的 80us 高电平 标置信号结束*/  
        while(AM2302_DATA_IN()==Bit_SET){}  
       
      /*开始接收数据*/    
         AM2302_Data->humiHighByte= Read_Byte();  
                                       
         AM2302_Data->humiLowByte= Read_Byte();  
                       
         AM2302_Data->temmHighByte= Read_Byte();  
       
         AM2302_Data->temmLowByte= Read_Byte();  
                               
         AM2302_Data->check_num= Read_Byte();  
                                                 
       
         /*读取结束,引脚改为输出模式*/  
    AM2302_Mode_Out_PP();  
        /*主机拉高*/  
        AM2302_DATA_OUT(HIGH);  
       
        /*检查读取的数据是否正确*/  
        tmp = AM2302_Data->humiHighByte + AM2302_Data->humiLowByte + AM2302_Data->temmHighByte+ AM2302_Data->temmLowByte;
        if(AM2302_Data->check_num == tmp )  
          return SUCCESS;  
        else  
          return ERROR;  
   }  
   else  
   {          
          return ERROR;  
   }  
          
}


delay.c这里定义了两个delay函数,如下;

void Delay_us(__IO u32 us)
{
	 u32 temp;
   SysTick->LOAD =  180 * us;
   SysTick->VAL  =  0x00;
	 SysTick->CTRL =  0x0005;
   temp  = SysTick->CTRL;
	 while((temp & 0x01) && (!(temp & (1 << 16))))
	 {
	   temp = SysTick->CTRL;
	 }
	 SysTick->VAL  =  0x00;
	 SysTick->CTRL =  0x00;
} 

void Delay_ms(__IO u32 ms)
{
	 u32 temp;
   SysTick->LOAD =  180000 * ms;
   SysTick->VAL  =  0x00;
	 SysTick->CTRL =  0x0005;
   temp  = SysTick->CTRL;
	 while((temp & 0x01) && (!(temp & (1 << 16))))
	 {
	   temp = SysTick->CTRL;
	 }
	 SysTick->VAL  =  0x00;
	 SysTick->CTRL =  0x00;
}


main.c

  while(1)
	{

		/*调用Read_AM2302读取温湿度,若成功则输出该信息*/  
    if( Read_AM2302(&AM2302_Data)==SUCCESS)  
    {             
      //计算出实际湿度值的10倍  
      RH_Value= AM2302_Data.humiHighByte*256 + AM2302_Data.humiLowByte;  
      RH_H = RH_Value/10;  
      RH_L = RH_Value%10;  
      //计算出时间温度值的10倍  
      TEMP_Value = AM2302_Data.temmHighByte*256 + AM2302_Data.temmLowByte;  
      TP_H = TEMP_Value/10;  
      TP_L = TEMP_Value%10;  
      printf("\r\n读取AM2302成功!\r\n\r\n湿度为%d.%d %RH,温度为 %d.%d℃ \r\n",RH_H,RH_L,TP_H,TP_L);//“\”表示转向一下行  
     }  
        else  
            printf("Read AM2302 ERROR!\r\n");


原博主的代码是没法直接通过的,和博主不一样的地方有下:

(1)GPIO那里,F1和F4是不一样的,  

GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_OUT;

 (2)用系统定时器编写了两个定时函数

void Delay_ms(__IO u32 ms)
void Delay_us(__IO u32 us)

(3)最要的是这里:

AM2302_DATA_OUT(HIGH);

先拉高,在开始通信,这部分在FPGA也是这样处理的,这里又调试了好久。-------千万注意

(4)这里是一定要这样:

        tmp = AM2302_Data->humiHighByte + AM2302_Data->humiLowByte + AM2302_Data->temmHighByte+ AM2302_Data->temmLowByte;

如果,采用博主的

结果如下:

1.png