DHT11是一款濕溫度一體化的數(shù)字傳感器。該傳感器包括一個電阻式測濕元件和一個NTC測溫元件,并與一個高性能8位單片機(jī)相連接。通過單片機(jī)等微處理器簡單的電路連接就能夠?qū)崟r的采集本地濕度和溫度。DHT11與單片機(jī)之間能采用簡單的單總線進(jìn)行通信,僅僅需要一個I/O口。傳感器內(nèi)部濕度和溫度數(shù)據(jù)40Bit的數(shù)據(jù)一次性傳給單片機(jī),數(shù)據(jù)采用校驗和方式進(jìn)行校驗,有效的保證數(shù)據(jù)傳輸?shù)臏?zhǔn)確性。DHT11功耗很低,5V電源電壓下,工作平均最大電流0.5mA。
DHT11的技術(shù)參數(shù)如下:
l 工作電壓范圍:3.3V-5.5V
l 工作電流 :平均0.5mA
l 輸出:單總線數(shù)字信號
l 測量范圍:濕度20~90%RH,溫度0~50℃
l 精度 :濕度±5%,溫度±2℃
l 分辨率 :濕度1%,溫度1℃
DHT11的管腳排列如圖36.1.1所示:
圖36.1.1 DHT11管腳排列圖
雖然DHT11與DS18B20類似,都是單總線訪問,但是DHT11的訪問,相對DS18B20來說要簡單很多。下面我們先來看看DHT11的數(shù)據(jù)結(jié)構(gòu)。
DHT11數(shù)字濕溫度傳感器采用單總線數(shù)據(jù)格式。即,單個數(shù)據(jù)引腳端口完成輸入輸出雙向傳輸。其數(shù)據(jù)包由5Byte(40Bit)組成。數(shù)據(jù)分小數(shù)部分和整數(shù)部分,一次完整的數(shù)據(jù)傳輸為40bit,高位先出。DHT11的數(shù)據(jù)格式為:8bit濕度整數(shù)數(shù)據(jù)+8bit濕度小數(shù)數(shù)據(jù)+8bit溫度整數(shù)數(shù)據(jù)+8bit溫度小數(shù)數(shù)據(jù)+8bit校驗和。其中校驗和數(shù)據(jù)為前四個字節(jié)相加。
傳感器數(shù)據(jù)輸出的是未編碼的二進(jìn)制數(shù)據(jù)。數(shù)據(jù)(濕度、溫度、整數(shù)、小數(shù))之間應(yīng)該分開處理。例如,某次從DHT11讀到的數(shù)據(jù)如圖36.1.2所示:
圖36.1.2 某次讀取到DHT11的數(shù)據(jù)
由以上數(shù)據(jù)就可得到濕度和溫度的值,計算方法:
濕度= byte4 。 byte3=45.0 (%RH)
溫度= byte2 。 byte1=28.0 ( ℃)
校驗= byte4+ byte3+ byte2+ byte1=73(=濕度+溫度)(校驗正確)
可以看出,DHT11的數(shù)據(jù)格式是十分簡單的,DHT11和MCU的一次通信最大為3ms左右,建議主機(jī)連續(xù)讀取時間間隔不要小于100ms。
下面,我們介紹一下DHT11的傳輸時序。DHT11的數(shù)據(jù)發(fā)送流程如圖36.1.3所示:
圖36.1.3 DHT11數(shù)據(jù)發(fā)送流程
首先主機(jī)發(fā)送開始信號,即:拉低數(shù)據(jù)線,保持t1(至少18ms)時間,然后拉高數(shù)據(jù)線t2(20~40us)時間,然后讀取DHT11的相應(yīng),正常的話,DHT11會拉低數(shù)據(jù)線,保持t3(40~50us)時間,作為響應(yīng)信號,然后DHT11拉高數(shù)據(jù)線,保持t4(40~50us)時間后,開始輸出數(shù)據(jù)。
DHT11輸出數(shù)字‘0’的時序如圖36.1.4所示:
圖36.1.4 DHT11數(shù)字‘0’時序
DHT11輸出數(shù)字‘1’的時序如圖36.1.5所示:
圖36.1.5 DHT11數(shù)字‘1’時序
通過以上了解,我們就可以通過STM32來實現(xiàn)對DHT11的讀取了。DHT11的介紹就到這里,更詳細(xì)的介紹,請參考DHT11的數(shù)據(jù)手冊。
36.2 硬件設(shè)計
由于開發(fā)板上標(biāo)準(zhǔn)配置是沒有DHT11這個傳感器的,只有接口,所以要做本章的實驗,大家必須找一個DHT11插在預(yù)留的DHT11接口上。
本章實驗功能簡介:開機(jī)的時候先檢測是否有DHT11存在,如果沒有,則提示錯誤。只有在檢測到DHT11之后才開始讀取溫濕度值,并顯示在LCD上,如果發(fā)現(xiàn)了DHT11,則程序每隔100ms左右讀取一次數(shù)據(jù),并把溫濕度顯示在LCD上。同樣我們也是用DS0來指示程序正在運(yùn)行。
所要用到的硬件資源如下:
1) 指示燈DS0
2) TFTLCD模塊
3) DHT11溫濕度傳感器
這些我們都已經(jīng)介紹過了,DHT11和DS18B20的接口是共用一個的,不過DHT11有4條腿,需要把U13的4個接口都用上,將DHT11傳感器插入到這個上面就可以通過STM32來讀取溫濕度值了。連接示意圖如圖36.2.1所示:
圖36.2.1 DHT11連接示意圖
這里要注意,將DHT11貼有字的一面朝內(nèi),而有很多孔的一面朝外,然后然后插入如圖所示的四個孔內(nèi)就可以了。
36.3 軟件設(shè)計
打開上一章的工程,首先在HARDWARE文件夾下新建一個DHT11的文件夾。然后新建一個dht11.c和dht11.h的文件保存在DHT11文件夾下,并將這個文件夾加入頭文件包含路徑。
打開dht11.c在該文件下輸入如下代碼:
#include “dht11.h”
#include “delay.h”
//復(fù)位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); //主機(jī)拉高20~40us
}
//等待DHT11的回應(yīng)
//返回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
{
retry++;
delay_us(1);
};
if(retry》=100)return 1;
return 0;
}
//從DHT11讀取一個位
//返回值:1/0
u8 DHT11_Read_Bit(void)
{
u8 retry=0;
while(DHT11_DQ_IN&&retry《100)//等待變?yōu)榈碗娖?/p>
{
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讀取一個字節(jié)
//返回值:讀到的數(shù)據(jù)
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讀取一次數(shù)據(jù)
//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++)//讀取40位數(shù)據(jù)
{
buf[i]=DHT11_Read_Byte();
}
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
{
*humi=buf[0];
*temp=buf[2];
}
}else return 1;
return 0;
}
//初始化DHT11的IO口 DQ 同時檢測DHT11的存在
//返回1:不存在
//返回0:存在
u8 DHT11_Init(void)
{
RCC-》APB2ENR|=1《《8; //使能PORTG口時鐘
GPIOG-》CRH&=0XFFFF0FFF;//PORTG.11 推挽輸出
GPIOG-》CRH|=0X00003000;
GPIOG-》ODR|=1《《11; //輸出1
DHT11_Rst();
return DHT11_Check();
}
該部分代碼就是根據(jù)我們前面介紹的單總線操作時序來讀取DHT11的溫濕度值的,DHT11的溫濕度值通過DHT11_Read_Data函數(shù)讀取,如果返回0,則說明讀取成功,返回1,則說明讀取失敗。保存dht11.c,并把該文件加入到HARDWARE組下,然后我們打開dht11.h,在該文件下輸入如下內(nèi)容:
#ifndef __DHT11_H
#define __DHT11_H
#include “sys.h”
//IO方向設(shè)置
#define DHT11_IO_IN() {GPIOG-》CRH&=0XFFFF0FFF;GPIOG-》CRH|=8《《12;}
#define DHT11_IO_OUT() {GPIOG-》CRH&=0XFFFF0FFF;GPIOG-》CRH|=3《《12;}
////IO操作函數(shù)
#define DHT11_DQ_OUT PGout(11) //數(shù)據(jù)端口 PG11
#define DHT11_DQ_IN PGin(11) //數(shù)據(jù)端口 PG11
u8 DHT11_Init(void); //初始化DHT11
u8 DHT11_Read_Data(u8 *temp,u8 *humi);//讀取溫濕度
u8 DHT11_Read_Byte(void); //讀出一個字節(jié)
u8 DHT11_Read_Bit(void); //讀出一個位
u8 DHT11_Check(void); //檢測是否存在DHT11
void DHT11_Rst(void); //復(fù)位DHT11
#endif
此部分代碼比較簡單,接下來,我們先保存這段代碼,然后打開test.c,在該文件下修改main函數(shù)如下:
int main(void)
{
u8 t=0;
u8 temperature;
u8 humidity;
Stm32_Clock_Init(9); //系統(tǒng)時鐘設(shè)置
uart_init(72,9600); //串口初始化為9600
delay_init(72); //延時初始化
LED_Init(); //初始化與LED連接的硬件接口
LCD_Init(); //初始化LCD
usmart_dev.init(72); //初始化USMART
KEY_Init(); //按鍵初始化
POINT_COLOR=RED;//設(shè)置字體為紅色
LCD_ShowString(60,50,200,16,16,“WarShip STM32”);
LCD_ShowString(60,70,200,16,16,“DHT11 TEST”);
LCD_ShowString(60,90,200,16,16,“ATOM@ALIENTEK”);
LCD_ShowString(60,110,200,16,16,“2012/9/12”);
while(DHT11_Init()) //DHT11初始化
{
LCD_ShowString(60,130,200,16,16,“DHT11 Error”);
delay_ms(200);
LCD_Fill(60,130,239,130+16,WHITE);
delay_ms(200);
}
LCD_ShowString(60,130,200,16,16,“DHT11 OK”);
POINT_COLOR=BLUE;//設(shè)置字體為藍(lán)色
LCD_ShowString(60,150,200,16,16,“Temp: C”);
LCD_ShowString(60,170,200,16,16,“Humi: %”);
while(1)
{
if(t==0)//每100ms讀取一次
{
DHT11_Read_Data(&temperature,&humidity); //讀取溫濕度值
LCD_ShowNum(60+40,150,temperature,2,16); //顯示溫度
LCD_ShowNum(60+40,170,humidity,2,16); //顯示濕度
}
delay_ms(10);
t++;
if(t==20)
{
t=0;
LED0=!LED0;
}
}
}