stm32F4----DHT22(AM2302)数字温湿度传感器读取(六)
1赞
发表于 3/7/2017 10:57:53 PM
阅读(6826)
经过了自己用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
#endifam2302.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;
如果,采用博主的
结果如下:

