1. 程式人生 > >基於樹莓派(Raspberry Pi)平臺的智能家居實現(一)----繼電器模塊,DHT11模塊

基於樹莓派(Raspberry Pi)平臺的智能家居實現(一)----繼電器模塊,DHT11模塊

Raspberry 繼電器模塊 DHT11溫濕度模塊 智能家居

前言:


??其實做這個智能家居系統我還是因為學校的畢業設計,距離上篇文章發布已經過去了20多天了,之前想著只是做一個煙霧報警,然後通過Zabbix進行報警,但是通過這20多天的設計,我發現實現報警的功能其實除了郵件,還有短信、微信、甚至電話。但是因為各種原因,比如.....錢0.0,哈哈哈,因此我計劃用企業微信進行一個報警,然後貌似通過普通微信進行一個簡單的交互(interactive),還是不錯的選擇,並且做出來的效果也很棒。
??最後想說的是:“基於樹莓派(Raspberry Pi)平臺的MQ-2煙霧報警系統以及結合Zabbix監控的實現(二)”,我本打算為這篇文章起的名字.....後來發現自己已經偏離Zabbix了,不過我後面會學到Zabbix,基於前面已經有了通過調用微信的API來進行交互操作,那麽我覺得,二次開發Zabbix來進行樹莓派的監控還是不難的吧。下面文章如果有不正確的地方,還請多指正。



一、實現內容(重要)


??前面我已經做了闡述,要做智能家居控制系統,除了實現各種報警之外,還要做到和Raspberry的交互,通過手機來控制它的輸出,和執行相應的動作,還有最重要的一點,後面會用到運動識別檢測。。。噢耶:)

1.實現目標

??下面是實現的具體目標,分三部分:交互端,報警端,攝像頭運動物體檢測報警端。

普通微信端交互控制:

  • 通過“MQ-2煙霧報警模塊”實現對家中的氣體檢測。
  • 通過“DHT11溫度檢測模塊”實現對家中的溫度測控。
  • 通過“繼電器模塊”實現對家中電器設備的開閉控制。
  • 隨時查看攝像頭所拍攝的照片


企業微信端的報警:

  • 當家中溫度出現異常,進行報警。
  • 當家中有害氣體含量異常,進行報警。
  • 當家中有繼電器控制的電器設備異常開啟或者關閉,進行報警。


家中運動物體識別檢測報警:

  • 基於OpneCV算法實現對攝像頭運動物體的檢測,識別,拍照,最後上傳到企業微信端。

2.註解

??這裏我想大家解釋一下我的計劃組成部分:

①微信端交互功能。

??通俗的講,也就是用戶通過菜單的指引,在微信端輸入輸入一系列關鍵字,然後Raspberry識別,並進行相應的動作,比如控制燈的開關啦,檢測室內溫度啦,看看攝像頭拍的什麽照片啦等等,這些都是通過調用API接口來實現。


②微信端報警功能

??報警我計劃使用的還是微信,但是這個不是普通微信,而是企業微信,也就是可以類似於純凈版的微信,QQ的TIM,它的功能大部分和公司的相關業務靠的很近,用起來很舒服,比如當家中有不明氣體產生,或者溫度濕度超過我們規定的閾值,我們都進行報警,或者當離開家的時候,忘記關閉電器開關,也會進行一個提醒,這裏用到的也是企業微信提供的API接口,其實用法是差不多的,但是總結下來。還是企業微信在調用的時候會方便一點,最起碼不用掃碼,哈哈哈哈。


③運動物體檢測。

??為什麽要加這一塊兒呢?試想一下,當家中沒有人的時候,可能會有陌生人闖入,我們這時該如何檢測呢?答案當然是:PiCamera+OpenCV。這裏簡要介紹一下,PiCamera是Raspberry官方的攝像頭,可以用來拍照,錄制視頻,一般為800萬像素的比較好,某寶或者某東都有賣的,為了能檢測出來攝像頭當前區域的物體活動跡象,我們用到了跨平臺計算機視覺庫:“OpenCV”,很強大的一個庫,支持多種語言,我在這裏就Python2寫了,因為Raspbian系統當中Python2默認是可以安裝OpenCV2,而Python3是好像不能裝的,總是失敗,想要安裝OpenCV3在Python3的話,需要自己去找網上的教程,需要源碼編譯,這裏我就不過多贅述了。通過編寫一定的算法,對圖片的每一幀進行一個比對,灰度化,二值,過濾出輪廓,然後進行統計,通過設定的閾值,來判斷這一幀是否有像素的變化,從而感知是否有物體運動,這裏會用到很多的數字圖像處理知識,希望做這一塊兒的讀者,可以先去網上搜下關於數字圖像處理的書籍,了解基本概念很重要。


  最後附上我的文件結構,不太符合Python工程標準,嘻嘻,野生程序員0.0...

