DHT11模塊簡介
DHT11是一款價格便宜,易於使用的溫度濕度測量二合一傳感器。它具有超小體積、極低功耗的特點。它使用單根總線與單片機進行雙向的串行數據傳輸,信號傳輸距離可達20米以上。非常適用於對精度和實時性要求不高的溫濕度測量場合。
本文將以DFRobot開源硬件平台的DHT11模塊和DFRduino開發板來演示,講解DHT11的驅動和使用。
DHT11電氣參數
電源電壓:3~5.5V(典型值:5V);
溫度量程:0~50℃,誤差 ±2℃;
濕度量程:20~90%RH,誤差 ±5%RH;
采樣周期:大於等於1秒/次。
DHT11硬件原理圖
數據總線DATA使用上拉電阻拉高,因此總線空閑時為高電平。上拉電阻阻值推薦范圍:4.7K~5.1K。
必要時在VDD和GND之間並一個100nF的去耦電容。
DHT11的工作原理
DHT11使用單一總線通信,即DATA引腳和單片機連接的線。總線總是處於空閑狀態和通信狀態這個2個狀態之間。
當單片機沒有與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釋放總線,總線在上拉電阻的作用下再次恢復到高電平狀態。
注意事項:
1、DHT11上電后,要等待 1秒 以越過不穩定狀態,在此期間不能發送任何指令。
2、DHT11屬於低速傳感器,兩次通信請求之間的間隔時間不能太短,一般來說要不能低於1秒。
3、當前DHT11通信幀的小數部分默認都是0,廠商預留給以后實現。所以一般只讀取整數值部分即可。校驗和定義為:前4個Byte的總和的低8位。
Ardunio驅動代碼
在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); }
Arduino社區貢獻的DHT11庫
在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); }
本文參考資料