STM32F1驅動AM2302溫濕度傳感器


先來個AM2302的自我介紹:
         AM2302數字溫濕度傳感器是一款含有已校准數字信號輸出的溫濕度復合傳感器。它應用專用的數字模塊采集技術和溫濕度傳感技術,確保產品具有極高的可靠性與卓越的長期穩定性。傳感器包括一個電容式感濕元件和一個NTC測溫元件,並與一個高性能8位單片機相連接。因此該產品具有品質卓越、超快響應、抗干擾能力強、性價比極高等優點。每個AM2302傳感器都在極為精確的濕度校驗室中進行校准。校准系數以程序的形式儲存在OTP內存中,傳感器內部在檢測信號的處理過程中要調用這些校准系數。單線制串行接口,使系統集成變得簡易快捷。超小的體積、極低的功耗,信號傳輸距離可達20米以上,使其成為各類應用甚至最為苛刻的應用場合的最佳選則。產品為 4 針單排引腳封裝。連接方便,特殊封裝形式可根據用戶需求而提供。

重要的來了啊:AM2302時序圖


單總線通信特殊說明: 
1.典型應用電路中建議連接線長度短於30米時用5.1K上拉電阻,大於30米時根據實際情況降低上拉電阻的阻值。 
2.使用3.3V電壓供電時連接線長度不得大於30cm。否則線路壓降會導致傳感器供電不足,造成測量偏差。 
3.讀取傳感器最小間隔時間為2S;讀取間隔時間小於2S,可能導致溫濕度不准或通信不成功等情況。 
4.每次讀出的溫濕度數值是上一次測量的結果,欲獲取實時數據,需連續讀取兩次, 建議連續多次讀取傳感器,且每次讀取傳感器間隔大於2秒即可獲得准確的數據。
看到這里相信對AM2302有了一定了解了。下面開始貼出程序,共同驅動AM2302吧。
先來主函數把

/***********************************************************************************
 * 文件名  :main.c
 * 描述    :         
 * 實驗平台:神舟III號
 * 庫版本  :ST3.5
 * 作者    :xiayufeng  xiayufeng90520@163.com 
 * 博客    :http://hi.baidu.com/xiayufeng520
**********************************************************************************/
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "usart1.h"
#include "am2302.h"
      
AM2302_Data_TypeDef AM2302_Data;
      
/*                                               
************************************************************************
函 數 名: int main(void)
      
功    能: 主函數
      
入口參數: None
      
返 回 值: None
        
其他說明: None
      
調用形式: None   
************************************************************************
*/
int main(void)
{
    unsigned int RH_Value,TEMP_Value;
    unsigned char RH_H,RH_L,TP_H,TP_L;
    Led_Init(); //LED初始化
    Delay_Init();//Delay初始化
    USART1_Init();//串口初始化
          
    AM2302_GPIO_Config();//AM2302管腳初始化  
      
    while(1)
    {
        /*調用Read_AM2302讀取溫濕度,若成功則輸出該信息*/
        if( Read_AM2302(&AM2302_Data)==SUCCESS)
        {           
            //計算出實際濕度值的10倍
            RH_Value= AM2302_Data.humi_int*256 + AM2302_Data.humi_deci;
            RH_H = RH_Value/10;
            RH_L = RH_Value%10;
            //計算出時間溫度值的10倍
            TEMP_Value = AM2302_Data.temp_int*256 + AM2302_Data.temp_deci;
            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");
              
        Led_Turn(LED2,LED_ON);
        Delay_ms(1100);
        Led_Turn(LED2,LED_OFF);
        Delay_ms(1100);
    }
}
再來AM2302的頭文件部分:

#ifndef __AM2302_H
#define __AM2302_H
      
#include "stm32f10x.h"
#include "delay.h"
      
#define RCC_GPIO_AM2302   RCC_APB2Periph_GPIOF
#define GPIO_AM2302       GPIOF
#define PIN_AM2302        GPIO_Pin_6
#define HIGH  1
#define LOW   0
      
typedef struct
{
    uint8_t  humi_int;      //濕度的整數部分
    uint8_t  humi_deci;     //濕度的小數部分
    uint8_t  temp_int;      //溫度的整數部分
    uint8_t  temp_deci;     //溫度的小數部分
    uint8_t  check_sum;     //校驗和
                               
}AM2302_Data_TypeDef;
      
//帶參宏,可以像內聯函數一樣使用,輸出高電平或低電平
#define  AM2302_DATA_OUT(a) if (a)  \
                    GPIO_SetBits(GPIO_AM2302,PIN_AM2302);\
                    else        \
                    GPIO_ResetBits(GPIO_AM2302,PIN_AM2302)
 //讀取引腳的電平
#define  AM2302_DATA_IN()      GPIO_ReadInputDataBit(GPIO_AM2302,PIN_AM2302)
      
      
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);
      