技術分享圖片

  • interactive # 用戶微信交互
    > air # 煙霧報警測試目錄
    >>MQ-2_module.py
    >
    camera # PiCamera拍照錄像目錄
    > >photo.py
    >>video.py
    >>picture
    > >video
    > face # 人臉識別目錄
    >>friend.py
    >>haarcascade_frontalface_alt2.xml
    >
    relay # 繼電器模塊測試目錄
    >>RELAY.py
    > temp # 溫濕度測控目錄
    >>DHT11.py
    >
    weixin # 微信交互主文件目錄
    >>weixin_group.py

  • warning # 企業微信報警檢測
    > main.py # 主文件
    >
    Face # 運動物體報警檢測目錄
    >>conf.json
    >>motion_detection.py
    >>picture
    > Temp # 溫濕度報警檢測目錄
    >>DHT11.py
    >
    Weixin_warning # 企業微信報警調用目錄
    >>picture_send.py
    >>video_send.py
    >>wechat.py


??上述的所有點我會在後面一一進行詳細講解,並實現其功能。


二、繼電器功能實現

1. 繼電器模塊簡介


??繼電器(英文名稱:relay)是一種電控制器件,是當輸入量(激勵量)的變化達到規定要求時,在電氣輸出電路中使被控量發生預定的階躍變化的一種電器。它具有控制系統(又稱輸入回路)和被控制系統(又稱輸出回路)之間的互動關系。通常應用於自動化的控制電路中,它實際上是用小電流去控制大電流運作的一種“自動開關”。
??按照我的話說:繼電器模塊是通過Raspberry輸入高低電平到IN口,來控制繼電器的當中的電磁鐵鐵芯和銜鐵的相互作用,當給線圈通電的時候,就會產生一個磁場,使得電磁鐵鐵芯被吸引到一個端口,從而實現端口的開路或者閉路,進而控制電器的開關。

繼電器靚照:
技術分享圖片

  官方簡介:(便於後面的連線和理解原理)

>①采用松樂繼電器,單刀雙擲,一個公共端,一個常開端,一個常閉端。
②低電平吸和,高電平釋放,吸和時狀態指示燈亮起,否則是熄滅狀態。
③VCC系統電源,JD_VCC繼電器電源,5V電源
④繼電器最大輸出:直流30V/10A,交流250V/10A
⑤VCC:系統電源正極
⑥GND:系統電源負極
⑦IN1--IN2:繼電器控制端口

2. 三種工作原理介紹


??我在這裏使用了一個模塊,是松樂的SRD(T73)型號家用繼電器,這裏,分為三個端,依次是:“NO”,“COM”,“NC”,後面還有個“IN”端,用來連接樹莓派的GPIO口,根據它輸入的高低電平,來進行繼電器的控制,也就是:

>* NC —— Normal Connected ,指常閉端(接點),平常(不加電時)的狀態

  • NO —— Normal Open,指常開端(接點),平常(不加電時)的狀態
  • COM —— Common,指公共端,根據是否加電,可以與NC端或NO端接觸


  這裏有兩種模式,常開,常閉。我經過測試以後,做了一個總結:

??1. 當連接“COM”和“NC”的時候,燈常亮,也就是沒有給任何電平的時候,它就連通了,說明這個是常開模式,這個時候通過“IN”給一個高電平,或者把“IN”線拔掉,都會導致這個燈是亮的,不會受到影響,線路為通路;但當通過“IN”給一個低電平的時候,這個時候燈就滅了,但是可以看到工作模式燈亮起,也就是說,這個時候由於通電的原因,電磁鐵把單刀開關吸到了斷路的端口上,這也就說通了,當不給電或者給一個高電平的時候,會讓磁鐵沒電,不會進行吸附耦合,那就是一直接著通路了,默認有電。

??2. 當連接“COM”和“NO”的時候,燈常滅,也就是沒有給任何電平的時候,它是默認斷開的,說明這個常閉模式,這時候通過給“IN”給一個低電平,會發現燈亮了,很神奇,這是為什麽呢?在正常情況下,在樹莓派關閉,斷電時候,或者把“IN”線拔了,或者給一個高電平,都會導致燈滅;只有給到低電平的時候,才會使工作燈亮起,並且會通電,把電磁鐵把單刀開關吸到了開路的那一端,在不給低電平的時候,此時裏面的磁鐵是不會移動的。


  不過這測試的結果好像顛覆了我的世界觀。。。。。因為上面測試的結果,和前面對“常開端”和“常閉端”的定義好像正好相反,我也不知道為什麽,可能是他們把線接反了嗎?
