STM32F103讀取DHT22溫濕度傳感器引數
1、首先通過DHT22的說明書獲取操作流程 (覺得文字太多可直接向下翻,有完整.c和.h )
通信啟動規則:
它有一條通信總線,空閑時總線為高電平,發送一次開始信號后,DHT22從低功耗模式轉換到高速模式,通訊開始時主機(MCU)拉低總線500us后釋放總線,延時20-40us后主機開始檢測從機(DHT22)的回應信號, 從機的回應信號是一個80us左右的低電平,隨后從機在拉高總線80us左右代表即將進入資料傳送,
資料傳送規則:
首先傳送50us左右的低電平時隙,它代表資料位的起始,其后的高電平的長度決定資料位所代表的數值,70us的高電平代表1,26-28us的高電平代表0, 共40bit資料,當最后一Bit資料傳送完畢后,從機將再次拉低總線50us左右,
下面進行分析:
(1)只有一條資料總線,所以埠既做輸入也做輸出,功能有拉高、拉低和讀取
//其中CRH用來設定高8-15引腳,CRL用來設定0-7引腳,這里是PA0,選擇CRL暫存器
#define DHT22_IO_IN() {DHT22_PORT->CRL&=0XFFFFFFF0;DHT22_PORT->CRL|=8<<0;}//設為輸入
#define DHT22_IO_OUT() {DHT22_PORT->CRL&=0XFFFFFFF0;DHT22_PORT->CRL|=3<<0;}//設為輸出
#define DHT22_IO_HIGH() GPIO_SetBits(DHT22_PORT,DHT22_PIN); //輸出1,拉高
#define DHT22_IO_LOW() GPIO_ResetBits(DHT22_PORT,DHT22_PIN); //輸出0,拉低
#define DHT22_IO_READ (GPIO_ReadInputDataBit(DHT22_PORT,DHT22_PIN)) //讀埠值
(2)空閑為高,初始化埠時讓埠輸出高電平,
void DHT22_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(DHT22_PORT_CLK, ENABLE); //使能PORTA口時鐘
GPIO_InitStructure.GPIO_Pin = DHT22_PIN; //PORTA0 推挽輸出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT22_PORT, &GPIO_InitStructure);
DHT22_IO_HIGH(); //輸出1
}
(3)開始信號,拉低500us,再拉高等待20到40us,等待傳感器回應,
static void DHT22_Awake(void)//喚醒
{
DHT22_IO_OUT();//設為輸出
DHT22_IO_LOW();//拉低500us,激活傳感器
delay_us(500);
DHT22_IO_HIGH();//拉高,釋放總線
delay_us(30);
DHT22_IO_IN();//等待20到40us設為輸入,等待回應
}
(4)傳感器回應,先拉低80us,再拉高80us
while(DHT22_IO_READ);//檢測回應信號,傳感器拉低80us
while((!DHT22_IO_READ));//傳感器將總線拉高80us,標志馬上進入資料傳輸
(5)傳感器發送40bit的資料,根據規則進行讀取
for(i = 0;i < 40;i ++)//獲取40bit資料
{
while(DHT22_IO_READ);//等待50us低電平間隙到來
while(!DHT22_IO_READ);//間隙結束,等待資料高電平到來
//高電平保持26~28us表示低電平,保持70us表示高電平,
delay_us(30);//這里等待30us,越過28us(但不能大于28+50),直接判斷是不是1
if(DHT22_IO_READ)//讀取當前總線的狀態,是不是為1
{
//為真則:
data <<= 1;//右移1位空出末位
data |= 1;//把1添入末位
}
else
//為假則:
data <<= 1;右移1位空出末位,末位就是0
}
(6)最后依舊釋放總線,以便下次資料獲取
DHT22_IO_OUT();//設為輸出
DHT22_IO_HIGH();//拉高,釋放總線
2、完整.c和.h
dht22.h
#ifndef __DHT22_H
#include "common.h"
#define DHT22_PORT GPIOA
#define DHT22_PIN GPIO_Pin_0
#define DHT22_PORT_CLK RCC_APB2Periph_GPIOA
//其中CRH用來設定高8-15引腳,CRL用來設定0-7引腳,這里是PA0,選擇CRL暫存器
#define DHT22_IO_IN() {DHT22_PORT->CRL&=0XFFFFFFF0;DHT22_PORT->CRL|=8<<0;}//設為輸入
#define DHT22_IO_OUT() {DHT22_PORT->CRL&=0XFFFFFFF0;DHT22_PORT->CRL|=3<<0;}//設為輸出
#define DHT22_IO_HIGH() GPIO_SetBits(DHT22_PORT,DHT22_PIN); //輸出1
#define DHT22_IO_LOW() GPIO_ResetBits(DHT22_PORT,DHT22_PIN); //輸出0
#define DHT22_IO_READ (GPIO_ReadInputDataBit(DHT22_PORT,DHT22_PIN)) //讀埠值
void DHT22_Init(void);
u8 DHT22_GetValue(int* temp,u16* humi);
#endif
dht22.c
#include "dht22.h"
/*************************
*作 用:初始化傳感器引腳
*參 數:無
*回傳值:無
**************************/
void DHT22_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(DHT22_PORT_CLK, ENABLE); //使能PORTA口時鐘
GPIO_InitStructure.GPIO_Pin = DHT22_PIN; //PORTA0 推挽輸出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DHT22_PORT, &GPIO_InitStructure);
DHT22_IO_HIGH(); //輸出1
}
/**************************
*作 用:喚醒傳感器
*參 數:無
*回傳值:無
***************************/
static void DHT22_Awake(void)
{
DHT22_IO_OUT();//設為輸出
DHT22_IO_LOW();//拉低500us,激活傳感器
delay_us(500);
DHT22_IO_HIGH();//拉高,釋放總線
delay_us(30);
DHT22_IO_IN();//等待20到40us設為輸入,等待回應
}
/************************************************
*作 用:與DHT傳感器通信,獲取資料
*參 數:無
*回傳值:回傳獲取的40位資料,小于0xff表示失敗
*************************************************/
static uint64_t DHT22_ReadData(void)
{
u8 waitTime = 0;//回應等待時間
u16 i = 0;//回圈變數
uint64_t data = 0;//資料存盤變數
DHT22_Awake();//傳感器喚醒
waitTime = 100;//回應超時時間設定
while(DHT22_IO_READ)//檢測回應信號,傳感器拉低80us
{
if((waitTime--) > 0)
delay_us(1);
else
return 1;
}
waitTime = 100;//回應超時時間設定
while((!DHT22_IO_READ))//傳感器將總線拉高80us,標志馬上進入資料傳輸
{
if((waitTime--) > 0)
delay_us(1);
else
return 2;
}
for(i = 0;i < 40;i ++)//獲取40bit資料
{
waitTime = 100;//回應超時時間設定
while(DHT22_IO_READ)//等待50us低電平間隙到來
{
if((waitTime--) > 0)
delay_us(1);
else
return 3;
}
waitTime = 50;//回應超時時間設定
while(!DHT22_IO_READ)//間隙結束,等待資料高電平到來
{
if((waitTime--) > 0)
delay_us(1);
else
return 3;
}
//高電平保持26~28us表示低電平,保持70us表示高電平,
delay_us(30);//這里等待30us,越過28us(但不能大于28+50),直接判斷是不是1
if(DHT22_IO_READ)//讀取當前總線的狀態
{
data <<= 1;//右移1位空出末位
data |= 1;//把1添入末位
}
else
data <<= 1;右移1位空出末位,末位就是0
}
DHT22_IO_OUT();//設為輸出
DHT22_IO_HIGH();//拉高,釋放總線
return data;
}
/*****************************************
*作 用:獲取溫濕度傳感器的檢測值
*參 數:temp:用于獲取溫度值的變數地址
humi:用于獲取濕度值得變數地址
*回傳值:回傳0成功,非0獲取失敗
******************************************/
u8 DHT22_GetValue(int* temp,u16* humi)
{
uint64_t data1 = 0;
data1 = DHT22_ReadData();
if(data1 < 0xff)//判斷資料接收是否成功,大于0xff代表成功
{
return (u8)data1;//
}
//去掉后24位資料保留16位濕度資料
*humi = (u16)(data1 >> 24) & 0x00ffff;
//去掉前16位濕度資料和后8位校驗資料,保留16位溫度資料
*temp = (u16)(data1 >> 8) & 0x00ffff;
return 0;
}
回應超時的設定是為了便于除錯,若各位不需要可直接洗掉,
(有不足之處,還請各位老兄不吝賜教)
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/189389.html
標籤:其他
