目錄
前言
1. DHT11簡(jiǎn)介
2. DHT11數(shù)據(jù)結(jié)構(gòu)
3. DHT11的傳輸時(shí)序
3.1 DHT11開始發(fā)送數(shù)據(jù)流程
3.2 主機(jī)復(fù)位信號(hào)和DHT11響應(yīng)信號(hào)
3.3 數(shù)字 “0” 信號(hào)表示方法
3.4 數(shù)字 “1” 信號(hào)表示方法
4. 硬件分析
5. 實(shí)驗(yàn)程序詳解
5.1 main.c
5.2 DHT11.c
5.3 DHT11.h
前言
????????DHT11數(shù)字溫濕度傳感器不但能測(cè)溫度,還能測(cè)濕度。本節(jié)我們將利用STM32F4來(lái)讀取DHT11的溫濕度傳感器,獲取環(huán)境的溫度和濕度值。
1. DHT11簡(jiǎn)介
????????DHT11是廣州奧松有限公司生產(chǎn)的一款溫濕度一體化的數(shù)字傳感器。該傳感器包括一個(gè)電阻式測(cè)濕元件和一個(gè)NTC測(cè)溫元件,并與一個(gè)高性能8位單片機(jī)相連。通過(guò)單片機(jī)等微處理器簡(jiǎn)單的電路連接就能實(shí)時(shí)的采集本地的溫度和濕度。DHT11 與單片機(jī)之間能采用簡(jiǎn)單的單總線進(jìn)行通信,僅僅需要一個(gè)I/O 口。
性能指標(biāo)和特性:
- ? ? ? ? 工作電壓范圍:3.5V~5.5V
- ? ? ? ? 工作電流:0.5mA
- ? ? ? ? 濕度測(cè)量范圍:20-90%RH
- ? ? ? ? 溫度測(cè)量范圍:0-50℃
- ? ? ? ? 濕度分辨率:1%RH? 8位
- ? ? ? ? 溫度分辨率:1℃? 8位
- ? ? ? ? 采樣周期:1S
- ? ? ? ? 單總線結(jié)構(gòu)
- ? ? ? ? 與TTL兼容(5V)
2. DHT11數(shù)據(jù)結(jié)構(gòu)
DHT11數(shù)字溫濕度傳感器采用單總線數(shù)據(jù)格式。通過(guò)單個(gè)數(shù)據(jù)的引腳端口就可以完成輸入輸出雙向傳輸。其數(shù)據(jù)包由5Byte(5*8=40Bit)組成。數(shù)據(jù)分小數(shù)部分和整數(shù)部分。
一次完整的數(shù)據(jù)傳輸為40bit,高位先行。
數(shù)據(jù)格式:8bit濕度整數(shù)數(shù)據(jù)+8bit濕度小數(shù)數(shù)據(jù)+8bit溫度整數(shù)數(shù)據(jù)+8bit溫度小數(shù)數(shù)據(jù)+8bit校驗(yàn)和
? ? ? ? ? ? ? ? 其中校驗(yàn)和數(shù)據(jù)為前四個(gè)字節(jié)相加。
DHT11和DS18B20相同,傳感器輸出的都是未編碼的二進(jìn)制數(shù)字。數(shù)據(jù)(濕度、溫度、整數(shù)、小數(shù))之間應(yīng)該分開進(jìn)行處理。
比方說(shuō):
????????
DHT11溫濕度傳感器一次完整的數(shù)據(jù)傳輸位如上圖所示
那么:humidity(濕度)=byte4 . byte3=45.0(%RH)
? ? ? ? ? ?temperature(溫度)=byte2 . byte1=28.0(℃)
? ? ? ? ? ?校驗(yàn)位byte0:byte4+byte3+byte2+byte1=73(humidity+temperature)
因此:溫濕度的讀取方式就是整數(shù)部分的二進(jìn)制轉(zhuǎn)換成十進(jìn)制放在整數(shù)部分;小數(shù)部分的二進(jìn)制轉(zhuǎn)換成十進(jìn)制放在小數(shù)部分。
注意:DHT11和MCU的一次通訊時(shí)間最大3ms,主機(jī)連續(xù)向DHT11采樣的間隔建議不小于100ms。
3. DHT11的傳輸時(shí)序
3.1 DHT11開始發(fā)送數(shù)據(jù)流程
主機(jī)發(fā)送開始信號(hào)后,延時(shí)等待20us~40us后讀取DHT11的應(yīng)答信號(hào),正常的話,DHT11 會(huì)拉低數(shù)據(jù)線,保持40~50us時(shí)間,讀取總線為低電平,說(shuō)明DHT11發(fā)送響應(yīng)信號(hào),DHT11發(fā)送響應(yīng)信號(hào)后,再把總線拉高,保持40-50us,準(zhǔn)備發(fā)送數(shù)據(jù),每一位 bit 數(shù)據(jù)都以低電平開始。
如果讀取響應(yīng)為高電平,則DHT11沒(méi)有響應(yīng),檢查線路是否連接正常。
3.2 主機(jī)復(fù)位信號(hào)和DHT11響應(yīng)信號(hào)
主機(jī)發(fā)送復(fù)位信號(hào)后,主機(jī)拉低總線,延時(shí)至少18ms,然后將主機(jī)拉高,延遲20-40us等待DHT11的應(yīng)答信號(hào)。讀取總線電平,如果為低電平,則表示從機(jī)DHT11發(fā)送應(yīng)答信號(hào)成功。然后從機(jī)把總線拉高,準(zhǔn)備發(fā)送數(shù)據(jù)。之所以拉高,是因?yàn)槊堪l(fā)送一位數(shù)據(jù)都是以低電平開始的,為發(fā)送數(shù)據(jù)做準(zhǔn)備。
3.3 數(shù)字 “0” 信號(hào)表示方法
因?yàn)镈HT11也是遵循單總線協(xié)議的。所以也是通過(guò)高低電平延時(shí)不同時(shí)間進(jìn)行組合來(lái)發(fā)送邏輯1或者邏輯0.
從機(jī)DHT11拉低總線,延時(shí)12-14us,然后從機(jī)釋放總線,延時(shí)26-28us。表示發(fā)送數(shù)字 “0”?
3.4 數(shù)字 “1” 信號(hào)表示方法
從機(jī)DHT11拉低總線,延時(shí)12-14us,然后從機(jī)釋放總線,延時(shí)116-118us。表示發(fā)送數(shù)字 “1”?
4. 硬件分析
- VCC:正電源,支持3.5V~5.5V
- Dout:輸出引腳
- NC:空腳
- GND:地
DHT11數(shù)字溫濕度傳感器的第一腳接電源正極,第四腳接電源地端。數(shù)據(jù)端為第二腳。第二端數(shù)據(jù)引腳可以直接接在主機(jī)(單片機(jī))的IO口。同時(shí)為了提高穩(wěn)定性,一般在數(shù)據(jù)端和電源正極之間接一只4.7K的上拉電阻。第三腳NC為空腳,此管腳懸空不用。
5. 實(shí)驗(yàn)程序詳解
實(shí)驗(yàn)現(xiàn)象:開機(jī)的時(shí)候先檢測(cè)是否有DHT11存在,如果沒(méi)有,則提示錯(cuò)誤。只有在檢測(cè)到DHT11之后才會(huì)開始讀取溫濕度值。如果發(fā)現(xiàn)了DHT11,則程序每隔100ms左右讀取一次數(shù)據(jù)。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-474338.html
5.1 main.c
#include "stm32f4xx.h"
#include "delay.h"
#include "usart.h"
#include "LED.h"
#include "lcd.h"
#include "Key.h"
#include "usmart.h"
#include "MyI2C.h"
#include "AT24C02.h"
#include "DS18B20.h"
#include "DHT11.h"
//LCD狀態(tài)設(shè)置函數(shù)
void led_set(u8 sta)//只要工程目錄下有usmart調(diào)試函數(shù),主函數(shù)就必須調(diào)用這兩個(gè)函數(shù)
{
LED1=sta;
}
//函數(shù)參數(shù)調(diào)用測(cè)試函數(shù)
void test_fun(void(*ledset)(u8),u8 sta)
{
led_set(sta);
}
int main(void)
{
u8 t=0;
u8 temperature;
u8 humidity;
delay_init(168);
uart_init(115200);
LED_Init();
LCD_Init();
POINT_COLOR=RED;
LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");
LCD_ShowString(30,70,200,16,16,"DHT11 Text");
LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTER");
LCD_ShowString(30,110,200,16,16,"2023/20/23");
while(DHT11_Init())//返回1表示沒(méi)有檢測(cè)到DHT11的存在,報(bào)錯(cuò)
{
LCD_ShowString(30,130,200,16,16,"DHT11 Rrror");
delay_ms(200);
LCD_Fill(30,130,239,130+16,WHITE); //清除這塊區(qū)域 x 30~239 y 130~130+16
delay_ms(200);
}
LCD_ShowString(30,130,200,16,16,"DHT11 OK");
POINT_COLOR=BLUE;
LCD_ShowString(30,150,200,16,16,"Temperature: C");
LCD_ShowString(30,170,200,16,16,"Humidity: %");
while(1)
{
if(t%10==0) //每100ms讀取一次
{
DHT11_Read_Data(&temperature,&humidity); //讀取溫濕度的值
LCD_ShowNum(30+12*8,150,temperature,2,16); //顯示溫度
LCD_ShowNum(30+9*8,170,humidity,2,16); //顯示濕度
}
delay_ms(10);
t++;
if(t==20)
{
t=0;
LED0=!LED0;
}
}
}
5.2 DHT11.c
#include "stm32f4xx.h"
#include "DHT11.h"
#include "delay.h"
//復(fù)位DHT11
void DHT11_Reset(void)
{
//復(fù)位DHT11的時(shí)序:主機(jī)拉低總線,延時(shí)至少18ms,然后主機(jī)拉高總線,延時(shí)20-40us,等待從機(jī)應(yīng)答
DHT11_IO_OUT(); //復(fù)位時(shí)序是主機(jī)來(lái)完成的,所以首先設(shè)置主機(jī)IO引腳輸出模式
DHT11_DQ_OUT=0; //主機(jī)拉低總線
delay_ms(20); //延時(shí)至少18ms
DHT11_DQ_OUT=1; //主機(jī)拉高總線
delay_us(30); //延時(shí)20-40us
}
//等待DHT11的應(yīng)答信號(hào)
//返回1:未檢測(cè)到DHT11的存在
//返回0:存在
u8 DHT11_CheckExist(void)
{
//應(yīng)答信號(hào)的時(shí)序是:主機(jī)發(fā)送應(yīng)答信號(hào)后,從機(jī)DHT11會(huì)拉低信號(hào)線,保持40-50us。此時(shí),若讀取主機(jī)總線為低電平,這說(shuō)明DHT11發(fā)送了應(yīng)答信號(hào)
//DHT11發(fā)送應(yīng)答信號(hào)之后,再把總線拉高,保持40-50us,準(zhǔn)備發(fā)送數(shù)據(jù),每一位bit數(shù)據(jù)都是以低電平開始的。
u8 Existence=0;
DHT11_IO_IN(); //主機(jī)IO引腳設(shè)置為輸入模式,等待從機(jī)的應(yīng)答信號(hào)輸入
while(DHT11_DQ_IN&&Existence<100) //從機(jī)DHT11會(huì)拉低信號(hào)線,保持40-80us,等待應(yīng)答 按位&&操作必須兩個(gè)條件都為真才是真
{
//DHT11_DQ_IN為真,就一直在這里循環(huán),表示始終沒(méi)有接收到從機(jī)DHT11的應(yīng)答信號(hào);因?yàn)榭偩€拉低,讀取高電平是始終沒(méi)有響應(yīng)的
//DHT11_DQ_IN是從機(jī)DHT11發(fā)送主機(jī)MCU的信號(hào),應(yīng)答信號(hào)時(shí),從機(jī)會(huì)拉低信號(hào)線,因此,如果主機(jī)收到的是高電平,那么意味著沒(méi)有發(fā)送應(yīng)答信號(hào)
//Existence<100表示:設(shè)置一個(gè)緩沖時(shí)間去等待從機(jī)發(fā)送應(yīng)答,這里設(shè)置的就是100us
Existence++;
delay_us(1);
}
if(Existence>=100)
{
return 1; //主機(jī)給從機(jī)的緩沖時(shí)間是100us,主機(jī)等了從機(jī)100us還是沒(méi)有接收到應(yīng)答信號(hào),那么返回信息,未檢測(cè)到DHT11的存在
}
else //在給定的100us內(nèi)接收到了應(yīng)答信號(hào),將緩沖計(jì)時(shí)變量Existence清0,為后續(xù)總線拉高后延遲做準(zhǔn)備
Existence=0;
while(!DHT11_DQ_IN&&Existence<100) //拉低后再次拉高,準(zhǔn)備發(fā)送數(shù)據(jù),延遲40-80us
{
//!DHT11_DQ_IN表示主機(jī)接收到了應(yīng)答信號(hào),也就是主機(jī)接收到了低電平,延遲100us
Existence++;
delay_us(1);
}
if(Existence>=100)
{
return 1;
}
return 0;
}
//從DHT11讀取一個(gè)位
//返回值:1/0
u8 DHT11_Read_Bit(void)
{
//DHT11讀取一位的時(shí)序:不管讀的那一位是高電平1還是低電平0,首先從機(jī)DHT11都需要拉低總線
//數(shù)據(jù)0:從機(jī)拉低總線,延時(shí)12-14us,然后從機(jī)釋放總線,延時(shí)26-28us
//數(shù)據(jù)1:從機(jī)拉低總線,延時(shí)12-14us,然后從機(jī)釋放總線,延時(shí)116-118us
u8 data=0;
while(DHT11_DQ_IN&&data<100)//等待變?yōu)榈碗娖? //主機(jī)從DHT11讀取一位,從機(jī)要拉低總線,在沒(méi)有拉低之前,主機(jī)收到的DHT11_DQ_IN一定是高電平1,而通過(guò)觀察低電平的時(shí)序可以發(fā)現(xiàn),不管是邏輯1還是0,低電平延時(shí)12-14us
//所以設(shè)置的100us是遠(yuǎn)遠(yuǎn)大于低電平延時(shí)時(shí)間的,所以data<100這個(gè)條件在此while循環(huán)中一定為真,跳出循環(huán)的條件一定是DHT11_DQ_IN=0,也就是等待變?yōu)榈碗娖? {
data++;
delay_us(1);
}
data=0; //離開while循環(huán)時(shí)主機(jī)一定收到了低電平,此時(shí)DHT11_DQ_IN=0;設(shè)置data=0是為后續(xù)等待高電平做準(zhǔn)備
while(!DHT11_DQ_IN&&data<100) //等待變?yōu)楦唠娖? {
//從上面的循環(huán)出來(lái)時(shí),DHT11_DQ_IN=0,取反就為真
//條件data<100:低電平0的整個(gè)發(fā)送時(shí)序延時(shí)時(shí)間(包括低電平延時(shí)12-14us,高電平延時(shí)26-28us)也遠(yuǎn)遠(yuǎn)小于100us,所以data<100在該循環(huán)中也是始終為真的
// 高電平1的整個(gè)發(fā)送時(shí)間是大于100us的(低電平延時(shí)12-14us,高電平延時(shí)116-118us)
//經(jīng)分析,離開循環(huán)的條件是DHT11_DQ_IN變?yōu)楦唠娖?1,取反等于0,為假。在低電平0的12-14us過(guò)去以后,高電平信號(hào)就會(huì)來(lái)臨
data++;
delay_us(1);
}
//delay_us(40) 沒(méi)有這個(gè)延遲40us是無(wú)法判斷是數(shù)據(jù)1還是數(shù)據(jù)0的
delay_us(40);//從上一個(gè)while循環(huán)出來(lái)以后,時(shí)序停留在剛剛變?yōu)楦唠娖降乃查g,這個(gè)時(shí)候延時(shí)40us,數(shù)據(jù)0會(huì)跳過(guò)高電平,數(shù)據(jù)1會(huì)停留在高電平
if(DHT11_DQ_IN) //這個(gè)時(shí)候根據(jù)主機(jī)讀到的是1還是0設(shè)置返回值
return 1;
else
return 0;
}
//從DHT11讀取一個(gè)字節(jié)
//返回值:讀到的數(shù)據(jù)
u8 DHT11_Read_Byte(void)
{
u8 i,data;
data=0;
for(i=0;i<8;i++)
{
data=data<<1; //DHT11讀取的字節(jié)是高位先行的,所以每循環(huán)一次都要將上次讀取的那一位左移,右側(cè)最低位補(bǔ)0,每次都將新讀取的那一位數(shù)據(jù)和0進(jìn)行|或運(yùn)算。
data=data|DHT11_Read_Bit();
}
return data;
}
//從DHT11讀取一位數(shù)據(jù)
//temperature:溫度值(范圍:0~50℃)
//humidity:濕度值(范圍:20%~90%)
//返回值:0 正常;1 讀取失敗
u8 DHT11_Read_Data(u8 *temperature,u8 *humidity)
{
//DHT11的數(shù)據(jù)格式是:5個(gè)字節(jié),40位數(shù)據(jù),前兩位是濕度的整數(shù)和小數(shù)部分,第三、第四位是溫度的整數(shù)和小數(shù)部分,最后一位是校驗(yàn)位
u8 Buf[5]; //定義一個(gè)數(shù)組來(lái)存放收到的5個(gè)字節(jié)的數(shù)組
u8 i;
DHT11_Reset();
if(DHT11_CheckExist()==0) //應(yīng)答信號(hào)返回值為0,表示檢測(cè)到了DHT11應(yīng)答信號(hào)
{
for(i=0;i<5;i++) //調(diào)用讀字節(jié)函數(shù)將讀取到的5個(gè)字節(jié)存放到Buf數(shù)組中
{
Buf[i]=DHT11_Read_Byte();
}
if((Buf[0]+Buf[1]+Buf[2]+Buf[3])==Buf[4]) //檢驗(yàn)成功
{
*humidity=Buf[0]; //這里只顯示了溫濕度的整數(shù)部分
*temperature=Buf[2];
}
}
else
return 1; //DHT11_CheckExist()==1 表示沒(méi)有檢測(cè)到DHT11的應(yīng)答信號(hào),報(bào)錯(cuò)
return 0; //返回正常情況
}
//初始化DHT11的IO口 DQ 同時(shí)檢測(cè)DHT11的存在
//返回1:不存在
//返回0:存在
u8 DHT11_Init(void)
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE); //使能GPIOG時(shí)鐘
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //默認(rèn)設(shè)置為輸出模式
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOG,&GPIO_InitStructure);
DHT11_Reset();
return DHT11_CheckExist(); //初始化返回檢測(cè)DHT11是否成功,0:成功 1:收不到應(yīng)答信號(hào),報(bào)錯(cuò)
}
5.3 DHT11.h
#ifndef _DHT11__H_
#define _DHT11__H_
#include "sys.h"
//IO方向設(shè)置
//IO方向是通過(guò)位段設(shè)置的,調(diào)用GPIO模式寄存器,以下代碼已經(jīng)多次使用,如有不理解,可回頭溫習(xí)DS18B20的實(shí)驗(yàn)代碼
#define DHT11_IO_IN() {GPIOG->MODER&=~(3<<(9*2));GPIOG->MODER|=0<<9*2;} //PG9輸入模式
#define DHT11_IO_OUT() {GPIOG->MODER&=~(3<<(9*2));GPIOG->MODER|=1<<9*2;} //PG9輸出模式
//IO引腳設(shè)置
#define DHT11_DQ_OUT PGout(9) //PG9輸出
#define DHT11_DQ_IN PGin(9) //PG9輸入
void DHT11_Reset(void);
u8 DHT11_CheckExist(void);
u8 DHT11_Read_Bit(void);
u8 DHT11_Read_Byte(void);
u8 DHT11_Read_Data(u8 *temperature,u8 *humidity);
u8 DHT11_Init(void);
#endif
本節(jié)程序每一步都進(jìn)行了詳細(xì)的注釋,有哪里解釋的不對(duì)的,歡迎指正?。?!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-474338.html
到了這里,關(guān)于STM32F4_DHT11數(shù)字溫濕度傳感器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!