1. 程式人生 > >arduino學習系列——DHT11溫溼度感測器的使用

arduino學習系列——DHT11溫溼度感測器的使用

一、器材
arduino UNO、麵包板、DHT11溫溼度感測器、連線線
這裡說一下DHT11的基本情況:
(1)引腳說明:
1、VDD 供電 3.5V-5.5V DC
2、DATA 序列資料,單匯流排
3、GND 接地,電源負極。
(2)DHT11data資料格式:
一次傳輸40位資料=8bit溼度整數資料 + 8bit溼度小數資料 + 8bint溫度整數資料 + 8bit溫度小數資料 + 8bit校驗位
3、時序圖
這裡寫圖片描述
二、連線圖
這裡寫圖片描述
如圖所示,將DHT11的正極與5V電源介面相連,負極與GND相連,中間的資料介面與2號引腳相連。
三、程式碼

#include <dht11.h>
dht11 DHT11;
#define DHT11PIN 2
void setup(){
  Serial.begin(9600);
}

void loop(){
  Serial.println("/n");
  int chk = DHT11.read(DHT11PIN);
   Serial.print("Read sensor: ");
  switch (chk)
  {
    case DHTLIB_OK: 
                Serial.println("OK"); 
                break;
    case DHTLIB_ERROR_CHECKSUM: 
                Serial.println("Checksum error"); 
                break;
    case DHTLIB_ERROR_TIMEOUT: 
                Serial.println("Time out error"); 
                break;
    default: 
                Serial.println("Unknown error"); 
                break;
  }

  Serial.print("Humidity (%): ");
  Serial.println((float)DHT11.humidity, 2);

  Serial.print("Temperature (oC): ");
  Serial.println((float)DHT11.temperature, 2);
 delay(2000);
}

四、注意事項
1、程式碼中引用了#include <dht11.h>,這個是操作DHT11的庫檔案,有了它,就可以輕鬆操作我們這個溫溼度感測器了。但是引用這個庫檔案的操作步驟是:
(1)在網上找到並下載該庫檔案,包括一個頭檔案和一個.cpp檔案。
(2)在arduinoIDE中點選選單:程式–匯入庫–add library,然後選擇你存放庫檔案的那個資料夾。
(3)在程式碼中引用#include <dht11.h>,這樣就可以使用了。
2、#define DHT11PIN 2,表示定義引腳2的名字為DHT11PIN ,注意這個定義語句後面沒有分號。
五、原理分析
在硬體程式設計過程中,當你拿到一個器件,首先要了解他的引腳定義,這會告訴你這個東西應該怎麼連線,在一個就是要看他的時序圖,看了時序圖你就知道主從裝置之間進行資料採集過程中的程式碼應該怎麼寫,比如怎麼啟動,如何握手,怎麼採集真正的資料等等。
在我們這個試驗中,DHT11的時序圖是這樣的:
這裡寫圖片描述


下面對照dht11.cpp原始碼說說我們採集溫溼度資訊的原理(在程式碼中加了註釋,說明相關內容。):

#include "dht11.h"


