我的自己做的硬體時直接用STM32f103的最小闆外界AM2302實作的溫濕度采集,證明不用上拉電阻也可以實作溫濕度采集功能。
但不知道為什麼效驗位≠濕度高8位+濕度低8位+溫度高8位+溫度低8位。
是以我的程式上并沒有加效驗位判斷。
AM2302引腳圖
單總線通信時序
主機和傳感器之間的通信可通過下面四個步驟
一、 AM2302 上電後(AM2302 上電後要等待 2S 以越過不穩定狀态,在此期間讀取裝置不能發送任何指令),測試環境溫濕度資料,并記錄資料,此後傳感器自動轉入休眠狀态。AM2302 的 SDA 資料線由上拉電阻拉高一直保持高電平,此時 AM2302 的 SDA 引腳處于輸入狀态,時刻檢測外部信号。
二、微處理器的 I/O 設定為輸出,同時輸出低電平,且低電平保持時間不能小于 800us,典型值是拉低 1MS,然後微處理器的 I/O 設定為輸入狀态,釋放總線,由于上拉電阻,微處理器的 I/O 即 AM2302的 SDA 資料線也随之變高,等主機釋放總線後,AM2302 發送響應信号,即輸出 80 微秒的低電平作為應答信号,緊接着輸出 80 微秒的高電平通知外設準備接收資料。
三、AM2302 發送完響應後,随後由資料總線 SDA 連續串行輸出 40 位資料,微處理器根據 I/O 電平的變化接收 40 位資料。
位資料“0”的格式為: 50 微秒的低電平加 26-28 微秒的高電平;
位資料“1”的格式為: 50 微秒的低電平加 70 微秒的高電平;
連續讀取五個資料
AM2302.C
#include "AM2302.h"
uint8_t Hum_H,Hum_L,Temp_H,Temp_L,Check;
uint16_t Hum,Temp;
void AM2302_DATA_OUT(uint8_t a)//輸出模式下,輸出高低電平
{
if(a==)
{
GPIO_SetBits(GPIOA, GPIO_Pin_9);
}
else if(a==)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_9);
}
}
uint8_t AM2302_DATA_IN(void)//輸入模式下,讀取引腳是高電平還是低電平
{
uint8_t a;
a=GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_9);
return a;
}
void AM2302_OUT(void)//設定為推挽輸出模式
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void AM2302_IN(void)//設定為上拉輸入模式
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
uint8_t Read_Byte(void)
{
uint8_t i,temp=;
for(i=;i<;i++)
{
while(AM2302_DATA_IN()==);
Delay_us();//50us
if(AM2302_DATA_IN()==)
{
while(AM2302_DATA_IN()==);//直到高電平結束跳出
temp|=(uint8_t)(<<(-i)); //把7-i位置1
}
else
{
temp&=(uint8_t)~(<<(-i)); //把7-i位置0
}
}
return temp;
}
void AM2302_RESET(void)//2s的啟動延時
{
uint16_t i;
AM2302_OUT();
AM2302_DATA_OUT();
for(i=;i<;i++)
{
Delay_us();
}
}
void Read_AM2302(void)
{
AM2302_OUT();
AM2302_DATA_OUT();
Delay_us();//1ms-2ms之間都可以,設定為1.8ms
AM2302_DATA_OUT();
Delay_us(); //30us
AM2302_IN();
if(AM2302_DATA_IN()==)//判斷AM2302是否傳回響應
{
while(AM2302_DATA_IN()==);//響應80ms低電平
while(AM2302_DATA_IN()==);//響應80ms高電平
Hum_H=Read_Byte(); //讀取濕度高8位
Hum_L=Read_Byte(); //讀取濕度低8位
Temp_H=Read_Byte(); //讀取溫度高8位
Temp_L=Read_Byte();//讀取溫度低8位
Check=Read_Byte();//讀取效驗位
AM2302_OUT();
AM2302_DATA_OUT();
Delay_us(); //50us
}
}
void AM2302(void)
{
Hum=(Hum_H*+Hum_L);//此處的濕度為實際濕度的10倍
Temp=Temp_H*+Temp_L;//此處的濕度為實際溫度的10倍
}
主函數
#include "stm32f10x.h"
#include "Systick.h"
#include "AM2302.h"
int main(void)
{
SysTick_Init();
AM2302_RESET();
while()
{
Read_AM2302();
AM2302();//濕度、溫度均為實際的10倍
}
}
AM2302.h
#ifndef __AM2302_H
#define __AM2302_H
#include "stm32f10x.h"
#include "SysTick.h"
void AM2302_DATA_OUT(uint8_t a);
uint8_t AM2302_DATA_IN(void);
void AM2302_IN(void);
void AM2302_OUT(void);
uint8_t Read_Byte(void);
void Read_AM2302(void);
void AM2302(void);
void AM2302_RESET(void);
#endif /* __AM2302_H */
滴答時鐘函數,用來做延時(SysTick.c)
#include "SysTick.h"
#include "bsp_key.h"
static uint64_t TimingDelay;
void SysTick_Init(void)
{
if (SysTick_Config(SystemCoreClock / ))
{
while ();
}
SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;
}
void Delay_us(__IO u32 nTime)//10us為一個機關,例如Delay—us(1)=10us
{
TimingDelay = nTime;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
while(TimingDelay != );
}
void TimingDelay_Decrement(void)
{
if (TimingDelay != )
{
TimingDelay--;
}
}
SysTick.h
#ifndef __SYSTICK_H
#define __SYSTICK_H
#include "stm32f10x.h"
void SysTick_Init(void);
void Delay_us(__IO u32 nTime);
#define Delay_ms(x) Delay_us(100*x)
寫到這,AM2302驅動程式就寫完了。
單總線器件隻要認真看時序圖照着一步一步寫就行了。