重要的来了啊:AM2302时序图
单总线通信特殊说明:
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******************************/