反正就是記著他的原理,然後用法就是這麽用的就行了0.0
總結:

?? 當輸入一個低電平的時候,總會導致繼電器裏面的電磁鐵有磁性,從而把單刀開關從原始的一頭,切到了另一頭。記住這裏是給控制器的低電平哦,從而控制了繼電器高電平,進而通過電磁鐵把這個單刀吸到了有電的一方,就是這麽簡單。搞清楚哦 !

註意 :上面敘述的為什麽和網上正好相反,低電平的時候,電磁鐵帶電,並且可以使得電器電路閉合
???因為這是 “繼電器模塊 ” ,也就是結合了繼電器的電路,裏面是是帶有一個控制器的,也就是說對於用戶,這些暴露的I/O口是連接控制芯片的,然後通過芯片來控制繼電器,所以低電平是給控制器一個信號,然後讓控制器給繼電器一個高電平,那麽內部的線圈就帶電,然後產生磁場,把電磁鐵鐵芯吸到了一端。反正要是還有些迷糊的話,大家可以找找網上的關於繼電器的相關知識。


記住:給“IN”一個低電平就是使磁鐵有磁性,改變當前單刀開關的位置

???為了方便,我後面會使用第二種連線方式,也就是“常閉”模式,為了保證安全!!!

3. 繼電器連線


  開始接線,我們的目的是要通過繼電器控制家用電器,也就意味著需要把電線的兩頭接到繼電器的兩個端口,來通過控制繼電器,從而控制兩個端口是否是閉合還是斷開,先上個圖吧。
技術分享圖片

3.1 I/O口連線及解釋:

>??① 通過跳線帽把JD_VCC和VCC進行了一個連接,也就是意味著,通過最右邊的VCC,就把電源除了供給給繼電器模塊的控制器之外,也並聯給了繼電器本身一個5V的電源,省去了插兩根電源線的麻煩。
??②當然他們的地線GND,則是都需要連接在Raspberry的GND上,這是毋庸置疑的。
??③IN1和IN2,這是控制繼電器的I/O口,通過對兩個口的高低電平的輸入,來控制繼電器的斷開和閉合。
??④ 看到正面這裏,我為了試驗的真實性,在五金店買了一根帶插頭的電線,和家用四孔插座,帶插頭的電線,一端把線接在四孔插座的後面,然後在中間位置,剪開其中的一根線(雙頭插頭默認都是一根零線,一根火線,一共兩根),但別都剪短斷哈......然後把這根剪開的兩端分別接在 “公共端口COM” “常開端“NO” ,就像我前面說的,根據自己測試的結果,我的需求是:在Raspberry沒有開機,或者不給任何電平的時候,那它就是常閉的,不帶電的,只有給它一個低電平的時候,它才會亮。因此我們要接在公共端和常閉端,但是由於我也不知道這個繼電器是怎麽設置的,只有接公共端和常開端,它才能達到我們的目的,雖然很奇怪,但是先這樣把。


這裏放一個連接公共端和常開端的圖:
技術分享圖片


  註意: 由於連接的是220V的電壓,所以很具有危險性,因為閉合開關以後,繼電器模塊底部有一定的幾率帶電,所以盡量在下面墊一層紙板,用絕緣膠帶纏上,通電以後,不要觸摸,可以買一根電筆來測試連個端口是否有電。

4. 命令行測試


  這裏安排了一個簡單的測試,是為了保證正確的連線,用到了一個軟件wiringPi和上篇文章提到過的Python當中的RPi.GPIO庫。

4.1 wiringPi介紹:

  WiringPi 是應用於樹莓派平臺的 GPIO 控制庫函數,WiringPi 遵守 GUN Lv3。wiringPi 使用 C 或者 C++ 開發並且可以被其他語言包轉,例如 Python、ruby 或者 PHP 等。 wiringPi 包括一套 gpio 控制命令,使用 gpio 命令可以控制樹莓派 GPIO 管腳。用戶可以利用 gpio 命令通過 shell 腳本控制或查詢 GPIO 管腳。

4.2 wiringPi安裝:

使用 GIT 工具,通過 GIT 獲得 wiringPi 的源代碼。
git clone git://git.drogon.net/wiringPi
cd wiringPi
./build
build 腳本會幫助你編譯和安裝 wiringPi。

