DHT11溫濕度傳感器
1 DHT11溫濕度傳感器:2 P8913常見接線圖單線雙線數(shù)據(jù)線DATA上拉后與微處理器的 I/O 端口相連。
1.典型應(yīng)用電路中建議連接線長(zhǎng)度短于 5m 時(shí)用 4.7K 上拉電阻,大于 5m 時(shí)根據(jù)實(shí)際情況降低上拉電阻的阻值。
2. 使用 3.3V 電壓供電時(shí)連接線盡量短,接線過長(zhǎng)會(huì)導(dǎo)致傳感器供電不足,造成測(cè)量偏差。
3. 每次讀出的溫濕度數(shù)值是上一次測(cè)量的結(jié)果,欲獲取實(shí)時(shí)數(shù)據(jù),需連續(xù)讀取 2 次,但不建議連續(xù)多次讀取傳感器,每次讀取傳感器間隔大于 2 秒即可獲得準(zhǔn)確的數(shù)據(jù)。
4. 電源部分如有波動(dòng),會(huì)影響到溫度。如使用開關(guān)電源紋波過大,溫度會(huì)出現(xiàn)跳動(dòng)。
3 驅(qū)動(dòng)時(shí)序圖及工作參數(shù)DHT11 器件采用簡(jiǎn)化的單總線通信。單總線即只有一根數(shù)據(jù)線,系統(tǒng)中的數(shù)據(jù)交換、控制均由單總線完成。設(shè)備(主機(jī)或從機(jī))通過一個(gè)漏枀開路或三態(tài)端口連至該數(shù)據(jù)線,以允許設(shè)備在不發(fā)送數(shù)據(jù)時(shí)能夠釋放總線,而讓其它設(shè)備使用總線;單總線通常要求外接一個(gè)約 4.7kΩ 的上拉電阻,這樣,當(dāng)總線閑置時(shí),其狀態(tài)為高電平。由于它們是主從結(jié)極,只有主機(jī)呼叫從機(jī)時(shí),從機(jī)才能應(yīng)答,因此主機(jī)訪問器件都必須嚴(yán)格遵循單總線序列,如果出現(xiàn)序列混亂,器件將不響應(yīng)主機(jī)。
◎單總線傳送數(shù)據(jù)位定義
DATA 用于微處理器與 DHT11 之間的通訊和同步,采用單總線數(shù)據(jù)格式,一次傳送 40 位數(shù)據(jù),高位先出。
數(shù)據(jù)格式:
8bit 濕度整數(shù)數(shù)據(jù) + 8bit 濕度小數(shù)數(shù)據(jù) + 8bit 溫度整數(shù)數(shù)據(jù) + 8bit 溫度小數(shù)數(shù)據(jù) + 8bit 校驗(yàn)位。
注:其中濕度小數(shù)部分為 0。
◎校驗(yàn)位數(shù)據(jù)定義
“8bit 濕度整數(shù)數(shù)據(jù) + 8bit 濕度小數(shù)數(shù)據(jù) + 8bit 溫度整數(shù)數(shù)據(jù) + 8bit 溫度小數(shù)數(shù)據(jù)” 8bit 校驗(yàn)位等于所得結(jié)果的末 8 位
示例一:接收到的 40 位數(shù)據(jù)為:
0011 0101 0000 0000 0001 1000 0000 0100 0101 0001
濕度高 8 位 濕度低 8 位 溫度高 8 位 溫度低 8 位 校驗(yàn)位
計(jì)算:
0011 0101+0000 0000+0001 1000+0000 0100= 0101 0001
接收數(shù)據(jù)正確:
濕度: 0011 0101(整數(shù))=35H=53%RH 0000 0000(小數(shù))=00H=0.0%RH =>53%RH + 0.0%RH =
53.0%RH
溫度: 0001 1000(整數(shù))=18H=24℃ 0000 0100(小數(shù))=04H=0.4℃ =>24℃ + 0.4℃ = 24.4℃
◎特殊說明:
當(dāng)溫度低于 0 ℃ 時(shí)溫度數(shù)據(jù)的低 8 位的最高位置為 1。
示例: -10.1 ℃ 表示為 0000 1010 1000 0001
溫度: 0000 1010(整數(shù))=0AH=10℃, 0000 0001(小數(shù))=01H=0.1℃ =>-(10℃+0.1℃)= -10.1℃
示例二:接收到的 40 位數(shù)據(jù)為:
0011 0101 0000 0000 0001 1000 0000 0100 0100 1001
濕度高 8 位 濕度低 8 位 溫度高 8 位 溫度低 8 位 校驗(yàn)位
計(jì)算:
0011 0101+0000 0000+0001 1000+0000 0100= 0101 0001
0101 0001 不等于 0100 1001
本次接收的數(shù)據(jù)不正確,放棄,重新接收數(shù)據(jù)。
4 驅(qū)動(dòng)思路
4.1 時(shí)序圖分析總線空閑狀態(tài)為高電平,主機(jī)把總線拉低等待DHT11響應(yīng),主機(jī)把總線拉低必須大于18毫秒,保證DHT11能檢測(cè)到起始信號(hào)。DHT11接收到主機(jī)的開始信號(hào)后,等待主機(jī)開始信號(hào)結(jié)束,然后發(fā)送80us低電平響應(yīng)信號(hào)。主機(jī)發(fā)送開始信號(hào)結(jié)束后,延時(shí)等待20-40us后, 讀取DHT11的響應(yīng)信號(hào)。主機(jī)發(fā)送開始信號(hào)后,可以切換到輸入模式,或者輸出高電平均可, 總線由上拉電阻拉高。檢測(cè)到總線為低電平,說明DHT11發(fā)送響應(yīng)信號(hào),DHT11發(fā)送響應(yīng)信號(hào)后,再把總線拉高80us,準(zhǔn)備發(fā)送數(shù)據(jù),每一bit數(shù)據(jù)都以50us低電平時(shí)隙開始,高電平的長(zhǎng)短定了數(shù)據(jù)位是0還是1.格式見下面圖示,如果讀取響應(yīng)信號(hào)為高電平,則DHT11沒有響應(yīng),請(qǐng)檢查線路是否連接正常。當(dāng)最后一bit數(shù)據(jù)傳送完畢后,DHT11拉低總線50us,隨后總線由上拉電阻拉高進(jìn)入空閑狀態(tài)。4.2 發(fā)送一位數(shù)據(jù):MCU:
//總線空閑狀態(tài)為高電平,主機(jī)把總線拉低等待DHT11響應(yīng),主機(jī)把總線拉低必須大于18毫秒,保證DHT11能檢測(cè)到起始信號(hào)。
推挽輸出模式:
//發(fā)送起始信號(hào),先拉低電平,延時(shí)至少18ms再拉高
DHT11_SEND_DATA=0;
Delay_ms(18);
DHT11_SEND_DATA=1;
//DHT11接收到主機(jī)的開始信號(hào)后,等待主機(jī)開始信號(hào)結(jié)束,然后發(fā)送80us低電平響應(yīng)信號(hào)。主機(jī)發(fā)送開始信號(hào)結(jié)束后,延時(shí)等待20-40us后, 讀取DHT11的響應(yīng)信號(hào)。
Delay_us(20); //延時(shí)20us
DHT11_Input( ); //切換IO口為輸入模式
u8 DHT11_Ack(void)
{
if(DHT11_REV_DATA!=0) //如果沒有檢測(cè)到低電平的應(yīng)答信號(hào)就返回0
{
return 0;
}
while(DHT11_REV_DATA==0);//等待80us低電平應(yīng)答結(jié)束
while(DHT11_REV_DATA==1);//等待80us高電平應(yīng)答結(jié)束
//很有必要檢測(cè)高低電平,防止時(shí)序出錯(cuò)
return 1; 檢測(cè)到高電平,說明信號(hào)不是應(yīng)答信號(hào),返回1
}
讀取從機(jī)發(fā)送過來(lái)的數(shù)據(jù),以8位為單位接收
u8 DHT11_Read_Byte(void)
{
u8 data=0;
u8 i;
//接受數(shù)據(jù),每個(gè)數(shù)據(jù)以50us低電平開始
for(i=0;i<8;i++)
{
data <<= 1; //左移一位,空位補(bǔ)0.
while(!DHT11_REV_DATA); //當(dāng)?shù)碗娖浇Y(jié)束,等待準(zhǔn)備數(shù)據(jù)的時(shí)間過去,消除影響
Delay_us(40); //延時(shí)40us,卡時(shí)序,卡在低電平已經(jīng)過,高電平還沒結(jié)束
if(DHT11_REV_DATA==1)//如果還是高電平說明從機(jī)確實(shí)發(fā)送了高電平
//就算是低電平了也不會(huì)影響時(shí)序。
{
data |=1; //‘1’如果是高電平就將左移的一個(gè)空位
while(DHT11_REV_DATA);//等待高電平應(yīng)答結(jié)束
}
}
return data;
}
5 實(shí)戰(zhàn)代碼5.1 引腳初始化。void DHT11_Init(void)
{
RCC->APB2ENR |=0x01<<3;
DHT11_Input( );// DHT11 的DATA 引腳處于輸入狀態(tài),時(shí)刻檢測(cè)外部信號(hào)
Delay_ms(500);//DHT11 上電后要等待 1S 以越過不穩(wěn)定狀態(tài)在此期間不能發(fā)送任何指令
Delay_ms(500);
}
將輸出輸入模式另外整合成函數(shù),方便調(diào)用
void DHT11_Output(void)
{
GPIOB->CRL &=~(0x0f<<12);
GPIOB->CRL |=(0x03<<12);
}
void DHT11_Input(void)
{
GPIOB->CRL &=~(0x0f<<12);
GPIOB->CRL |=(0x04<<12);
}
5.2 發(fā)送起始信號(hào)void DHT11_Start(void)
{
DHT11_SEND_DATA=0;
Delay_ms(18);
DHT11_SEND_DATA=1;
}
5.3 檢測(cè)應(yīng)答信號(hào)//返回值 0--無(wú)應(yīng)答 1--有應(yīng)答
u8 DHT11_Ack(void)
{
if(DHT11_REV_DATA!=0)
{
return 0;
}
while(DHT11_REV_DATA==0);//等待80us低電平應(yīng)答結(jié)束
while(DHT11_REV_DATA==1);//等待80us高電平應(yīng)答結(jié)束
return 1;
}
5.4 讀取一個(gè)字節(jié)數(shù)據(jù)u8 DHT11_Read_Byte(void)
{
u8 data=0;
u8 i;
//接受數(shù)據(jù),每個(gè)數(shù)據(jù)以50us低電平開始
for(i=0;i<8;i++)
{
data <<= 1;
while(!DHT11_REV_DATA);//等待
Delay_us(40);
if(DHT11_REV_DATA==1)
{
data |=1;//‘1’
while(DHT11_REV_DATA);//等待高電平應(yīng)答結(jié)束
}
}
return data;
}
5.5 最終函數(shù)//讀取溫濕度
u8 DHT11_Read_Data(u8 *Temp_H,u8* Temp_L,u8* RH_H,u8* RH_L)
//注意這里是址傳遞
{
u8 i;
u8 check;
DHT11_Output( );
DHT11_Start( );
Delay_us(20);
DHT11_Input( );//切換為輸入
if( DHT11_Ack( )==0 )
{
return -1;
}
//讀取數(shù)據(jù),分開讀40個(gè)字節(jié),調(diào)用5次讀取函數(shù)
*RH_H=DHT11_Read_Byte( );
*RH_L=DHT11_Read_Byte( );
*Temp_H=DHT11_Read_Byte( );
*Temp_L=DHT11_Read_Byte( );
check=DHT11_Read_Byte( );
//結(jié)束讀取
Delay_ms(50);
DHT11_Output( );//切換為輸出
DHT11_SEND_DATA=1;//釋放總線
//校驗(yàn)數(shù)據(jù)
if(check !=(*Temp_H+*Temp_L+*RH_H+*RH_L) )
{
return -2;
}
return 0;
}