DHT11及DHT21溫濕度傳感器時序圖解析(STM32)
掃描二維碼
隨時隨地手機看文章
下面對DHT11和DHT21進行簡單的對比:
DHT11:
測量范圍:20-90% RH 0-50℃
測濕精度:±5% RH
測溫精度:±2℃
分辨力:1
DHT11引腳說明(正面觀看,左邊的為1腳):
DHT21(AM2301):
測量范圍:0-99.9% RH -40~+80℃
測濕精度:±3% RH
測溫精度:±0.5℃
分辨力:0.1%RH/0.1℃
典型應用電路:
說明:
(1)、DHT11和DHT21供電范圍都是3V~5.5V,對于STM32單片機,我們VDD引腳接3.3V即可;(2)、DHT11的手冊中說,SDA數(shù)據(jù)引腳接線長度短于20米時,用5K上拉電阻。大于20米時根據(jù)實際情況使用合適的上拉電阻;(3)、DHT11上電后,需要等待1s以越過不穩(wěn)定狀態(tài),在此期間無需發(fā)現(xiàn)任何指令;本人嘗試上電即讀取,返回溫濕度值都為0,1S以后溫濕度值即可恢復正常;(4)、電源引腳(VDD,GND)之間可增加一個100nF的電容,用以去耦濾波。DHT11和DHT21的時序基本相同,下面以DHT11的時序圖為例進行分析:
注意:
DHT11和DHT21的主線拉低的時間不同,DHT11主機(MCU)至少拉低18ms,DHT21主機(MCU)至少拉低500us,為了程序上兼容,我們一般將總線拉低25ms,這樣DHT11和DHT21的驅(qū)動程序就可以兼容了。
DHT11總線驅(qū)動過程:
1、MCU發(fā)送開始起始信號總線空閑狀態(tài)為高電平,主機把總線拉低等待DHT11響應;與MCU相連的SDA數(shù)據(jù)引腳置為輸出模式;主機把總線拉低至少18毫秒,然后拉高20-40us等待DHT返回響應信號;2、讀取DHT11響應SDA數(shù)據(jù)引腳設(shè)為輸入模式;DHT11檢測到起始信號后,會將總線拉低80us,然后拉高80us作為響應;3、DHT11送出40bit數(shù)據(jù)注意:
送出的數(shù)據(jù)高位在前。40bit數(shù)據(jù)(5字節(jié)數(shù)據(jù))數(shù)據(jù)包:
DHT11
數(shù)據(jù)格式: 40bit數(shù)據(jù)=8位濕度整數(shù)+8位濕度小數(shù)+8位溫度整數(shù)+8位溫度小數(shù)+8位校驗
DHT21
數(shù)據(jù)格式: 40bit數(shù)據(jù)=16bit濕度數(shù)據(jù)+16bit溫度數(shù)據(jù)+8bit校驗和
例子: 接收40bit數(shù)據(jù)如下:
0000 0010 1000 1100 0000 0001 0101 1111 1110 1110
濕度數(shù)據(jù) 溫度數(shù)據(jù) 校驗和
濕度高8位+濕度低8位+溫度高8位+溫度低8位=和的低8位=校驗和
例如:0000 0010+1000 1100+0000 0001+0101 1111=1110 1110
二進制的濕度數(shù)據(jù) 0000 0010 1000 1100 ==>轉(zhuǎn)為十進制:652,除以10即為濕度值;濕度=65.2%RH
二進制的溫度數(shù)據(jù) 0000 0001 0101 1111 ==>轉(zhuǎn)為十進制:351,除以10即為溫度值;
溫度=35.1℃
當溫度低于0℃時溫度數(shù)據(jù)的最高位置1。
例如:-10.1℃表示為1000 0000 0110 0101
注意:DHT21溫濕度數(shù)據(jù)為16位,DHT11數(shù)據(jù)為8位,所以盡管兩者時序相同,卻不能用同樣的數(shù)據(jù)類型計算。
/** * @brief 讀取40bit數(shù)據(jù) * @param none. * @retval 1 讀取成功,0讀取失敗. */int DHT11_ReadData(void){ unsigned int cout = 1; unsigned int T_H, T_L, H_H, H_L, Check; //設(shè)置IO為輸出模式 DHT_Set_Output(); //1、MCU發(fā)送開始起始信號 DHT_ResetBit(); delay_ms(25); //拉低至少18ms DHT_SetBit(); delay_us(20); //拉高20~40us //設(shè)置IO口為輸入模式 DHT_Set_Input(); //2、讀取DHT11響應 if(DHT_ReadBit() == Bit_RESET) { //等待80us的低電平 cout = 1; while(!DHT_ReadBit() && cout++); //等待80us的高電平 cout = 1; while(DHT_ReadBit() && cout++); //3、DHT11送出40bit數(shù)據(jù) //讀取8bit的濕度整數(shù)數(shù)據(jù) H_H = DH21_ReadByte(); //讀取8bit的濕度小數(shù)數(shù)據(jù) H_L = DH21_ReadByte(); //讀取8bit的溫度整數(shù)數(shù)據(jù) T_H = DH21_ReadByte(); //讀取8bit的溫度小數(shù)數(shù)據(jù) T_L = DH21_ReadByte(); //讀取8位的校驗和 Check = DH21_ReadByte(); //校驗數(shù)據(jù)是否合法,合法的話將數(shù)據(jù)保存到全局結(jié)構(gòu)體變量中備用 if(Check == (H_H + H_L + T_H + T_L)) { DHT11.Hum_H = H_H; DHT11.Hum_L = H_L; DHT11.Tem_H = T_H; DHT11.Tem_L = T_L; return 1; } else { return 0; } } return 0;}上面讀取40bit數(shù)據(jù)的函數(shù)中有一個讀取單字節(jié)(8bit)數(shù)據(jù)的函數(shù)DH21_ReadByte();這里涉及到1bit數(shù)據(jù)到底是0還是1的判斷規(guī)則。
數(shù)據(jù)'0'還是'1'判定規(guī)則:
位數(shù)據(jù)“0”的格式為:50 微秒的低電平和 26-28 微秒的高電平,位數(shù)據(jù)“1”的格式為:50 微秒的低電平加 70微秒的高電平。時序過程:1、等待50us低電平結(jié)束因為接收數(shù)據(jù)時,低電平的時間都是50us,該位數(shù)據(jù)到底是0還是1,取決于低電平后面的高電平的時間多少;如果不考慮低電平的時間,我們可以簡化程序,可以先等待低電平過去;2、數(shù)據(jù)拉高后,判斷30us后數(shù)據(jù)總線電平的高低等待數(shù)據(jù)線拉高后,再延時30us,因為30us大于28us且小于70us,再檢測此時數(shù)據(jù)線是否為高,如果為高,則數(shù)據(jù)判定為1,否則為0。
位數(shù)據(jù)“0”判定圖
位數(shù)據(jù)“1”判定圖
該函數(shù)的具體實現(xiàn)如下:
/** * @brief 讀取8bit 數(shù)據(jù) * @param none. * @retval none. */int DH21_ReadByte(void){ int data=0; char i; char cout; for(i=0; i<8; i++) { //1、等待50us低電平結(jié)束 cout=1; while(!DHT_ReadBit() && cout++); //2、數(shù)據(jù)拉高后,判斷30us后數(shù)據(jù)總線電平的高低 //延時30us之后讀取IO口的狀態(tài) delay_us(30); //先把上次的數(shù)據(jù)移位,再保存本次的數(shù)據(jù)位。 data = data << 1; if(DHT_ReadBit() == Bit_SET) { data |= 1; } //等待輸入的是低電平(高電平結(jié)束),進入下一位數(shù)據(jù)接收 cout=1; while(DHT_ReadBit() && cout++); } return data;}
對40bit數(shù)據(jù)處理,得到溫濕度數(shù)據(jù):
/** * @brief 獲取溫度 * @param none. * @retval Temp, 溫度值 */int DHT11_GetTem(void){ //return (DHT11.Tem_H << 8 | DHT11.Tem_L); //DHT21 return (DHT11.Tem_H*10 + DHT11.Tem_L); //DHT11}/** * @brief 獲取濕度 * @param none. * @retval Hum,濕度值 */int DHT11_GetHum(void){ //return (DHT11.Hum_H << 8 | DHT11.Hum_L); //DHT21 return (DHT11.Hum_H*10 + DHT11.Hum_L); //DHT11}
注意:
上面函數(shù)得到的數(shù)據(jù)為真實溫濕度值的放大10倍之后的值,使用時,需將函數(shù)的返回值除以10才為真實值;?