4.3 命令行測試:

    ① # gpio readall     


  讀取當前Raspberry的GPIO引腳情況。在這個地方可以查看40個的BCM編碼規則;wPi編碼規則;Name:引腳名稱(有些I/O兼備多種功能的);Mode:模式,此時這個引腳是輸入模式還是輸出模式(默認開機的時候是輸入模式),V:此時引腳的電平:“1”為高電平,“0”為低電平(大部分默認開機是低電平),可以看到圖中方框圈住的是引腳,它是此時是輸入模式並且是高電平。
附圖:
技術分享圖片

    ② # gpio mode 11 out

  我采用了wPi編碼規則,根據剛剛我上面的連線,我選取了IN2引腳,通過杜邦線把它接在了Raspberry的26號引腳上,就是中間的“Physical”物理引腳命名規則的26號引腳,而26號引腳對應的是wPi命名規則的“11”號引腳,然後用上面的命令設置該引腳為輸出模式“OUT”,這樣的話,才可以輸出高低電平;相反要接收並且判斷連在某個引腳上的電平是高電平還是低電平,那麽就設置為輸入模式“IN”,用來接收。這個地方大家一定要分清。
附圖:
技術分享圖片

    ③ # gpio write  11 0

  向wPi命名規則的11號引腳輸出一個低電平,然後就會發看到“V由1到0”,並且燈也亮了,狀態燈也亮了,還有刀片的切換的聲音,說明燈光打開成功啦。

附圖:
技術分享圖片


狀態燈圖:
技術分享圖片

    ④ # gpio write 11 1

  向wPi命名規則的11號引腳輸出一個高電平,然後就會發看到“V由0到1”,並且插在插座上的燈滅了,同時狀態燈也滅了,同樣刀片有切換的聲音,說明燈光關閉成功啦。

附圖:
技術分享圖片

    ⑤ # gpio read 11

  可以讀取剛剛定義好命名規則的引腳的狀態,當然就是“0”或者“1”啦。
   附圖:
技術分享圖片


  當你上面的都做出來的時候,那麽恭喜你,成功地通過命令行的方式控制了連接在繼電器模塊上IN2引腳,到Raspberry的GPIO口的高低電平,進而控制了燈的開關,好像是不太難吧。。。只要按照我的連線,大家肯定可以做出來,並且可以多幾次的輸出高低電平,來感受繼電器的工作原理和工作方式,並且熟悉這樣命令行界面控制GPIO口的方式,很方便,很快可以的到一些結論,並且前面的對MQ-煙霧檢測模塊的測試,也可以通過上面的 gpio read 11 的命令來查看引腳狀態。

> 註意:
上面對於一個引腳的輸入高低電平,獲取高低電平狀態,這一切的一切的都需要你必須在提前定義好了引腳的命名規則,是wPi還是BCM。不然是無法成功的!!!

5. Python代碼測試


  還是老樣子,我使用的是Python3,通過調用RPo.GPIO庫來實現在腳本當中,對GPIO的操作。

5.1 程序段一

#!/usr/bin/env python3
import RPi.GPIO as GPIO
import time

relay = 40      # 采用BOARD編碼,40號引腳,來控制繼電器
buzzer = 32   # 采用BOARD編碼,32號引腳,來控制蜂鳴器
GPIO.setmode(GPIO.BOARD)  # 聲明BOARD編碼規則
GPIO.setwarnings(False)   
GPIO.setup(relay, GPIO.OUT)     #  設置繼電器的引腳為輸出模式
GPIO.setup(buzzer, GPIO.OUT)  #  設置蜂鳴器的引腳為輸出模式

  ①對GPIO庫進行一個引用,然後先定義引腳號,並且定義BOARD編碼規則,這裏需要看著前面的GPIO對應表,不要寫錯了,需要註意是當我們每次去執行完腳本以後,GPIO引腳有可能沒有關閉調用,或者之前引腳在設定之前就是輸出模式,要是再次定義它為輸出模式,就會產生一個警告,很煩人,那麽如何避免這個問題呢?就是中間的那條命令 GPIO.setwarnings(False) ,需要大家特別註意哦!

5.2 程序段二

