概述
DHT11數字溫濕度傳感器是一款含有已校准數字信號輸出的溫濕度復合傳感器。它應用專用的數字模塊采集技術和溫濕度傳感技術,確保產品具有極高的可靠性與長期的穩定性。傳感器包括一個電阻式感濕元件和一個NTC測溫元件,並與一個8位單片機相連接。因此該產品具有抗干擾能力強、性價比高等優點。
硬件連接
DHT11使用1-wire總線與MCU進行半雙工通信,當連接線長度短於20米時可用5K的上拉電阻,大於20米時需要根據實際情況選擇合適的上拉電阻。
通信過程
DATA引腳用於MCU與DHT11之間的通訊和同步,采用單總線數據格式,一次通訊時間4ms左右,數據分小數部分和整數部分,一次完整的數據傳輸為40bit,高位先出(MSB)。數據格式:8bit濕度整數數據+8bit濕度小數數據+8bit溫度整數數據+8bit溫度小數數據+8bit校驗和。數據傳送正確時校驗和數據等於“8bit濕度整數數據+8bit濕度小數數據+8bit溫度整數數據+8bit溫度小數數據”所得結果的末8位。
通信的開始
上圖為MCU與DH11通信的開始,MCU拉低總線20ms后拉高,請求DH11響應,DH11收到信號后將總線拉低以此來響應主機,響應后拉高總線開始傳輸數據,本圖來源為DH11的數據手冊。需要注意MCUI/O引腳輸入輸出模式的切換,本人使用的是GPIOG的號引腳與DHT11進行通信。
數據的判斷
上圖中可以看出論時數據0還是數據1,數據的開始總線都是被拉低50us,只是在總線被拉高時的時長不一樣,於是程序便可以在40us的時候判斷引腳的電平,以此來指定當前傳輸的數據是0是1。
溫濕度傳感器程序
以下為溫濕度傳感器初始化函數和獲得溫濕度數據的程序,初始化相關引腳后調用read_ht_data(&data),便可以獲得所需數據,注意該函數1s鍾只能調用一次,不然獲取不到數據。還需要保證延遲函數是准確的,參考我之前的系統定時器的相關隨筆。
void ht_sensor_init()
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;
GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOG,&GPIO_InitStruct);
}
int read_ht_data(uint8_t *p)
{
uint32_t t=0;//用於計時
int32_t i=0,j=0;
uint8_t d=0;
uint8_t check_sum=0;
GPIO_InitTypeDef GPIO_InitStruct;
//保證PG9為輸出模式,必須要
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;
GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOG,&GPIO_InitStruct);
//PG9輸出低電平
PGout(9)=0;
//延時至少18ms
delay_ms(18);
//PG9輸出高電平
PGout(9)=1;
//延時30us
delay_us(30);
//保證PG9為輸入模式
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOG,&GPIO_InitStruct);
//等待低電平出現,添加超時處理
t=0;//
while(PGin(9))
{
t++;
delay_us(1);
if(t>=4000)
{
printf("Obtion data error1, please try again\n");
delay_ms(1000);
return -1;
}
}
//通過超時檢測低電平的合法性,注意總線電平每跳變一次就需要將t清0
t=0;/
while(PGin(9)==0)
{
t++;
delay_us(1);
if(t>=100)
{
printf("Obtion data error2, please try again\n");
delay_ms(300);
return -2;
}
}
//通過超時檢測高電平的合法性
t=0;
while(PGin(9))
{
t++;
delay_us(1);
if(t>=100)
{
printf("Obtion data error3, please try again\n");
delay_ms(300);
return -3;
}
}
for(j=0; j<5; j++)
{
//接收一個字節,高位優先接收數據,bit7 bit6 ...... bit0
d=0;
for(i=7; i>=0; i--)
{
//通過超時檢測低電平的合法性
t=0;
while(PGin(9)==0)
{
t++;
delay_us(1);
if(t>=100)
{
printf("Obtion data error4, please try again\n");
delay_ms(300);
return -4;
}
}
//延時40us~60us左右
delay_us(40);
//判斷引腳的電平
if(PGin(9))
{
d|=1<<i;
//等待剩下的高電平持續完畢
t=0;
while(PGin(9))
{
t++;
delay_us(1);
if(t>=100)
{
printf("Obtion data error5, please try again\n");
delay_ms(300);
return -5;
}
}
}
}
p[j]=d;
}
//校驗數據
check_sum = (p[0]+p[1]+p[2]+p[3])&0xFF;
if(check_sum != p[4])
{
printf("Obtion data error6, please try again\n");
delay_ms(300);
return -6;
}
//printf("H:%d.%d\tT:%d.%d\n",p[0], p[1], p[2], p[3]);
return 0;
}
總結
1.獲得溫濕度數據不可太快;
2.除了獲取溫濕度數據出錯外,在通信過程中不可使用printf函數不然將超時,導致獲取失敗。
模塊資料
鏈接:https://pan.baidu.com/s/1RYk_LayvZ0__EaiTVYZxrA
提取碼:vs24
復制這段內容后打開百度網盤手機App,操作更方便哦