【精品博文】stm32F4----DHT22(AM2302)数字温湿度传感器读取(六)
经过了自己用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 0typedef 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;
如果,采用博主的
结果如下: