DHT11是一款價格便宜,易於使用的溫度溼度測量二合一傳感器。它具備超小體積、極低功耗的特色。它使用單根總線與單片機進行雙向的串行數據傳輸,信號傳輸距離可達20米以上。很是適用於對精度和實時性要求不高的溫溼度測量場合。php
本文將以DFRobot開源硬件平臺的DHT11模塊和DFRduino開發板來演示,講解DHT11的驅動和使用。html
DHT11電氣參數git
電源電壓:3~5.5V(典型值:5V);數組
溫度量程:0~50℃,偏差 ±2℃;函數
溼度量程:20~90%RH,偏差 ±5%RH;oop
採樣週期:大於等於1秒/次。學習
數據總線DATA使用上拉電阻拉高,所以總線空閒時爲高電平。上拉電阻阻值推薦範圍:4.7K~5.1K。測試
必要時在VDD和GND之間並一個100nF的去耦電容。ui
DHT11使用單一總線通訊,即DATA引腳和單片機鏈接的線。總線老是處於空閒狀態和通訊狀態這個2個狀態之間。spa
當單片機沒有與DHT11交互時,總線處於空閒狀態,在上拉電阻的做用下,處於高電平狀態。
當單片機和DHT11正在通訊時,總線處於通訊狀態,一次完整的通訊過程以下:
①單片機將驅動總線的IO配置爲輸出模式。準備向DHT11發送數據。
②單片機將總線拉低至少18ms,以此來發送起始信號。再將總線拉高並延時20~40us,以此來表明起始信號結束。
③單片機將驅動總線的IO配置爲輸入模式,準備接收DHT11回傳的數據。
④當DHT11檢測倒單片機發送的起始信號後,就開始應答,回傳採集到的傳感器數據。DHT11先將總線拉低80us做爲對單片機的應答(ACK),而後接着將總線拉高80us,準備回傳採集到的溫溼度數據。溫溼度數據以固定的幀格式發送,具體格式以下圖:
能夠發現一幀爲40個bit,而每個bit的傳輸時序邏輯爲:每個bit都以50us的低電平(DHT11將總線拉低)爲先導,而後緊接着DHT11拉高總線,若是這個高電平持續時間爲26~28us,則表明邏輯0,若是持續70us則表明邏輯1。
⑤當一幀數據傳輸完成後,DHT11釋放總線,總線在上拉電阻的做用下再次恢復到高電平狀態。
注意事項:
一、DHT11上電後,要等待 1秒 以越過不穩定狀態,在此期間不能發送任何指令。
二、DHT11屬於低速傳感器,兩次通訊請求之間的間隔時間不能過短,通常來講要不能低於1秒。
三、當前DHT11通訊幀的小數部分默認都是0,廠商預留給之後實現。因此通常只讀取整數值部分便可。校驗和定義爲:前4個Byte的總和的低8位。
在DFRobot官網能夠找到DHT11模塊驅動庫,但出於學習和講解的目的,下面給出了我本身的驅動實現源代碼。使用C語言編寫,並在Arduino上測試。
//file:dht11.h //author:lulipro //date:2019-5-5 #ifndef DHT11_H__ #define DHT11_H__ #include <stdint.h> #ifdef __cplusplus extern "C" { #endif #define DHT11_OK (0) //讀取成功 #define DHT11_TIMEOUT (-1) //DHT11響應超時 #define DHT11_CHECKERROR (-2) //數據幀校驗錯誤 void DHT11_init(uint8_t pin); int DHT11_read(uint8_t* temperature,uint8_t* humidity ); #ifdef __cplusplus } #endif #endif
//file:dht11.c //author:lulipro //date:2019-5-5 #include "dht11.h" #include <Arduino.h> //for pinMode(),delay() 等 #include <string.h> //for memset() static uint8_t DHT11_dataPin_; //驅動DHT11的數據線引腳 static uint8_t DHT11_recvData_[5]; //存放 從DHT11讀取的數據的緩衝數組,40個bit
/**********************
*做用:初始化
*參數:pin,Arduino驅動DHT11的總線使用的IO引腳
*返回:無
**********************/ void DHT11_init(uint8_t pin) { DHT11_dataPin_ = pin; //delay(1000); }
/*********************
*做用:讀取一次DHT11的傳感器數據
*參數:temperature,指向存放溫度數據的指針;humidity,指向存放溼度數據的指針
*返回:函數的執行狀態:DHT11_OK,DHT11_TIMEOUT,DHT11_CHECKEROR
*********************/ int DHT11_read(uint8_t* temperature,uint8_t* humidity ) { uint8_t time_cnt; uint8_t i; uint8_t bit_position; memset(DHT11_recvData_,0,5); //緩衝數組內容清0 /*--------------主機發送起始信號----------------*/ pinMode(DHT11_dataPin_,OUTPUT); digitalWrite(DHT11_dataPin_, LOW); // 主機將總線拉低(時間>=18ms),使得DHT11可以接收到起始信號。 delay(20); //至少 18 ms digitalWrite(DHT11_dataPin_, HIGH); // 主機將總線拉高,表明起始信號結束。 delayMicroseconds(40); //延時20~40us /*--------------引腳配置爲輸入模式,準備接收傳感器回傳的數據-------------------*/ pinMode(DHT11_dataPin_,INPUT); //配置爲輸入模式 //DHT11將總線拉低至少80us,做爲DHT11的響應信號(ACK)。 time_cnt=0; while(LOW == digitalRead(DHT11_dataPin_)) { delayMicroseconds(5); ++time_cnt; if(time_cnt > 16) return DHT11_TIMEOUT; } //DHT11將總線拉高至少80us,爲發送傳感器數據作準備。 time_cnt=0; while(HIGH == digitalRead(DHT11_dataPin_)) { delayMicroseconds(5); ++time_cnt; if(time_cnt > 16) return DHT11_TIMEOUT; } /*-------------------DHT11數據幀的接收和解析------------------*/ for( i=0 ; i < 40 ; ++i ) { time_cnt = 0; while( LOW == digitalRead(DHT11_dataPin_) ) //拉低50us做爲bit信號的起始標誌 { time_cnt++; delayMicroseconds(5); if(time_cnt>10) return DHT11_TIMEOUT; } time_cnt = 0; while( HIGH == digitalRead(DHT11_dataPin_) ) //拉高。持續26~28us表示bit0,持續70us表示bit1 { time_cnt++; delayMicroseconds(5); if(time_cnt>14) return DHT11_TIMEOUT; } if(time_cnt>6){ //說明是bit1 bit_position = 7 - i%8; DHT11_recvData_[i/8] |= (uint8_t)(1<<bit_position); } } //------------檢驗和的比對------------- i = (uint8_t)(DHT11_recvData_[0] + DHT11_recvData_[1] + DHT11_recvData_[2] + DHT11_recvData_[3]) ; if(i != DHT11_recvData_[4] ) return DHT11_CHECKERROR; *humidity = DHT11_recvData_[0]; //回傳溼度數據 *temperature = DHT11_recvData_[2]; //回傳溫度數據 return DHT11_OK; }
硬件鏈接
Arduino 5V --- DHT11 VDD
Arduino pin5 --- DHT11 DATA
Arduino GND --- DHT11 GND
主程序
#include "dht11.h" #include <stdint.h> uint8_t temperature ,humidity ; //保存溫度和溼度的全局變量 void setup (void) { Serial.begin (115200); //波特率115200 DHT11_init(5); //使用Arduino的pin 5驅動DHT11 delay(1000); } void loop(void) { switch (DHT11_read(&temperature,&humidity)) { case DHT11_OK: Serial.print("Temperature:"); Serial.print(temperature,DEC); Serial.print("°C"); Serial.print(" Humidity:"); Serial.print(humidity,DEC); Serial.println("%RH"); break; case DHT11_TIMEOUT: Serial.println("time out"); break; case DHT11_CHECKERROR: Serial.println("check error"); break; default: Serial.println("unknown error"); break; } delay(2000); }
在DFRobot DHT11使用教程頁面的【樣例代碼】一節找到【下載樣例程序和庫文件】,點擊便可下載Arduino社區開發的DHT11驅動庫。
下載後完成後,解壓出來。在Arduino安裝目錄下的【librraies】目錄下新建文件夾【dht11】,並將解壓出來的dht11.cpp和dht11.h複製到新建的【dht11】文件夾下,便可完成庫的安裝。
安裝到Arduino的【librraies】目錄下的庫使用#include <xxx>的方式來包含其頭文件。例以下面的測試代碼:
// // FILE: dht11_test1.pde // PURPOSE: DHT11 library test sketch for Arduino // #include <dht11.h> //包含驅動庫的頭文件 dht11 DHT; //創建一個dht11模塊對象 #define DHT11_PIN 4 void setup(){ Serial.begin(9600); Serial.println("DHT TEST PROGRAM "); Serial.print("LIBRARY VERSION: "); Serial.println(DHT11LIB_VERSION); Serial.println(); Serial.println("Type,\tstatus,\tHumidity (%),\tTemperature (C)"); } void loop(){ int chk; Serial.print("DHT11, \t"); chk = DHT.read(DHT11_PIN); // READ DATA switch (chk){ case DHTLIB_OK: Serial.print("OK,\t"); break; case DHTLIB_ERROR_CHECKSUM: Serial.print("Checksum error,\t"); break; case DHTLIB_ERROR_TIMEOUT: Serial.print("Time out error,\t"); break; default: Serial.print("Unknown error,\t"); break; } // DISPLAT DATA Serial.print(DHT.humidity,1); Serial.print(",\t"); Serial.println(DHT.temperature,1); delay(2000); }