一奇徒、介紹
?? 數(shù)字溫濕度傳感器DHT11是一種復(fù)合傳感器干像,包含溫度和濕度的校準(zhǔn)數(shù)字信號(hào)輸出赖歌。采用專(zhuān)用數(shù)字模塊采集技術(shù)和溫濕度傳感技術(shù)构资,確保產(chǎn)品具有高可靠性和優(yōu)異的長(zhǎng)期穩(wěn)定性割坠。
?? 該傳感器包含一個(gè)電阻濕感元件和一個(gè)NTC溫度測(cè)量設(shè)備齐帚,并與一個(gè)高性能8位微控制器連接。其精度:濕度+-5%RH彼哼, 溫度+-2℃对妄。量程:濕度20-90%RH, 溫度0~50℃敢朱。采樣周期:大于等于1秒/次剪菱。
?? 在我們剛開(kāi)始練習(xí)寫(xiě)傳感器的時(shí)序時(shí),DHT11非常適合新手入門(mén)練習(xí)如何寫(xiě)時(shí)序拴签。
二孝常、組件
★Raspberry Pi主板*1
★樹(shù)莓派電源*1
★40P軟排線*1
★濕度傳感器DHT11模塊*1
★面包板*1
★跳線若干
三、實(shí)驗(yàn)原理
?? DHT11是一款價(jià)格便宜蚓哩,易于使用的溫度濕度測(cè)量二合一傳感器茫因。它具有超小體積、極低功耗的特點(diǎn)杖剪。它使用單根總線與單片機(jī)進(jìn)行雙向的串行數(shù)據(jù)傳輸冻押,信號(hào)傳輸距離可達(dá)20米以上。非常適用于對(duì)精度和實(shí)時(shí)性要求不高的溫濕度測(cè)量場(chǎng)合盛嘿。
?? 數(shù)據(jù)總線DATA使用上拉電阻拉高洛巢,因此總線空閑時(shí)為高電平。上拉電阻阻值推薦范圍:4.7K~5.1K次兆。必要時(shí)在VDD和GND之間并一個(gè)100nF的去耦電容稿茉。
1. DHT11的數(shù)據(jù)格式:
??DATA 用于樹(shù)莓派與DHT11之間的通訊和同步,采用單總線數(shù)據(jù)格式,一次通訊時(shí)間4ms左右漓库,數(shù)據(jù)分小數(shù)部分和整數(shù)部分恃慧,具體格式在下面說(shuō)明,操作流程如下:
?? DHT11用的是單總線協(xié)議渺蒿,一次傳送40位的數(shù)據(jù)痢士。 注意了,看到這一句話茂装,也就是說(shuō)我們每次讀取DHT11的數(shù)據(jù)時(shí)怠蹂,都要一次性讀取40次,也就是讀取40位少态。并且數(shù)據(jù)前16位是與濕度相關(guān)的城侧,中間16位是與溫度相關(guān)的,最后八位是用來(lái)校驗(yàn)的彼妻,當(dāng)我們校驗(yàn)成功后嫌佑,證明這一次的溫濕度結(jié)果正確的,我們的樹(shù)莓派就可以使用這個(gè)溫濕度值侨歉;如果校驗(yàn)不通過(guò)歧强,那么就代表我們這次讀取出來(lái)的溫濕度值,是錯(cuò)誤的(也許是我們的時(shí)序錯(cuò)誤了为肮,也許是傳感器的問(wèn)題),我們不進(jìn)行采樣肤京。
2. DHT11的工作原理:
DHT11的總體通信流程:
第一步:主機(jī)(樹(shù)莓派)先發(fā)送開(kāi)始信號(hào)颊艳,從機(jī)(DHT11)會(huì)返回一個(gè)相應(yīng)信號(hào)進(jìn)行應(yīng)答。
第二步:主機(jī)信號(hào)線拉高準(zhǔn)備接收數(shù)據(jù)忘分。
第三步:開(kāi)始接收數(shù)據(jù)(一次接收40位)棋枕。
?? DHT11使用單一總線通信,即DATA引腳和單片機(jī)連接的線妒峦≈匕撸總線總是處于空閑狀態(tài)和通信狀態(tài)這個(gè)2個(gè)狀態(tài)之間。當(dāng)樹(shù)莓派沒(méi)有與DHT11交互時(shí)肯骇,總線處于空閑狀態(tài)窥浪,在上拉電阻的作用下,處于高電平狀態(tài)笛丙。
?? 當(dāng)單片機(jī)和DHT11正在通信時(shí)漾脂,總線處于通信狀態(tài),一次完整的通信過(guò)程如下:
?? 第一步:DHT11 上電后(DHT11 上電后要等待 1秒以越過(guò)不穩(wěn)定狀態(tài)在此期間不能發(fā)送任何指令)胚鸯,測(cè)試環(huán)境溫濕度數(shù)據(jù)骨稿,幵記錄數(shù)據(jù),同時(shí) DHT11 的 DATA 數(shù)據(jù)線由上拉電阻拉高一直保持高電;此時(shí) DHT11 的DATA 引腳處于輸入狀態(tài)坦冠,時(shí)刻檢測(cè)外部信號(hào)形耗。
?? 第二步:微處理器的 I/O 設(shè)置為輸出,同時(shí)輸出低電平辙浑,且低電平保持時(shí)間不能小于 18ms激涤,然后輸出高電平20~40us,再樹(shù)莓派的 I/O設(shè)置為輸入狀態(tài)例衍,等待 DHT11 作出回答信號(hào)昔期,發(fā)送信號(hào)如圖所示:
?? 第三步:DHT11 的 DATA 引腳檢測(cè)到外部信號(hào)有低電平時(shí),等待外部信號(hào)低電平結(jié)束佛玄,延遲后 DHT11 的 DATA引腳處于輸出狀態(tài)硼一,輸出 80 微秒的低電平作為應(yīng)答信號(hào),緊接著輸出 80 微秒的高電平通知外設(shè)準(zhǔn)備接收數(shù)據(jù)梦抢,樹(shù)莓派的 I/O 此時(shí)處于輸入狀態(tài)般贼,檢測(cè)到 I/O 有低電平(DHT11 回應(yīng)信號(hào))后,等待 80 微秒的高電平后的數(shù)據(jù)接收奥吩,發(fā)送信號(hào)如圖所示:
?? 第四步:由 DHT11 的 DATA 引腳輸出 40 位數(shù)據(jù)哼蛆,樹(shù)莓派根據(jù) I/O 電平的變化接收 40 位數(shù)據(jù),位數(shù)據(jù)“0”的格式為: 50 微秒的低電平和 26-28 微秒的高電平霞赫;位數(shù)據(jù)“1”的格式為: 50 微秒的低電平加 70微秒的高電平腮介。位數(shù)據(jù)“0”、“1”格式信號(hào)如圖所示:
?? 我們可以把這一段的時(shí)序理解為叠洗,DHT11先把數(shù)據(jù)線拉低50us,然后我們?cè)偃?duì)比高電平持續(xù)的時(shí)間旅东,如果持續(xù)時(shí)間較短灭抑,則為位“0”;如果持續(xù)時(shí)間較長(zhǎng)抵代,則為位“1”腾节。
?? 結(jié)束信號(hào):DHT11 的 DATA 引腳輸出 40 位數(shù)據(jù)后,繼續(xù)輸出低電平 50 微秒后轉(zhuǎn)為輸入狀態(tài)荤牍,由于上拉電阻隨之變?yōu)楦唠娖桨赶佟5?DHT11 內(nèi)部重測(cè)環(huán)境溫濕度數(shù)據(jù),幵記錄數(shù)據(jù)康吵,等待外部信號(hào)的到來(lái)救湖。
注意事項(xiàng):
1、DHT11上電后涎才,要等待 1秒 以越過(guò)不穩(wěn)定狀態(tài)鞋既,在此期間不能發(fā)送任何指令力九。
2、DHT11屬于低速傳感器邑闺,兩次通信請(qǐng)求之間的間隔時(shí)間不能太短跌前,一般來(lái)說(shuō)要不能低于1秒。
對(duì)DHT11的時(shí)序做一個(gè)總結(jié):
一. 主機(jī)(單片機(jī))發(fā)送起始信號(hào):
??1.主機(jī)先拉高data陡舅。
??2.拉低data延遲18ms抵乓。
??3.拉高data(單片機(jī)引腳設(shè)置為輸入)。
二. 從機(jī)(DHT11)收到起始信號(hào)后進(jìn)行應(yīng)答:
??從機(jī)拉低data靶衍,主機(jī)讀取到data線被拉低持續(xù)80us后從機(jī)拉高data線灾炭, 持續(xù)80us,直到高電平結(jié)束颅眶,意味著主機(jī)可以開(kāi)始接受數(shù)據(jù)蜈出。
三. 主機(jī)開(kāi)始接收數(shù)據(jù):
??1.主機(jī)先把data線拉高(io設(shè)置為輸入)。
??2.從機(jī)把data線拉低涛酗,主機(jī)讀取data線電平续滋,直到低電平結(jié)束(大約50us)從機(jī)拉高data線后肃续,對(duì)比高電平持續(xù)的時(shí)間捆愁,如果持續(xù)時(shí)間較短饿凛,則為位“0”;如果持續(xù)時(shí)間較長(zhǎng)時(shí)剖笙,則為位“1”卵洗。
??3.繼續(xù)重復(fù)上述1,2步驟累計(jì)40次。
四. data線拉低50us代表讀取結(jié)束
五. 校驗(yàn)數(shù)據(jù)
更多資料請(qǐng)參考DHT11 官方手冊(cè):
https://www.dfrobot.com.cn/image/data/DFR0067/DFR0067_DS_10.pdf
四弥咪、實(shí)驗(yàn)步驟
??第1步:連接電路过蹂。
樹(shù)莓派 | T型轉(zhuǎn)接板 | 溫濕度傳感器 |
---|---|---|
GPIO0 | G17 | OUT(DATA) |
5V | 5V | VCC |
GND | GND | GND |
??第2步:編寫(xiě)控制程序。將提取的二進(jìn)制數(shù)據(jù)轉(zhuǎn)化為十進(jìn)制數(shù)據(jù)酪夷,校驗(yàn)后打印出來(lái)。
??本次編程中將用到NumPy(Numerical Python)擴(kuò)展程序庫(kù)孽惰,支持大量的維度數(shù)組與矩陣運(yùn)算晚岭,此外也針對(duì)數(shù)組運(yùn)算提供大量的數(shù)學(xué)函數(shù)庫(kù)。詳情參考NumPy 教程:
??https://www.runoob.com/numpy/numpy-tutorial.html
??為便于對(duì)比DHT11高電平持續(xù)的時(shí)間勋功,我們?cè)O(shè)置了一個(gè)計(jì)數(shù)器參數(shù)k坦报,如果持續(xù)時(shí)間較短,則k值較锌裥片择;如果持續(xù)時(shí)間較長(zhǎng)時(shí),則k值較大骚揍。當(dāng)然字管,也可以使用時(shí)間函數(shù)直接對(duì)比時(shí)間長(zhǎng)短啰挪,但是程序相對(duì)要復(fù)雜一些。比如使用GPIO.add_event_detect()和time.time()函數(shù)嘲叔。
??從上面的截圖中可以看出亡呵,高電平持續(xù)的時(shí)間較短,26-28 微秒時(shí)硫戈,參數(shù)k等于5或6锰什;高電平持續(xù)的時(shí)間較長(zhǎng),70 微秒時(shí)丁逝,參數(shù)k等于17或18汁胆。
#!/usr/bin/env python
import RPi.GPIO as GPIO
import numpy as np
import time
DHTPIN = 17 #引腳號(hào)17
GPIO.setmode(GPIO.BCM) #以BCM編碼格式
def read_dht11_dat():
GPIO.setup(DHTPIN, GPIO.OUT)
GPIO.output(DHTPIN, GPIO.LOW)
#給信號(hào)提示傳感器開(kāi)始工作,并保持低電平18ms以上
time.sleep(0.02) #這里保持20ms
GPIO.output(DHTPIN, GPIO.HIGH) #然后輸出高電平
GPIO.setup(DHTPIN, GPIO.IN)
# 發(fā)送完開(kāi)始信號(hào)后得把輸出模式換成輸入模式,不然信號(hào)線上電平始終被拉高
while GPIO.input(DHTPIN) == GPIO.LOW:
continue
#DHT11發(fā)出應(yīng)答信號(hào)霜幼,輸出 80 微秒的低電平
while GPIO.input(DHTPIN) == GPIO.HIGH:
continue
#緊接著輸出 80 微秒的高電平通知外設(shè)準(zhǔn)備接收數(shù)據(jù)
#開(kāi)始接收數(shù)據(jù)
j = 0 #計(jì)數(shù)器
data = [] #收到的二進(jìn)制數(shù)據(jù)
kk=[] #存放每次高電平結(jié)束后的k值的列表
while j < 40:
k = 0
while GPIO.input(DHTPIN) == GPIO.LOW: # 先是 50 微秒的低電平
continue
while GPIO.input(DHTPIN) == GPIO.HIGH: # 接著是26-28微秒的高電平嫩码,或者 70 微秒的高電平
k += 1
if k > 100:
break
kk.append(k)
if k < 8: #26-28 微秒時(shí)高電平時(shí)通常k等于5或6
data.append(0) #在數(shù)據(jù)列表后面添加一位新的二進(jìn)制數(shù)據(jù)“0”
else: #70 微秒時(shí)高電平時(shí)通常k等于17或18
data.append(1) #在數(shù)據(jù)列表后面添加一位新的二進(jìn)制數(shù)據(jù)“1”
j += 1
print("sensor is working.")
print '初始數(shù)據(jù)高低電平:\n',data #輸出初始數(shù)據(jù)高低電平
print '參數(shù)k的列表內(nèi)容:\n',kk #輸出高電平結(jié)束后的k值
m = np.logspace(7,0,8,base=2,dtype=int) #logspace()函數(shù)用于創(chuàng)建一個(gè)于等比數(shù)列的數(shù)組
#即[128 64 32 16 8 4 2 1],8位二進(jìn)制數(shù)各位的權(quán)值
data_array = np.array(data) #將data列表轉(zhuǎn)換為數(shù)組
#dot()函數(shù)對(duì)于兩個(gè)一維的數(shù)組辛掠,計(jì)算的是這兩個(gè)數(shù)組對(duì)應(yīng)下標(biāo)元素的乘積和(數(shù)學(xué)上稱(chēng)之為內(nèi)積)
humidity = m.dot(data_array[0:8]) #用前8位二進(jìn)制數(shù)據(jù)計(jì)算濕度的十進(jìn)制值
humidity_point = m.dot(data_array[8:16])
temperature = m.dot(data_array[16:24])
temperature_point = m.dot(data_array[24:32])
check = m.dot(data_array[32:40])
print humidity,humidity_point,temperature,temperature_point,check
tmp = humidity + humidity_point + temperature + temperature_point
#十進(jìn)制的數(shù)據(jù)相加
if check == tmp: #數(shù)據(jù)校驗(yàn)谢谦,相等則輸出
return humidity, temperature
else: #錯(cuò)誤輸出錯(cuò)誤信息
return False
def main():
print "Raspberry Pi DHT11 Temperature test program\n"
time.sleep(1) #通電后前一秒狀態(tài)不穩(wěn)定,時(shí)延一秒
while True:
result = read_dht11_dat()
if result:
humidity, temperature = result
print "humidity: %s %%, Temperature: %s ℃" % \
(humidity, temperature)
print '\n'
time.sleep(1)
if result == False:
print "Data are wrong,skip\n"
time.sleep(1)
def destroy():
GPIO.cleanup()
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
destroy()
??