j = 0
while j<5:  
   GPIO.output(relay, GPIO.LOW)
   print ("燈亮了")
   GPIO.output(buzzer, GPIO.LOW)
   print ("蜂鳴器鳴響")

   time.sleep(3)  

   GPIO.output(relay, GPIO.HIGH)
   print ("燈關閉")
   GPIO.output(buzzer, GPIO.HIGH)
   print ("靜默")

   time.sleep(3)

  ②這裏進行了一個5次的程序執行,就拿出我們前面的結論:控制繼電器,當給它一個低電平的時候,繼電器模塊的控制器則給它一個高電平,繼電器內部線圈帶電,產生磁場,導致單刀吸附到閉合那一端,這樣上面我們接線的兩個端口“COM”和“NO”就是通路了,就好像他倆沒有被剪開一樣,這個時候,燈就亮了,然後我設置了一個低電平給蜂鳴器,蜂鳴器也響了;後面則是給繼電器IN2一個高電平,然後燈就關閉了,同時也給蜂鳴器一個高電平,蜂鳴器靜默。
  相信大家也看到了,我進行了兩次的睡眠 “time.sleep(3)” ,這是因為當進行了電平轉換以後,一個是我們需要檢驗結果,所以有個狀態駐留時間,尤其是最後的那個睡眠,記得必須加上,否則看不到效果,因為下次循環又轉換為低電平,在這個期間,需要時間去讓大家看出效果,就是燈是一直滅著的,同時也避免繼電器瞬間切換產生的異常,要是大家感覺有些繞,可以自己進行一個實驗,嘗試去掉睡眠,這樣也有助於你理解。

>   最後的效果就是:燈亮起三秒,蜂鳴器響起;燈滅三秒,蜂鳴器靜默;如此往復5次。
  設計這個程序的效果就是讓大家能熟悉繼電器的工作原理,以及Raspberry如何調用,博主可謂用心良苦啊0.0



三、溫度傳感器功能實現


  溫度傳感我覺得還是整個項目裏比較有分量的,也是比較難的部分,這是為什麽呢?其實大家可以在網上搜到很多關於溫度傳感器DHT11在Raspberry上的實現,有用Python寫的,有用C寫的,各種方法不盡相同,但是絕大部分都不夠詳細,比如程序當中有些語句 “while GPIO.input(channel_point) == GPIO.LOW:” 。這個就需要去結合DHT11模塊本身的工作模式去理解,就會好很多,後面我會逐句一一進行講解。

1. DHT11簡介

  • 可以檢測周圍環境的濕度和溫度
  • 濕度測量範圍:20%-95%(0 度-50 度範圍)濕度測量誤差:+-5%
  • 溫度測量範圍:0 度-50 度 溫度測量誤差:+-2 度
  • 工作電壓 3.3V-5V
  • VCC 外接 3.3V-5V
  • GND 外接 GND
  • DATA 小板開關數字量輸出接口,可接I/O口


附一張帥氣的自拍:
技術分享圖片

2. DHT11接線

這裏連線需要註意的點是:
   經過測試,必須要在DHT11模塊電源和DATA數字接口當中並聯一個電阻,否則測量出來的值非常的不準確,很多網上的資料沒有說並聯電阻這個事情,導致我程序寫完,總是測不出溫度的數值,還以為是程序有問題,所以走了很多的彎路,望大家千萬註意。


下面結合圖片進行連線講解:

①原理圖:
技術分享圖片
   上面這張圖是設計模塊的使用說明電路圖,很明顯,在VCC和DATA需要並聯一個電阻,貌似是需要做一個上拉電阻,來增加DATA的輸出能力,並且圖中是要求並聯4K左右的電阻,但是實際測試得出結論,只要有2K就夠了。


②虛擬連線圖:
技術分享圖片
   紅色的是電源線,連接在Raspberry的3.3V電源上,藍色的是數據口DATA,黑色的是GND,就是按照上面圖並聯的電阻,不理解的多看看電路圖。


③實際效果圖:
技術分享圖片
   由於手頭只有1K的電阻,所以簡單的進行了一個串聯,有些亂,但是這樣連線,再跑程序就完全沒有問題0.0。

3. 驅動程序


   程序實現的過程還是比較簡單的,但是需要結合DHT11的模塊的說明來進行講解,這樣的解釋程序的方式,相信大家讀完會才可以更好的理解,希望仔細閱讀這一部分。

註意:
   把引腳設置為輸出“OUT”,意味著需要Raspberry輸出高低電平信號給data數據口。
   把引腳設置為輸入“IN”,意味著Raspberry準備接收data數據口給它引腳的高低電平信號


   下面是產品公司對DHT11整個工作流程的時序圖的概括,這其中包括了初始化操作。

技術分享圖片

