上一章,我們介紹了數字溫度傳感器 DS18B20 的使用,本章我們將介紹數字溫溼度
傳感器DHT11 的使用,該傳感器不但能測溫度,還能測溼度。本章我們將向大家介
紹如何使用 STM32F1來讀取 DHT11 數字溫溼度傳感器,從而得到環境溫度和溼度
等信息,並把從溫溼度值顯示在TFTLCD 模塊上。本章分為如下幾個部分:
36.1 DHT11 簡介
36.2 硬體設計
36.3 軟體設計
36.4 下載驗證
36.1 DHT11 簡介
DHT11 是一款溼溫度一體化的數字傳感器。該傳感器包括一個電阻式測溼元件和一個 NTC
測溫元件,並與一個高性能 8 位單片機相連接。通過單片機等微處理器簡單的電路連接就能夠
實時的採集本地溼度和溫度。DHT11 與單片機之間能採用簡單的單總線進行通信,僅僅需要一
個 I/O 口。傳感器內部溼度和溫度數據 40Bit 的數據一次性傳給單片機,數據採用校驗和方式
進行校驗,有效的保證數據傳輸的準確性。DHT11 功耗很低,5V 電源電壓下,工作平均最大電流 0.5mA。
DHT11 的技術參數如下:
工作電壓範圍:3.3V-5.5V
工作電流 :平均 0.5mA
輸出:單總線數位訊號
測量範圍:溼度 20~90%RH,溫度 0~50℃
精度 :溼度±5%,溫度±2℃
解析度 :溼度 1%,溫度 1℃
DHT11 的管腳排列如圖 36.1.1 所示:
雖然 DHT11 與 DS18B20 類似,都是單總線訪問,但是 DHT11 的訪問,相對 DS18B20 來
說要簡單很多。下面我們先來看看 DHT11 的數據結構。
DHT11 數字溼溫度傳感器採用單總線數據格式。即,單個數據引腳埠完成輸入輸出雙向
傳輸。其數據包由 5Byte(40Bit)組成。數據分小數部分和整數部分,一次完整的數據傳輸為
40bit,高位先出。DHT11 的數據格式為:8bit 溼度整數數據+8bit 溼度小數數據+8bit 溫度整數
數據+8bit 溫度小數數據+8bit 校驗和。其中校驗和數據為前四個字節相加。
傳感器數據輸出的是未編碼的二進位數據。數據(溼度、溫度、整數、小數)之間應該分開
處理。例如,某次從 DHT11 讀到的數據如圖 36.1.2 所示:
由以上數據就可得到溼度和溫度的值,計算方法:
溼度= byte4 . byte3=45.0 (%RH)
溫度= byte2 . byte1=28.0 ( ℃)
校驗= byte4+ byte3+ byte2+ byte1=73(=溼度+溫度)(校驗正確)
可以看出,DHT11的數據格式是十分簡單的,DHT11和 MCU的一次通信最大為 3ms 左右,
建議主機連續讀取時間間隔不要小於 100ms。
下面,我們介紹一下 DHT11 的傳輸時序。DHT11 的數據發送流程如圖 36.1.3 所示:
首先主機發送開始信號,即:拉低數據線,保持 t1(至少 18ms)時間,然後拉高數據線 t2
(20~40us)時間,然後讀取 DHT11 的響應,正常的話,DHT11 會拉低數據線,保持 t3(40~50us)
時間,作為響應信號,然後 DHT11 拉高數據線,保持 t4(40~50us)時間後,開始輸出數據。
DHT11 輸出數字『0』的時序如圖 36.1.4 所示:
DHT11 輸出數字『1』的時序如圖 36.1.5 所示:
通過以上了解,我們就可以通過 STM32F1 來實現對 DHT11 的讀取了。DHT11 的介紹就到這裡,更詳細的介紹,請參考 DHT11 的數據手冊。
36.2 硬體設計
由於開發板上標準配置是沒有 DHT11 這個傳感器的,只有接口,所以要做本章的實驗,
大家必須找一個 DHT11 插在預留的 DHT11 接口上。
本章實驗功能簡介:開機的時候先檢測是否有 DHT11 存在,如果沒有,則提示錯誤。只
有在檢測到 DHT11 之後才開始讀取溫溼度值,並顯示在 LCD 上,如果發現了 DHT11,則程
序每隔 100ms 左右讀取一次數據,並把溫溼度顯示在 LCD 上。同樣我們也是用 DS0 來指示程
序正在運行。
所要用到的硬體資源如下:
1) 指示燈 DS0
2) TFTLCD 模塊
3) DHT11 溫溼度傳感器
這些我們都已經介紹過了,DHT11 和 DS18B20 的接口是共用一個的,不過 DHT11 有 4 條
腿,需要把 U6 的 4 個接口都用上,將 DHT11 傳感器插入到這個上面就可以通過 STM32F1 來
讀取溫溼度值了。連接示意圖如圖 36.2.1 所示:
這裡要注意,將 DHT11 貼有字的一面朝內,而有很多孔的一面(網面)朝外,然後然後插入
如圖所示的四個孔內就可以了。
36.3 軟體設計
打開 DHT11 數字溫溼度傳感器實驗工程可以發現,我們在工程中添加了 dht11.c 文件和
dht11.h 文件,所有 DHT11 相關的驅動代碼和定義都在這兩個文件中。
打開 dht11.c 代碼如下:
//復位 DHT11
void DHT11_Rst(void)
{
DHT11_IO_OUT(); //SET OUTPUT
DHT11_DQ_OUT=0; //拉低 DQ
delay_ms(20); //拉低至少 18ms
DHT11_DQ_OUT=1; //DQ=1
delay_us(30); //主機拉高 20~40us
}
//等待 DHT11 的回應
//返回 1:未檢測到 DHT11 的存在
//返回 0:存在
u8 DHT11_Check(void)
u8 retry=0;
DHT11_IO_IN(); //SET INPUT
while (DHT11_DQ_IN&&retry<100) //DHT11 會拉低 40~80us
retry++;
delay_us(1);
};
if(retry>=100)return 1;
else retry=0;
while (!DHT11_DQ_IN&&retry<100) //DHT11 拉低後會再次拉高 40~80us
return 0;
//從 DHT11 讀取一個位
//返回值:1/0
u8 DHT11_Read_Bit(void)
while(DHT11_DQ_IN&&retry<100) //等待變為低電平
retry ++;
delay_ us( 1 );
retry=0;
while(!DHT11_DQ_IN&&retry<100) //等待變高電平
retry++;
delay_us(1);
delay_us(40);//等待 40us
if(DHT11_DQ_IN)return 1;
else return 0;
//從 DHT11 讀取一個字節
//返回值:讀到的數據
u8 DHT11_Read_Byte(void)
{
u8 i,dat;
dat=0;
for (i=0;i<8;i++)
dat<<=1;
dat|=DHT11_Read_Bit();
}
return dat;
//從 DHT11 讀取一次數據
//temp:溫度值(範圍:0~50°)
//humi:溼度值(範圍:20%~90%)
//返回值:0,正常;1,讀取失敗
u8 DHT11_Read_Data(u8 *temp,u8 *humi)
u8 buf[5];
u8 i;
DHT11_Rst();
if(DHT11_Check()==0)
for(i=0;i<5;i++) buf[i]=DHT11_Read_Byte();//讀取 40 位數據
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
*humi=buf[0];
*temp=buf[2];
}else return 1;
//初始化 DHT11 的 IO 口 DQ 同時檢測 DHT11 的存在
//返回 1:不存在
u8 DHT11_Init(void)
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOG_CLK_ENABLE(); //開啟 GPIOG 時鐘
GPIO_Initure.Pin=GPIO_PIN_11; //PG11
GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推輓輸出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH; //高速
HAL_GPIO_Init(GPIOG,&GPIO_Initure); //初始化
DHT11_Rst();
return DHT11_Check();
該部分代碼就是根據我們前面介紹的單總線操作時序來讀取 DHT11 的溫溼度值的,DHT11
的溫溼度值通過 DHT11_Read_Data 函數讀取,如果返回 0,則說明讀取成功,返回 1,則說明
讀取失敗。同樣我們打開 dht11.h 可以看到,頭文件中主要是一些埠配置以及函數申明,代碼
比較簡單。 接下來我們打開 main.c,該文件代碼如下:
int main(void)
u8 t=0;
u8 temperature;
u8 humidity;
HAL_Init(); //初始化 HAL 庫
Stm32_Clock_Init(RCC_PLL_MUL9); //設置時鐘,72M
delay_init(72); //初始化延時函數
uart_init(115200); //初始化串口
LED_Init(); //初始化 LED
KEY_Init(); //初始化按鍵
LCD_Init(); //初始化 LCD FSMC 接口
POINT_COLOR=RED;
LCD_ShowString(30,50,200,16,16,"WarShip STM32");
LCD_ShowString(30,70,200,16,16,"DHT11 TEST");
LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,110,200,16,16,"2019/9/19");
while(DHT11_Init()) //DHT11 初始化
LCD_ShowString(30,130,200,16,16,"DHT11 Error");
delay_ms(200);
LCD_Fill(30,130,239,130+16,WHITE);
LCD_ShowString(30,130,200,16,16,"DHT11 OK");
POINT_COLOR=BLUE;//設置字體為藍色
LCD_ShowString(30,150,200,16,16,"Temp: C");
LCD_ShowString(30,170,200,16,16,"Humi: %");
while(1)
if(t%10==0)//每 100ms 讀取一次
DHT11_Read_Data(&temperature,&humidity); //讀取溫溼度值
LCD_ShowNum(30+40,150,temperature,2,16); //顯示溫度
LCD_ShowNum(30+40,170,humidity,2,16); //顯示溼度
delay_ms(10);
t++;
if(t==20)
t=0;
LED0=!LED0;
主函數比較簡單,進行一系列初始化後,如果 DHT11 初始化成功,那麼每隔 100ms 讀取
一次轉換數據並顯示在液晶上。至此,我們本章的軟體設計就結束了。
36.4 下載驗證
在代碼編譯成功之後,我們通過下載代碼到 ALIENTEK 戰艦 STM32F1 開發板上,可以看
到 LCD 顯示開始顯示當前的溫度值(假定 DHT11 已經接上去了),如圖 36.4.1 所示:
至此,本章實驗結束。大家可以將本章通過 DHT11 讀取到的溫度值,和前一章的通過DS18B20 讀取到的溫度值對比一下,看看哪個更準確?