一起玩轉樹莓派(23)——DHT11溫溼度傳感器實踐

一起玩轉樹莓派(23)——DHT11溫溼度傳感器實踐

一. 引言

DHT11是一款強大的複合傳感器,支持環境溫度和溼度的測量。其本身比較簡單,但是由於其採用串行時序的方式進行數據讀寫,非常適合我們練習時序編程。本次實驗我們使用的傳感器模塊如下圖所示。

可以看到,此傳感器模塊有3個引腳,除了電源和接地引腳外,只有一個out引腳用來輸出數據和傳輸控制指令。下面我們來介紹下如何使用此傳感器模塊。

二. 關於DHT11傳感器模塊

由於DHT11傳感器元件只有一個通信引腳,因此其輸入和輸出都需要使用同一個引腳。即此引腳是一個串行的單線雙向引腳。所謂單線雙向是指其只有一條信號傳輸線,但是可以雙向通信。這有些像我們使用的對講機,一方說話時另一方只能聽。DHT11的完整使用手冊地址如下:

https://www.dfrobot.com.cn/image/data/DFR0067/DFR0067_DS_10.pdf

首先我們先來看DHT11所傳輸的信息數據的格式。根據文檔介紹,DHT11一次完整的通信將傳遞40位數據,這40位數據包含了溫度,溼度和用於校驗正確性的數據。因此,我們在讀取DHT11的數據時,要完整的讀出40位數據後再進行計算。這40位數據的具體格式爲:

[8bit的溼度整數部分數據]+[8bit的溼度小數部分數據]+[8bit的溫度整數部分數據]+[8bit的溫度小數部分數據]+8bit校驗數據

其中[8bit的溼度整數部分數據]與[8bit的溼度小數部分數據]與[8bit的溫度整數部分數據]與[8bit的溫度小數部分數據]的和結果應爲8bit的校驗數據,如果結果不等則表明此次獲取的數據出現異常,應該拋棄掉重新獲取。

從傳感器拿到的數據格式本身比較簡單,比較複雜的點在於其通信過程。整體來說,樹莓派與DHT11傳感器的通信過程分爲3個階段:

1. 樹莓派發出開始信號,之後開始等待傳感器模塊的應答。

2.傳感器模塊收到樹莓派發出的開始信號後,返回應答信號。

3.樹莓派接收到應答信號後,開始進行40位數據的接收。

整體的通信過程手冊中有提供一張示意圖,如下:

通電後,傳感器模塊的總線將始終處於空閒狀態或通信狀態中的一種狀態下。定義當空閒狀態時,總線輸入高電平。對於上面通信過程中的第1個階段,樹莓派先將總線電平拉低,且必須大於18毫秒以讓傳感器模塊檢測到此拉低的信號。之後樹莓派再將總線拉高,表示樹莓派已經發出了一次開始通信信號,1階段結束。

傳感器模塊檢測到樹莓派發起的開始信號後,此時總線電平爲被樹莓派拉高狀態。傳感器模塊通過總線發送80微秒的低電平信號,表示響應了樹莓派的開始信號,之後傳感器模塊會將總線電平再拉高80微妙,提示樹莓派準備開始接收數據,2階段結束。

階段1和階段2的更詳細示意圖如下:

3階段爲傳感器模塊發送數據,樹莓派接收數據的階段。每一位數據的發送有0和1兩種狀態,傳感器每發送50微妙的低電平信號即表示要進行1bit數據的傳輸,之後如果傳感器發送了26微秒到28微秒的高電平,則表示發送數據位0,如果發送了70微秒的高電平則表示發送數據位1。之後再進行下一位數據的發送。在實際編程操作時,我們可能不太好精準的測量高電平的時間,但是由於數據位0和數據位1的高電平時間相差很多,我們可以通過測試循環變量的計數來大致得到一個傳輸數據0時的大致循環次數和傳輸數據1時的大致循環次數,通過循環次數來判斷數據具體是0還是1。

數據位0的信號示意圖如下:

數據位1的信號示意圖如下:

需要注意,每次測量的時間間隔最好大於1秒,且上電後等待1秒穩定再進行測量。

如果沒有接觸過元件單總線時序編程,上面的文字描述,總的來說還是有些抽象,下面我們會通過代碼來實踐。

三. 連線編碼

DHT11傳感器模塊只有3個引腳,中間的out引腳我們可以選擇任意一個樹莓派額GPIO引腳來連接,這裏我們選擇物理編碼爲11的GPIO引腳。按照上面我們介紹的DHT11模塊的使用方法,編寫代碼如下:

#coding:utf-8
import RPi.GPIO as GPIO
import time
import math

# 使用物理編碼爲11的引腳做總線
P = 11

GPIO.setmode(GPIO.BOARD)

print("開始進行DHT11測量數據獲取\n")
# 等待1s後再進行邏輯
time.sleep(1)


def readData():
	print("readData")
	# 先將總線引腳設置爲輸出模式
	GPIO.setup(P, GPIO.OUT)
	# 將總線電平拉低,發出開始信號
	GPIO.output(P, GPIO.LOW)
	# 手冊要求至少保持18ms的低電平,我們這裏保持20ms
	time.sleep(0.02)
	# 拉高電平
	GPIO.output(P, GPIO.HIGH)
	# 之後將引腳設爲輸入模式,等待傳感器響應
	GPIO.setup(P, GPIO.IN)

	# 先等待80us的低電平信號
	while GPIO.input(P) == GPIO.LOW:
        continue
	# 再等待80us的高電平信號 
	while GPIO.input(P) == GPIO.HIGH:
		continue

	# 開始接收數據

	# 循環計數
	i = 0
 	# 存放二進制位數據
	data = []
	# 存放中間數據
	kdata = []
	# 每次讀取40位數據
	while i < 40:
		j = 0
		# 50us的低電平表示準備傳輸一位數據
		while GPIO.input(P) == GPIO.LOW:
			continue
		# 開始檢測高電平的時間
		while GPIO.input(P) == GPIO.HIGH:
			j+=1
			if j > 100:
                    return [False, 0, 0]
		kdata.append(j)
		i+=1

	
	print("--------臨時數據----------\n")
	print(kdata)
	print("--------臨時數據----------\n")
	
	# 開始整理數據
	i = 0
	while i < 40:
		tmp = kdata[i]
		if tmp > 7:
			data.append(1)
		else:
			data.append(0)
		i+=1
	print("--------臨時數據2----------\n")
	print(data)
	print("--------臨時數據2----------\n")
	# 解析溼度整數部分
	t1 = data[0:8]
	c1 = 0
	i = 7
	for n in t1:
		c1 += n * math.pow(2, i)
		i-=1

	# 解析溼度整數部分
	t2 = data[8:16]
	c2 = 0
	i = 7
	for n in t2:
		c2 += n * math.pow(2, i)
		i-=1

	# 解析溫度整數部分
	t3 = data[16:24]
	c3 = 0
	i = 7
	for n in t3:
		c3 += n * math.pow(2, i)
		i-=1

	# 解析溫度整數部分
	t4 = data[24:32]
	c4 = 0
	i = 7
	for n in t4:
		c4 += n * math.pow(2, i)
		i-=1

	# 解析校驗
	t5 = data[32:40]
	c5 = 0
	i = 7
	for n in t5:
		c5 += n * math.pow(2, i)
		i-=1
	
	# 進行校驗
	va = True
	print("c1:%d\n2c:%d\n3c:%d\n4c:%d\n5:%d\n"%(c1,c2,c3,c4,c5))
	if c1 + c2 + c3 +c4 == c5:
		va = True
	else:
		va = False

	return [va, "%d.%d"%(c1, c2), "%d.%d"%(c3, c4)]


while True:
	time.sleep(1)
	result = readData()
	if result[0]:
		hum = result[1]
		temp = result[2]
		print("當前環境溼度: %s %%, 當前環境溫度:%s℃\n" % (hum, temp))
	else:
		print("此次數據無效,已被丟棄\n")
	time.sleep(1)

上面代碼中有比較詳細的註釋,有些地方我們還是可以再解釋一下。首先,樹莓派發出開始指令的過程比較簡單,無需過多解釋。麻煩之處在於循環40次來獲取40位的二進制數據。在獲取數據時,我們採用循環變量來記錄高電平的時間比例,從而可以分析出傳輸的數據是0還是1。需要注意,不同的設備可能循環一次的時間並不完全相同,我們可以先測試下上面代碼中kdata變量存儲的數據,運行代碼如下圖:

可以看到,如果是傳輸數據0,循環計數基本是在3或者4。而如果傳輸的是數據1,則循環計數在11左右。代碼中我們以7爲分割,分析時,循環計數大於7時就認爲當前傳輸數據1,否則爲0。

獲取到了完整的40位二進制數據後,將其轉換爲數值進行校驗即可。最終代碼運行效果如下圖所示。

專注技術,懂的熱愛,願意分享,做個朋友

QQ:316045346

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章