3.1 DHT11初始化(步驟一)

   官方原文:DHT11 上電後(DHT11 上電後要等待 1S 以越過不穩定狀態在此期間不能發送任何指令),測試環境溫濕度數據,並記錄數據,同時 DHT11 的 DATA 數據線由上拉電阻拉高一直保持高電平;此時 DHT11 的DATA 引腳處於輸入狀態,時刻檢測外部信號。

#!/usr/bin/env python3

import RPi.GPIO as GPIO
import time

def dht11(channel):
    channel_point = channel
    data = [ ]

    GPIO.setmode(GPIO.BOARD) # 設置編碼格式
    time.sleep(1)
  • 首先進行了庫的調用,為了在後面方便調用整個文件,並作為一個模塊導入其他文件,所以這裏定義成了函數。
  • “channel_point”是函數輸入的參數,作為引腳變量。
  • “data[ ]” 是一個空字典,用來存儲後面data引腳發來的40位數據,我會在後面細講。
  • 這裏我還是使用BOARD編碼命名規則進行定義。
  • “time.sleep(1)” 的目的就是程序開頭我敘述的那樣,當剛剛通電,DHT11模塊需要進行一個初始化操作,不能發送任何指令,所以要等待一秒

3.2 DHT11初始化(步驟二)

   官方原文:微處理器的 I/O 設置為輸出同時輸出低電平,且低電平保持時間不能小於 18ms,然後微處理器的 I/O設置為輸入狀態,由於上拉電阻,微處理器的 I/O 即 DHT11 的 DATA 數據線也隨之變高,等待DHT11 作出回答信號。

        GPIO.setup(channel_point, GPIO.OUT)    # 設置為輸出
        GPIO.output(channel_point, GPIO.LOW)  # 輸出一個低電平
        time.sleep(0.02)   # 睡眠0.02秒
        GPIO.output(channel_point, GPIO.HIGH)  # 輸出一個高電平
        GPIO.setup(channel_point, GPIO.IN)         # 設置GPIO引腳為輸入


   由於步驟二要求的是需要微處理器,也就是我們用的Raspberry,輸出一個低電平,並且保持18ms以上,然後設置為輸入模式,再把電平拉高,進行一個等待。

  • 為了達到上面的目的,首先設置GPIO引腳為輸出模式,然後給一個低電平。
  • 這裏為什麽睡眠 “0.02s” 呢?前面已經講到:必須要有不小於20ms的低電平,這是初始化的必要操作。
  • 然後輸入一個高電平給data,由於上拉電阻的原因,導致data現在被拉高了, 但要是GPIO這裏不拉高的話,就會有電流,因為前面還是輸出給data低電平嘛,所以這裏 保持電平的高低一致。。。
  • 最後使得引腳為輸入模式,準備接收來自data的信號。

3.3 DHT11初始化(步驟三)

   官方原文:DHT11 的 DATA 引腳檢測到外部信號有低電平時,等待外部信號低電平結束,延遲後 DHT11 的 DATA引腳處於輸出狀態,輸出 80 微秒的低電平作為應答信號,緊接著輸出 80 微秒的高電平通知外設準備接收數據,微處理器的 I/O 此時處於輸入狀態,檢測到 I/O 有低電平(DHT11 回應信號)後,等待 80 微秒
的高電平後的數據接收。

    while GPIO.input(channel_point) == GPIO.LOW: 
        continue
    while GPIO.input(channel_point) == GPIO.HIGH: 
        continue

這兩句while語句還是比較難理解的,需要結合上面的官方步驟來看。

  • 第 一個while語句: 這裏就是接收GPIO的INPUT輸入的低電平,這是data端發過來的,作為應答信號,並且是80微秒的低電平,由於實際生產環境當中,80微秒不一定準確, 因此,這裏用了while循環,當樹莓派接收到的GPIO為低電平的時候,就一直在while循環,並且是跳過下面的程序的,直到接受的GPIO口為高電平了,這裏while循環後面的判斷條件就為假了,這時候就不循環了。然後就往下走
  • 第二個while語句 : 當上面“80微秒”低電平結束以後,又會發送一個“80微秒”的高電平給樹莓派的GPIO,來告訴樹莓派,要準備發送數據了,準備接受了!!!

3.4 DHT11采集數據

   官方原文:由 DHT11 的 DATA 引腳輸出 40 位數據,微處理器根據 I/O 電平的變化接收 40 位數據,位數據“0”的格式為: 50 微秒的低電平和 26-28 微秒的高電平,位數據“1”的格式為: 50 微秒的低電平加 70
