STM32F1驱动AM2302温湿度传感器

先来个AM2302的自我介绍:
         AM2302数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电容式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个AM2302传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式储存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。单线制串行接口,使系统集成变得简易快捷。超小的体积、极低的功耗,信号传输距离可达20米以上,使其成为各类应用甚至最为苛刻的应用场合的最佳选则。产品为 4 针单排引脚封装。连接方便,特殊封装形式可根据用户需求而提供。

重要的来了啊:AM2302时序图

STM32F1驱动AM2302温湿度传感器_第1张图片

单总线通信特殊说明: 
1.典型应用电路中建议连接线长度短于30米时用5.1K上拉电阻,大于30米时根据实际情况降低上拉电阻的阻值。 
2.使用3.3V电压供电时连接线长度不得大于30cm。否则线路压降会导致传感器供电不足,造成测量偏差。 
3.读取传感器最小间隔时间为2S;读取间隔时间小于2S,可能导致温湿度不准或通信不成功等情况。 
4.每次读出的温湿度数值是上一次测量的结果,欲获取实时数据,需连续读取两次, 建议连续多次读取传感器,且每次读取传感器间隔大于2秒即可获得准确的数据。
看到这里相信对AM2302有了一定了解了。下面开始贴出程序,共同驱动AM2302吧。
先来主函数把

/***********************************************************************************
 * 文件名  :main.c
 * 描述    :         
 * 实验平台:神舟III号
 * 库版本  :ST3.5
 * 作者    :xiayufeng  [email protected] 
 * 博客    :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温湿度传感器的一些心得吧。


你可能感兴趣的:(ARM)