1.模塊介紹
DHT11溫濕度傳感器
DHT11溫濕度傳感器是數字式的,包括1個電阻式感濕元件和1個NTC測溫元件,內部自帶AD轉換功能,采用單總線,具有響應快、抗干擾能力強、性價比高等特點。該模塊總共4個引腳,其中兩個是電源引腳VCC和GND,一個是數據引腳,還有一個為空引腳。
DHT11外部引腳
目前流行的數據傳輸總線有II2C總線,SPI總線,單總線等,而DHT11則采用單總線傳輸數據。單總線,顧名思義,就是采用單根信號線,即可傳輸時鐘,又能傳輸數據,而且數據傳輸是雙向的,從而有主機和從機之別。在這里,stm32作為核心控制器,所以是主機,而DHT11為從機。 采用單總線進行數據傳輸,我們需要查看數據手冊的時序圖。
DHT11時序圖
總線空閑狀態為高電平,主機把總線拉低等待 DHT11 響應,主機把總線拉低必須大于 18 毫秒,保證 DHT11 能檢測到起始信號。DHT11 接收到主機的開始信號后, 等待主機開始信號結束,然后發送 80us 低電平響應信號.主機發送開始信號結束后,延時等待 20-40us 后, 讀取 DHT11 的響應信號,主機發送開始信號后,可以切換到輸入模式,或者輸出高電平均可, 總線由上拉電阻拉高。
DHT11啟動轉換時序圖
根據時序圖,單片機需要先將總線拉低至少18ms,然后拉高總線20~40us,此時主機的開始信號結束,檢測DHT11的響應信號。如果檢測到低電平,則DHT11響應,并且低電平時間維持80us,然后DHT11拉高總線80us。此時DHT11準備傳輸數據,傳輸的數據間隙為50us低電平,傳輸的數據通過高電平的時間長短來區分'0'和'1'。數據傳輸完畢,DHT11將總線拉低50us,最后主機再拉高總線。
數據'0'
數據'1'
2.軟件編程
(1)編寫延時函數
由于DHT11的時序比較嚴格,需要毫秒級別和微妙級別的延時。這里我們采用Systick去做延時。在之前按鍵掃描函數里也用到延時的,在此我敘述一下。
我們需要配置系統時鐘,然后把Systick設置成72,這樣就能產生1us時間基準,其次編寫Systick中斷處理函數,讓變量自減,從而達到延時的效果,最后編寫延時函數,也就是對自減的變量賦初始值。
__IO uint32_t TimingDelay;
/*配置SysTick函數*/
void systick_init(void)
{
/*配置Systick重載值,系統時鐘為72MHz*/
/*設置72,中斷時間:72*(1/72000000) = 1us*/
if(SysTick_Config(72)==1) //若SysTick_Config函數返回產生中斷信號,返回值為0
{
while(1); //SysTick_Config函數返回值為1,則等待
}
}
/*時間變量自減函數*/
void TimingDelay_Decrement(void)
{
if(TimingDelay!=0x00)
{
TimingDelay--;
}
}
/*SysTick中斷處理函數*/
void SysTick_Handler(void)
{
TimingDelay_Decrement();
}
/*延時函數,時間基準為1ms*/
void delay_ms(__IO uint32_t nTime)
{
TimingDelay = nTime*1000;
while(TimingDelay!=0);
}
/*延時函數,時間基準為1us*/
void delay_us(__IO uint32_t nTime)
{
TimingDelay = nTime;
while(TimingDelay!=0);
}
(2)配置相應的GPIO口作為單總線數據端
/*配置DHT11數據引腳,設置成浮空輸入模式*/
void dht11_gpio_portIn(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/*配置DHT11數據引腳,設置成推挽輸出模式*/
void dht11_gpio_portOut(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
由于DHT11采用單總線通信協議,所以數據傳輸是雙向的,所以分別將數據端口設置成浮空輸入模式和推挽輸出模式。并且將數據口的輸入和輸出定義成宏定義的形式。
#define DHT11_OUT_H GPIO_SetBits(GPIOA, GPIO_Pin_4)
#define DHT11_OUT_L GPIO_ResetBits(GPIOA, GPIO_Pin_4)
#define DHT11_IN GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4)
(3)根據DHT11時序圖,編寫時序函數
現在,我們開始編寫總線的驅動函數,根據時序圖,主機發送命令啟動轉換,接著,等待DHT11轉換響應并且輸出數據,最后讀取數據。
/*啟動總線函數*/
void dht11_reset(void)
{
dht11_gpio_portOut(); //設置成輸出模式
DHT11_OUT_L; //主機將總線拉低至少18ms
delay_ms(18);
DHT11_OUT_H; //主機拉高保持20~40us
delay_us(30);
dht11_gpio_portIn(); //設置成輸入模式,等待DHT11響應
}
/*DHT11響應函數*/
u8 dht11_scan(void)
{
return DHT11_IN; //返回值為DHT11的響應信號
}
實時監控DHT11的數據線,直至其產生出低電平,表示DHT11響應主機請求,開始傳輸數據。
/*DHT11讀取位函數*/
u8 dht11_read_bit(void)
{
while(DHT11_IN==RESET); //傳輸數據位前存在50us低電平
delay_us(40); //根據高電平的時間長短決定電平是1還是0
if(DHT11_IN==SET) //'0'電平持續時間為26~28us,'1'電平持續時間為70us
{
while(DHT11_IN==SET);
return 1; //若檢測到高電平,返回值為1
}
else
{
return 0; //若檢測到高電平,返回值為0
}
}
/*DHT11讀取字節函數*/
//注:數據最高位先傳輸
u8 dht11_read_byte(void)
{
u8 i,dat = 0x00;
for(i=0; i<8; i++)
{
dat = dat<<1;
dat = dat|dht11_read_bit();//將串行數據讀取出來
}
return dat;
}
當DHT11響應后,就開始通過單總線傳輸數據,在讀取位函數里,通過高電平的時間長短來判斷輸出的是'1'還是'0',在讀取字節函數里,調用讀取位函數,將傳輸的每8位整合出字節,并讀取出來。
我們查閱DHT11數據手冊,得知數據傳輸的結構(依次順序):濕度整數部分(1字節)、濕度小數部分(1字節)、溫度整數部分(1字節)、溫度小數部分(1字節)、校驗和(1字節)。這里,其實就是一個簡單的通信協議。校驗和就是源數據所有字節之和的低8位,確保傳輸數據的正確與穩定。
/*DHT11讀取數據函數*/
u8 dht11_read_data(void)
{
u8 i;
dht11_reset();
if(dht11_scan()==RESET) //DHT11發出響應信號
{
while(DHT11_IN==RESET); //DHT11拉低總線80us
while(DHT11_IN!=RESET); //DHT11拉高總線80us
for(i=0; i<5; i++)
{
buffer[i] = dht11_read_byte();
}
while(DHT11_IN==RESET); //發送完最后1bit數據后,等待50us低電平結束
dht11_gpio_portOut();
DHT11_OUT_H; //主機拉高總線
if(buffer[0]+buffer[1]+buffer[2]+buffer[3]==buffer[4])
{
return 1; //校驗成功
}
else
{
return 0; //校驗失敗
}
}
else
{
return 0; //DHT11未發出響應信號
}
}
在讀取字節里,先等待DHT11響應,然后開始接收數據,并且連續讀取5次,存放在事先定義好的數組里,主機發出結束信號,最后對讀取的數據進行校驗。
(4)測量顯示溫濕度
主函數調用DHT11讀數據函數,并調用lcd顯示函數,將溫度和濕度顯示出來即可。
if(dht11_read_data()==1)//讀取數據,前提是DHT11響應,并且數據校驗成功
{
humidity = buffer[0];//buffer[0]存放的是濕度整數部分
temperature = buffer[2];//buffer[2]存放的是溫度整數部分
}
lcd_display_string(2,0,'溫度');
lcd_display_num_m(2,32,temperature/10);
lcd_display_num_m(2,40,temperature%10);
lcd_display_string(4,0,“濕度”);
lcd_display_num_m(4,32,humidity/10);
lcd_display_num_m(4,40,humidity%10);
DHT11測量溫濕度
至此,通過本章的講解,我相信,大家應該對于DHT11模塊有了大致的了解,當然,如果你只是看看文章的話,可能效果不怎么理想。這些東西,都需要親自動手的,正所謂'實踐出真知'。所以,你可以在網上買開發板,再買一些模塊,不一定要和我的一樣。當然,想要挑戰自己的話,可以買塊最小系統板,這樣,外圍的硬件電路可以由自己搭建(功能自定義),靈活性強的同時,也鍛煉了自己的動手能力。如果你是會設計PCB的大佬,那更好,估計你的水平,就瀏覽一下我的文章即可。
上一篇:零基礎入門stm32選擇最多的stm32f103中斷學習總結
下一篇:STM32串口打印亂碼
- 熱門資源推薦
- 熱門放大器推薦
設計資源 培訓 開發板 精華推薦
- CAT3649AGEVB,CAT3649 評估板是一款高效四模式分數電荷泵,可驅動多達六個 LED
- LT3477IFE 87% 效率、4W LED 驅動器的典型應用電路
- 具有 2 線接口增益控制的 NAU8224、3.1W 立體聲無濾波器 D 類音頻放大器的典型應用
- 雙MIC電路+4階5KHz低通濾波制掉環境的背景噪音
- DSPIC30F4011最小系統
- OP295GSZ 單電源儀表放大器的典型應用
- 使用 ON Semiconductor 的 MC78T12 的參考設計
- 【實測成功】4路高電平控制繼電器
- LTC2259-14 演示板,14 位 80Msps ADC,LVDS 輸出,5-170MHz
- DM163025-1,PICDEM 全速 USB 演示板