微秒的高電平。
位數據“0”、“1”的圖兩張:
技術分享圖片
技術分享圖片


   用我自己的話概括就是:經過上面的初始化以後,data開始發送數據,是40位的高低電平,也就是40位的“0”和“1”,然後開始發送數據了,位數據“0”的格式為:50微秒的低電平和26-28微秒的高電平,位數據“1”的格式為:50微秒的低電平和70微秒的高電平。

   其實這裏就可以看出,只需要判斷後面的高電平是輸入給GPIO多少微秒,就可以來判斷是“0”還是“1”,就是一個時間長短的判斷而已,認真理解,這對於後面的程序理解有很大的幫助。

    data_number = 0                        # 設置計數器
    while data_number < 40:
                high_time = 0                  # 統計 “while高電平循環”次數
                while GPIO.input(channel_point) == GPIO.LOW:      # 接收一個50微秒的低電平
                            continue
                 while GPIO.input(channel_point) == GPIO.HIGH:  # 開始接收高電平
                             high_time += 1                                             # 開始對上面的while的循環次數進行計數
                             if high_time> 100:                                        # 當循環次數超過100,退出本次循環
                                      break

                 if high_time < 8:                                                       # 對前面的while循環的次數進行判斷
                             data.append(0)                                             # 如果小於8追加位數據“0”到字典當中
                  else:  
                             data.append(1)                                             # 大於8的追加位數據“1”到字典當中
                  data_number += 1                                                   # data_number自加1

    print("Modular is working.")
    print(data)
  • data_number 的作用就是計數40次,也就是寫入數據40次,因為DHT11就是傳輸40個二進制數,五個字節,需要特別註意,用於下面的while循環判斷。
  • 然後Raspberry的引腳開始接收一個50微秒的低電平,while檢測只要是低電平就跳過,不執行底下的程序,直到高電平的到來,這個while條件為假,它就退出了,並且接著自動執行下面的同級程序。這是因為我前面說的,我們只統計後面高電平輸出的時長,低電平的不管,因為高低電平都是50ms,所以執行下面的程序沒有意義。
  • 開始接收高電平,這裏通過高電平的輸出微秒的不同,來判斷這整個輸入的是“0”還是“1”,一般情況下“0”是高電平輸出的時間為26-30微秒,如果輸出的是“1”,那麽輸出高電平的時間為70微秒,也就是通過輸出高電平的時長來判斷此時輸入數據是“0”還是“1”。
       這裏做一個計數,意思是這個 while循環,執行一次需要“4微秒”,那麽也就是說:例如在輸出一個“0”的時候,需要輸出“28微秒”的高電平,而while循環的執行的邏輯判斷為後面只要是一直輸入的高電平,那麽這個while循環就一直循環,不往下走,直到這“28微秒”的高電平輸出完了,while循環判斷data引腳是低電平了,那麽才執行while循環下面的指令,但這將近 “28微秒”的高電平,由於while循環本身執行也需要時間,也就是“k”會計數這個while循環在這次的高電平輸出,共循環了幾次,依照前面給出的時間來算, 當輸入的是“0”的時候,高電平 輸入“28微秒”,while要循環7次或者8次,才會循環到這次高電平輸入結束。 同樣的,如果輸入的是“1”,那麽就是“70微秒”,也就是說,這次的while要循環17次以上,才會循環到這次高電平輸入結束,也就是“k”為17,最後其實就是判斷“k”的次數,來判斷data到底是輸入的“0”還是“1” ,這裏註意讀者要認真理解。
       當出現意外,也就是高電平循環時間過於長,導致while陷入了死循環,這樣就需要 if 判斷,當“k>100”,其實也就是while循環了100次以上、高電平輸出了 0.4s以上,那麽說明這個數據肯定有問題了,因此需要退出這次循環,並且數據作廢。
  • 最後的 if high_time < 8: 的判斷,其實就是上面說的,根據while循環的次數來判斷,每次發送來的數據,到底是“0”還是“1”,小於8那麽肯定說明接收的是位數據“0”,反之肯定是1啦,要是這裏想不通,就多看看中間那部分對“while”循環次數的技術的原因。

       上面的程序可以說是整個程序的核心部分,通過前面官方文檔中data引腳輸出位數據的特點,寫出的判斷數據的程序,可以說是很厲害了。

3.5 DHT11數據計算

   前面通過對while循環次數的計算得出了data引腳輸出的位數據是“0”還是“1”,並且全部追加到字典當中,下面開始對字典當中的值進行取出和計算。

   官方文檔:數據格式:8bit 濕度整數數據 + 8bit 濕度小數數據+8bit 溫度整數數據 + 8bit 溫度小數數據+8bit 校驗位。共40位,其中校驗位是為了判斷前面獲取的溫度和濕度是否數據由錯誤。