int dht11::read(int pin)
{
	// BUFFER TO RECEIVE
	uint8_t bits[5];//這裡定義了5個八位的陣列,也就是40位資料,用來儲存資料採集的結果。
	uint8_t cnt = 7;//這個是用來給每一個數據的每一位輸入值時計數用的。
	uint8_t idx = 0;//這個是給5個數組計數用的。

	// EMPTY BUFFER
	for (int i=0; i< 5; i++) bits[i] = 0;
	//首先在這裡把這5個八位的陣列全部填0,也就是初始值為0.
	// REQUEST SAMPLE
	pinMode(pin, OUTPUT);
	//將引腳定義為輸出,也就是由arduino給DHT11寫資料。從上面的時序圖可以看出,要啟動DHT11首先要給他傳送18毫秒的低電平,再發送20~40微秒的高電平,DHT11只有看到了這樣的訊號,才會採集資料。
	digitalWrite(pin, LOW);
	delay(18);//這裡就是傳送18毫秒的低電平
	digitalWrite(pin, HIGH);
	delayMicroseconds(40);//這裡就是傳送40微秒的高電平
	pinMode(pin, INPUT);
	//傳送完之後,這就等於把DHT11啟動了,這時候我們就要從這個引腳上接受資料了,所以這時候要將這個引腳定義為輸入引腳。
	// ACKNOWLEDGE or TIMEOUT
	unsigned int loopCnt = 10000;
	while(digitalRead(pin) == LOW)
		if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
	//從時序圖中可以看出,接受資料一開始首先要讀取80微秒的低電平,這裡是一個等待,要把這80微秒等過去,但是有時候也有可能是感測器出現了故障,他一直髮低電平,如果你持續等待不就相當於宕機了,所以在這裡要設定一個超時,也就是說要等待,但時間長了,就認為出問題了,返回一個異常資訊。
	loopCnt = 10000;
	while(digitalRead(pin) == HIGH)
		if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
	//從時序圖中可以看出,在80微秒的低電平之後是80微秒的高電平,這裡仍然要等待,超時的原理與上面的低電平一樣。
	// READ OUTPUT - 40 BITS => 5 BYTES or TIMEOUT
	//根據時序圖,從下面開始就是40位的真正要讀取的資料了,那麼這裡用了一個for迴圈來一位一位的讀取這40bit的資料(注意是bite)。
	for (int i=0; i<40; i++)
	{
		//根據時序圖,可以看出,對於每一個bite位資料,都是由一個低電平和一個高電平組成,區分這一位資料是1還是0取決於高電平的時常,如果高電平的時常為70微秒則表示1,如果高電平的時常為26~28微秒則表示0,因此讀取每一位資料時,都是先等待把50微秒的低電平等過去,然後判斷高電平的時常,根據這個時常來判斷這bite的資料是1還是0.
		loopCnt = 10000;
		while(digitalRead(pin) == LOW)
			if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
		//這一句就是要把低電平等過去。
		unsigned long t = micros();
		//這裡使用函式micros()獲取了一個當前的時間,就是為了比較高電平的時常用的。
		loopCnt = 10000;
		while(digitalRead(pin) == HIGH)
			if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT;
		//這裡就把高電平讀出來了。
		if ((micros() - t) > 40) bits[idx] |= (1 << cnt);
		//然後再次使用micros()函式獲取當前時間,減去讀取高電平之前的時間點,也就是這個高電平的時常了,然後看這個時常是否大於40微秒,如果大於就認為是1,否則就認為這位是0.那麼這裡又是怎麼運算的呢?分析下:bits[idx]表示一個8位的陣列,假設他是0000 0000,運算子“|=”表示按位進行或運算,然後再把運算的結果賦給運算子左邊的變數。而(1 << cnt)表示把數字1的二進位制表示法向左移動cnt位,移動後的空位用0來填充。因此,對於一個八位的1可以表示為:0000 0001,剛才的初始化過程中我們知道cnt的值為7,所以,把這個0000 0001左移七位就變成了:1000 0000.然後將這個數與0000 0000進行|=運算,之後bits[idx]中的值就是1000 0000。可見這段程式碼實現的功能就是如果的到的這位資料是1,就將他儲存到bits[idx]相應的位上去。
		//下面這段程式碼就是在迴圈的過程中修改cnt和idx的值,然後進行一位一位的讀數而已。
		if (cnt == 0)   // next byte?
		//cnt為0表示一個8位的陣列已經裝滿了,要換到下一個八位的陣列上去,於是就把cnt復原為7,idx++讓idx直到bits的下一個八位的陣列上去。
		{
			cnt = 7;    // restart at MSB
			idx++;      // next byte!
		}
		else cnt--;
		//如果cnt不為0就表示這個八位的資料還沒有讀完,這時只需要讓cnt-1,來填充下一位資料就可以了。
		//注意,在初始化的過程中我們把這40位的資料都初始化為0了,所以只有當有1出現時才需要進行改變。
	}

	// WRITE TO RIGHT VARS
        // as bits[1] and bits[3] are allways zero they are omitted in formulas.
        //從開始的時候的原理中我們知道這40位資料第1個8位是溼度的整數部分,第3個8位是溫度的整數部分,下面這兩句程式碼就是把資料分別放在這兩個變數裡了。
	humidity    = bits[0]; 
	temperature = bits[2]; 

	uint8_t sum = bits[0] + bits[2];  

	if (bits[4] != sum) return DHTLIB_ERROR_CHECKSUM;
	return DHTLIB_OK;
	//最後再用校驗和驗證一下資料是否正確。
}
//
// END OF FILE
//

六、執行結果
通電之後,在電腦上開啟串列埠就可以看到採集到的溫溼度資訊。
這裡寫圖片描述