#endif /* __AM2302_H */
最后來AM2302的實現函數部分:

#include "am2302.h"
     
/*
 * 函數名:AM2302_GPIO_Config
 * 描述  :配置AM2302用到的I/O口
 * 輸入  :無
 * 輸出  :無
 */
void AM2302_GPIO_Config(void)
{       
    /*定義一個GPIO_InitTypeDef類型的結構體*/
    GPIO_InitTypeDef GPIO_InitStructure;
     
    /*開啟GPIOF的外設時鍾*/
    RCC_APB2PeriphClockCmd( RCC_GPIO_AM2302, ENABLE); 
     
    /*選擇要控制的GPIOF引腳*/                                                             
    GPIO_InitStructure.GPIO_Pin = PIN_AM2302;   
     
    /*設置引腳模式為通用推挽輸出*/
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   
     
    /*設置引腳速率為50MHz */  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
     
    /*調用庫函數,初始化GPIO_AM2302*/
    GPIO_Init(GPIO_AM2302, &GPIO_InitStructure);          
     
    /* 拉高PIN_AM2302 */
    GPIO_SetBits(GPIO_AM2302, PIN_AM2302);   
}
     
/*
 * 函數名:AM2302_Mode_IPU
 * 描述  :使AM2302-DATA引腳變為輸入模式
 * 輸入  :無
 * 輸出  :無
 */
static void AM2302_Mode_IPU(void)
{
      GPIO_InitTypeDef GPIO_InitStructure;
     
        /*選擇要控制的GPIOD引腳*/  
      GPIO_InitStructure.GPIO_Pin = PIN_AM2302;
     
       /*設置引腳模式為浮空輸入模式*/
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ; 
     
      /*調用庫函數,初始化GPIOD*/
      GPIO_Init(GPIO_AM2302, &GPIO_InitStructure);   
}
     
/*
 * 函數名:AM2302_Mode_Out_PP
 * 描述  :使AM2302-DATA引腳變為輸出模式
 * 輸入  :無
 * 輸出  :無
 */
static void AM2302_Mode_Out_PP(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
     
        /*選擇要控制的GPIOD引腳*/                                                             
    GPIO_InitStructure.GPIO_Pin = PIN_AM2302;   
     
    /*設置引腳模式為通用推挽輸出*/
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   
     
    /*設置引腳速率為50MHz */  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     
    /*調用庫函數,初始化GPIOD*/
    GPIO_Init(GPIO_AM2302, &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(5); //延時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)
{  
    /*輸出模式*/
   AM2302_Mode_Out_PP();
   /*主機拉低*/
   AM2302_DATA_OUT(LOW);
   /*延時2ms*/
   Delay_ms(2);
     
   /*總線拉高 主機延時30us*/
   AM2302_DATA_OUT(HIGH); 
     
   Delay_us(3);   //延時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->humi_int= Read_Byte();
                                     
         AM2302_Data->humi_deci= Read_Byte();
                     
         AM2302_Data->temp_int= Read_Byte();
     
         AM2302_Data->temp_deci= Read_Byte();
                             
         AM2302_Data->check_sum= Read_Byte();
                                               
     
         /*讀取結束,引腳改為輸出模式*/
    AM2302_Mode_Out_PP();
        /*主機拉高*/
        AM2302_DATA_OUT(HIGH);
     
        /*檢查讀取的數據是否正確*/
        if(AM2302_Data->check_sum == AM2302_Data->humi_int + AM2302_Data->humi_deci + AM2302_Data->temp_int+ AM2302_Data->temp_deci)
          return SUCCESS;
        else
          return ERROR;
   }
   else
   {        
            return ERROR;
     }
        
}
     
/*************************************END OF FILE******************************/

好了,到此AM2302驅動算完全結束了。
驅動AM2302的過程磕磕絆絆的,分享出來希望和我一樣走在STM32路上的人能少走些彎路。
給一個新鮮器件時,一定要先仔細研究它的手冊,深刻的探究器件的要求,這樣才能在實現器件功能上少遭受一些挫折,也算這次驅動AM2302溫濕度傳感器的一些心得吧。



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com