對於這個40位的“0”和“1”,我們如何計算呢?下面給出了一個示例:

接收到的 40 位數據為:
0011 0101 0000 0000 0001 1000 0000 0000 0100 1101
濕度高 8 位 濕度低 8 位 溫度高 8 位 溫度低 8 位 校驗位
計算:
0011 0101+0000 0000+0001 1000+0000 0000= 0100 1101
接收數據正確:
濕度:0011 0101=35H=53%RH
溫度:0001 1000=18H=24℃


   上面用到的知識基本上就是2進制轉換為10進制的操作,這裏有個公式就是:就是2的次方乘以每個對應的0或者1,比如上面的溫度的計算,“18H”就是先從二進制轉換為16進制,24則是10進制;2的四次方 + 2的三次方=24,進制方面的知識可以去百度,但是必須要搞懂,因為下面的程序就是基於這個公式進行進制轉換的。

 # 這裏進行一個分片,一共40位的列表,先取出來前八個
    hum_bit = data[0:8]                    # 濕度高八位,其為整數位
    hum_decimal_bit = data[8:16]    # 濕度低八位,其為小數位
    temp_bit = data[16:24]                # 溫度高八位,其為整數位
    temp_decimal_bit = data[24:32]  # 溫度低八位,其為小數位
    check_bit = data[32:40]               # 校驗位

# 溫濕度的初始值
    hum = 0
    hum_decimal = 0
    tem = 0
    temp_decimal = 0
    check = 0

# 遍歷字典當中的數據
    for i in range(8):
        hum += hum_bit[i] * 2 ** (7 - i)
        hum_decimal += hum_decimal_bit[i] * 2 ** (7 - i)
        tem += temp_bit[i] * 2 ** (7 - i)
        temp_decimal += temp_decimal_bit[i] * 2 ** (7 - i)
        check += check_bit[i] * 2 ** (7 - i)

   對於上面的遍歷的公式:比如第六位的數字“1”,那是就用“1”去乘以2的5次方,因為它是從0開始的,所以到第六位就是“5”,也因此,後面算,也就是要減一位,也就有了上面的式子,認真理解。
最後就算出來10進制的數據了,一共5個數據。

3.6 DHT11數據整合判斷

   這塊兒程序是進行邏輯判斷,如果有前四個數據加起來的 sum 的值不等於 check 校驗位,那麽說明數據有誤,如果相同,說明數據是正常的,後面進行了數據的打印和整合。

    sum = hum + hum_decimal + tem+ temp_decimal

    info_dht11 = ‘‘‘ 溫度:{0}.{1}°C  濕度:{2}.{3}‘‘‘.format(tem,temp_decimal,hum,hum_decimal )
    print(info_dht11)
    return check,sum,info_dht11

if __name__ == ‘__main__‘:
    dht11(38)
    dht11(29)


   由於這個模塊我是打算在後面把它作為一個微信交互程序調用的模塊的,所以我的寫法可能和前面敘述的不一樣,我在這裏說明一下,尤其是和校驗位的比較,我放在了微信交互程序當中,為了把參數傳到另一個文件的函數當中,我就運用了Python當中最偉大的發明 return ----一個可以返回任何值的關鍵字,我把這三個參數作為返回值傳到微信交互函數當中,進行邏輯判斷,並且溫濕度的信息也一並傳過去了。

註意:
為了調試:我加了一個“ if name == ‘main‘: ”,對函數進行調用,並且輸入一個參數,這是兩個DHT11溫濕度模塊的data引腳連接Raspberry的引腳,而輸入的參數就是引腳編號(BOARD命名規則)。



四、總結


 上面講的只是用戶微信需要的兩個功能模塊;後面我就開始講Raspberry對PiCamera的調用,拍照,錄像;對發來的照片進行簡單的人臉識別;最後通過微信交互主程序對前面所有的功能進行統一調用,就完成了交互的全部功能。

   企業微信的報警系統,還在不斷的完善,但是已經基本實現了: 溫濕度異常的報警,煙霧模塊檢測到異常的報警;繼電器控制的電器開關異常開路或者閉路;通過PiCamera對監測區域內的運動物體檢測並報警







   我會把上面所有實現的方法在後續寫出來,就看這篇文章和下篇文章有多少人看了0.0....

基於樹莓派(Raspberry Pi)平臺的智能家居實現(一)----繼電器模塊,DHT11模塊