目錄
1. 簡介
1.1 認識DHT22:一種溫濕度感測器
1.2 您將要學到的內容
2. 將您的Raspberry Pi與DHT22感測器連接
2.1 DHT22:基本電路
2.1.1 BOM
2.1.2 啟動!
2.2 DHT22機房環境控制器
2.2.1 BOM
2.2.2 啟動!
能夠在任意環境中輕鬆感知環境濕度的能力非常重要,因為濕度不僅會影響人的舒適度,還會影響人類機體的運作。我們在本文中將要使用的雙模感測器非常適用於創客項目,例如改善HVAC、氣象站和物聯網恒溫器,尤其是與僅在Raspbian上可用的大量高品質套裝軟體相結合之後。您可以在Pi(或Linux終端)上試試這個:
1 2 3 |
wget \ http://archive.raspbian.org/raspbian/dists/stable/main/binary-armhf/Packages.xz \ -O - 2>/dev/null | xz -dfc | grep -c '^Package: ' \ | cut -d ' ' -f 2 |
等待其運行完成。它將輸出您可以使用的套裝軟體數量。在撰寫本文時,該存儲庫中有61.487個包。這個數量每天都在增加。
無論您需要什麼功能,應該都可以通過這些套裝軟體來實現。您只需要提供感知的環境資料,本文第二部分中的示例將會告訴您如何獲取這些資料。
相對濕度(RH)的概念在維基百科中有很詳盡的解釋。請記住,相對濕度和實際濕度是兩種不同的東西,因為相對濕度取決於溫度。
我們普遍感興趣的是濕度對於人類和電子設備的閾值。如果您在25C/77F左右的環境溫度下運動,那麼會在35-40% RH開始感到不適。您的電子設備,尤其是電腦系統,在45-55% RH,溫度在20C/68F至 24C/75F之間的環境中更靈敏,且性能最佳。如果RH太低,ESD就會成為問題。如果RH太高,有局部冷凝的風險。
在冷卻理論中,有一個簡單的事實經常被忽視,即水分子是完美的小熱量桶,風冷系統在45-55% RH環境中的冷卻效果會比在20% RH環境中好得多。濕度對此有所幫助。很多人沒有發現這一點,而您現在已經獲悉這個小技巧了。
瞭解了這些內容,現在我們繼續討論硬體部分。
該使用什麼硬體?當然,SHT85濕度感測器性能很好,防水等級為IP67,誤差範圍僅為±1.5% RH,但我想我們可以選擇濕度感測器誤差範圍為±2-5% RH的設備。
DHT22有一個板載模數轉換器,因此濕度感測器和熱敏電阻的信號清晰明瞭。如果沒有該功能,校驗和的讀取會讓您十分痛苦。溫度感應只有±0.5C的誤差,對創客來說性能已經算非常好了。
五年前我買了6個,每個都性能出色,即使是在戶外(雖然遮罩了來自陽光、雨水等的紫外線)。DHT22是單匯流排,既不是I2C也不是SPI,雖然電壓範圍為3.3至6伏,但是絕不能用大於3.3V的電壓供電,因為這會導致其發熱,並感應出錯誤的溫度資料。過高的局部溫度會蒸發水分,因此局部濕度也會下降。這一點是完全可以避免的:直接從Raspberry Pi的3V3引腳獲取3.3V電壓,該引腳的數字為1。
在沒有運行時的電流消耗非常低(約40uA),因此不需要任何節能功能,但如果您想要設置該功能,比如在MCU睡眠狀態期間將DHT22關閉,那麼在再次想要讀取資料時,需要大概1秒鐘的喚醒時間。當開始對周圍環境進行測量時,DHT22消耗1.5-2.5mA的電流,因此電流量不會達到使用3V3引腳時建議的最大電流量50mA。
最小輪詢間隔被定義為兩秒,不過實際並不是如此。我可以以大約350毫秒的間隔進行輪詢,大約10秒後會出現升溫問題—但是如果您出於某種原因需要快速讀取10次數據(取中位數?),那麼在3.5秒內就可以完成,非常好。
引腳從左到右分別是1:VCC(3V3),2:SIGNAL,3:NC(未連接),4:GND。您還需要一個從引腳2到引腳1的10kΩ上拉電阻。
當且僅當您遇到抖動(通常發生在長線纜電路上)狀況時,需要在VCC和GND之間添加一個100nF電容。
學習完本文內容後,您將能夠輕鬆感知相對溫度和濕度。我添加了一些輔助函數,使您無需穀歌工具就可以將完成“攝氏度”和“華氏度”之間的轉換。每次都手動轉換會比較麻煩。為了您的方便,我們添加兩個小的輔助函數:
1 2 3 4 5 6 7 8 9 |
# Celsius to fahrenheit: F = ( C * 1.8 ) + 32 def celsius2fahrenheit( _celsius ): _fahrenheit = ( "%.2f" % (( _celsius * 1.8 ) + 32) ) return float( _fahrenheit ) # Fahrenheit to celsius: C = ( F - 32 ) * 5/9 def fahrenheit2celsius( _fahrenheit ): _celsius = ( "%.2f" % (( _fahrenheit - 32 ) * 5/9 )) return float( _celsius ) |
在第二部分的dht22_simple.py和dht22_actionable.py中也有這兩個函數。
在我們研究DHT22的過程中,將會深入探索“DHT22機房環境控制器”或DCREC的構建和操作,該器件能夠對感測器資料進行回應。您可以將dht22_actionable.py作為濕度專案的範本(基於DHT22),如果您具備了硬體和安裝技能,就可以完成幾乎所有的工作了。閱讀完python腳本後,您也將會掌握GPIO輸出控制。
DHT22非常易於使用。此處無需處理I2C匯流排,它是I/O的一個資料引腳,是一種半雙工匯流排,也許您對這個術語更熟悉。
您可以從技術規格書獲取有關脈衝長度、間隔等資訊,但如果您想馬上開始,請首先按照此Raspberry Pi設置指南確保您的Pi已準備就緒。
準備好後,將下麵的腳本複製粘貼到您的Raspberry Pi GUI編輯器中(聽說Pluma很好用),並將檔保存為“rpi_prepare.sh”。
[ begin rpi_prepare.sh ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#! /usr/bin/env bash set -eu -o pipefail DEBIAN_FRONTEND="noninteractive" DEBIAN_PRIORITY="critical" DEBCONF_NOWARNINGS="yes" export DEBIAN_FRONTEND DEBIAN_PRIORITY DEBCONF_NOWARNINGS _pkg_list="pigpio wiringpi python-rpi.gpio python3-rpi.gpio rpi.gpio-common git python-gpiozero python-gpiozero-doc python3-gpiozero python-setuptools-git python3-setuptools-git python3-dev python3-pip" # Upgrade system and installed packages - uncomment where # relevant sudo apt update || echo failed to update index list #sudo dpkg --configure -a || echo failed to fix interrupted \ upgrades #sudo apt --fix-broken --fix-missing install || echo failed \ to fix conflicts #sudo apt -y --allow-downgrades --fix-broken --fix-missing \ #dist-upgrade # Install $_pkg_list sudo apt update sudo apt-get -y install $_pkg_list # Make 'pip3' bigly fresh? Yes. sudo python3 -m pip --upgrade pip setuptools wheel # Get Adafruit_DHT Python library sudo pip3 install Adafruit_DHT read -p "[?] Reboot? y/N: " _foo if [ X"$_foo" = X"y" -o X"$_foo" = X"Y" ] then echo "[!] Rebooting in 5 seconds, CTRL+C to abort ..." for i in $( seq 1 5 ) ; do echo -n . ; sleep 1 ; done ; echo sudo reboot fi |
[ end rpi_prepare.sh ]
該腳本用於安裝和更新Python3的“pip3”程式,以及安裝一些有用的GPIO軟體。將其複製到Pi後,使用以下命令運行:
1 |
bash rpi_prepare.sh |
Raspberry Pi 4 | https://www.newark.com/raspberry-pi/rpi4-modbp-4gb/raspberry-pi-4-model-b-4gb-rohs/dp/02AH3164 |
DHT22 感測器 | https://www.newark.com/mcm/83-17985/dht22-temp-humidity-sensor/dp/32AC9951 |
10kΩ 電阻 | https://www.newark.com/multicomp-pro/mccfr0w4j0103a50/carbon-film-resistor-10kohm-250mw/dp/58K5002 |
杜邦電線 | https://www.newark.com/adafruit/824/wire-gauge-28awg/dp/88W2794 |
麵包板 | https://www.newark.com/mcm/21-19082/breadboardjumper-kit-with-binding/dp/79X3995 |
將它們全部連接起來,這一步很簡單,請按照以下圖示進行連接。
首先,將DHT22放在麵包板上,並在引腳1和引腳2之間添加10kΩ上拉電阻。然後將BOARD1/3V3連接到麵包板上的紅色導軌,BOARD6/GND連接到黑色導軌,將BCM24/BOARD18連接到DHT22上的引腳2。現在,用一根導線從紅色導軌連接到DHT22的引腳1,用另一根導線從黑色導軌連接到引腳4。然後將以下腳本複製粘貼到您的Pi終端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#! /usr/bin/env python3 # Demonstrate reading DHT22 sensor using the # Adafruit_DHT library # DHT22 pinout (left to right): # 1: VCC(3.3-6V) # 2: SIGNAL # 3: UNUSED # 4: GND # Notes: # - 10kOhm pull-up resistor from SIG to VCC. # - Use 3V3 for VCC, or the DHT22 will heat up. # - Indentation: 2 whitespaces per level, no tabs. import Adafruit_DHT from time import sleep p=print # Alias # Note: Use >=2000ms polling intervals _poll_interval = 2 # Seconds _dht_pin = 24 # BCM24/BOARD18 _dht = Adafruit_DHT.DHT22 def celsius2fahrenheit( _celsius ): _fahrenheit = ( "%.1f" % (( _celsius * 1.8 ) + 32) ) return float( _fahrenheit ) def fahrenheit2celsius( _fahrenheit ): _celsius = ( "%.1f" % (( _fahrenheit - 32 ) * 5/9 )) return float( _celsius ) if __name__ == '__main__': while True: ( _humidity, _celsius ) = Adafruit_DHT.read_retry( _dht, _dht_pin ) p( "Humidity => %.1f%% RH" % _humidity ) p( "Temperature => %.2fF" % celsius2fahrenheit( _celsius ), end='/' ) p( "%.2fC" % _celsius ) sleep( _poll_interval ) |
[ end dht22_simple.py ]
輸出應如下所示。如果沒有輸出任何內容,您可能遇到了運行超時的問題。這種情況有時候會發生,但是是不應該會發生的。按下CTRL+C中斷程式,並檢查所有連接是否正確。
在截圖的執行過程中,我將熱風槍的噴嘴輕輕靠近DHT22,同時用紅外溫度計測量DHT22。這兩個讀數可以彼此驗證,以保證實驗的嚴謹性。
現在,我們將做一些比僅僅通過濕度感測器和熱敏電阻感知環境更有趣的事情—製作DHT22機房環境控制器。在閱讀下麵的dht22_actionable.py之前,需要對其操作進行簡短的解釋。我們設置兩個Raspberry Pi GPIO引腳作為輸出(BCM25/BOARD22和BCM23/BOARD16),建立與DHT22感測器的連接,然後我們迴圈幾個條件陳述式來檢查所處環境是否滿足公認的“適於計算的最佳濕度和溫度條件”。
每當濕度或溫度超出範圍時,_humidity_led或_temperature_led都會亮起。但它也可以用於驅動電路,例如IRLZ24N MOSFET或繼電器驅動電路。您可以利用自己現有的設備來實現所有這些功能。
準備好所有的元器件,如果有缺少的東西,請訪問下文BOM中的連接。
如下圖所示完成所有連接。保留上次Raspberry Pi GPIO BCM25/BOARD22和BCM23/BOARD16的引腳連接,3V3/BOARD1和GND/BOARD6的連接和上次相同。在您的Pi準備好運行程式之前不要給電路通電,在此之前仔細檢查所有連接。確認沒有任何問題後,通電並執行下文中的dht22_actionable.py。
1 |
python3 dht22_actionable.py |
[ begin dht22_actionable.py ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
#! /usr/bin/env python3 # Install prerequisite packages & Adafruit_DHT library """ #! /bin/sh _pkg_list='python3-setuptools python3-pip python3-dev python3-rpi.gpio' sudo apt-get -y install $_pkg_list sudo python3 -m pip --upgrade pip setuptools wheel sudo pip3 install Adafruit_DHT """ # # Ensure operating conditions in a # datacenter (your basement) are # within SAFE OPERATING HUMIDITY- AND # TEMPERATURE THRESHOLDS FOR OPTIMAL # COMPUTING CONDITIONS. # # Will fire BCM25/BOARD22 if humidity is # out of bounds, and BCM23/BOARD16 if # temperature is out of bounds. # # Uses RPi.GPIO Adafruit_DHT library, # tested on Raspbian, Dec. 2019 # # DHT22 pinout (left to right): # 1: VCC(3.3-6V) # 2: SIGNAL # 3: UNUSED # 4: GND # Notes: # - 10kOhm pull-up resistor from SIG to VCC. # - 330ohm resistors in series with RPi # GPIO pins and ROHM SLR343BC4TT32 # 3mm LEDs. # - Use 3V3 for VCC, or the DHT22 will # heat up. # - Indentation: 2 whitespaces per level, no # tabs. import Adafruit_DHT from time import sleep import RPi.GPIO as GPIO import atexit GPIO.setwarnings( True ) # Use BCM pin numbering instead of BOARD GPIO.setmode( GPIO.BCM ) _humidity_led = 25 # BCM25/BOARD22 _humidity_lower_threshold = 45.0 _humidity_upper_threshold = 55.0 _temperature_led = 23 # BCM23/BOARD16 _temperature_lower_threshold = 20.0 # 20C/68F _temperature_upper_threshold = 24.0 # 24C/75F _poll_interval = 2 # Use intervals >=2secs _dht_pin = 24 # BCM24/BOARD18 _dht = Adafruit_DHT.DHT22 _debug = True p=print # Alias if _debug: p( "[!] Setting up pin BCM_%i as OUTPUT for humidity LED ..." % _humidity_led ) p( "[!] Setting up pin BCM_%i as OUTPUT for temperature LED ..." % _temperature_led ) GPIO.setup( _humidity_led, GPIO.OUT ) GPIO.setup( _temperature_led, GPIO.OUT ) def exit_cleanly(): print( "[!] Cleaning up and exiting ..." ) GPIO.setwarnings( False ) GPIO.cleanup() exit() def celsius2fahrenheit( _celsius ): _fahrenheit = ( "%.1f" % (( _celsius * 1.8 ) + 32) ) return float( _fahrenheit ) def fahrenheit2celsius( _fahrenheit ): _celsius = ( "%.1f" % (( _fahrenheit - 32 ) * 5/9 )) return float( _celsius ) # Call exit_cleanly on normal exit and CTRL+C/KeyboardInterrupt/foo atexit.register( exit_cleanly ) if __name__ == '__main__': while True: ( _humidity, _celsius ) = Adafruit_DHT.read_retry( _dht, _dht_pin ) if _debug: p( "[+] Humidity => %.1f%% RH" % _humidity ) p( "[+] Temperature => %.1fC" % _celsius, end='/' ) p( "%.1fF" % celsius2fahrenheit( _celsius ) ) # Let's be neat _humidity = float( "%.1f" % _humidity ) _celsius = float( "%.1f" % _celsius ) # Humidity too high? if _humidity > _humidity_upper_threshold: p( "[!] Humidity %.1f%% RH exceeds upper threshold value of %.1f%% RH" % ( _humidity, _humidity_upper_threshold ) ) # Take decisive action! GPIO.output( _humidity_led, 1 ) # Humidity too low? elif _humidity < _humidity_lower_threshold: p( "[!] Humidity %.1f%% RH is below lower threshold value of %.1f%% RH" % ( _humidity, _humidity_lower_threshold ) ) # Take decisive action! GPIO.output( _humidity_led, 1 ) # Safe operating humidity? elif _humidity <= _humidity_upper_threshold and _humidity >= _humidity_lower_threshold: GPIO.output( _humidity_led, 0 ) # Safe! # Temperature too high? if _celsius > _temperature_upper_threshold: p( "[!] Temperature %.1fC/%.1fF exceeds upper threshold value of %.1fC/%.1fF" % ( _celsius, celsius2fahrenheit( _celsius ), _temperature_upper_threshold, celsius2fahrenheit( _temperature_upper_threshold ) ) ) # Take decisive action! GPIO.output( _temperature_led, 1 ) # Temperature too low? elif _celsius < _temperature_lower_threshold: p( "[!] Temperature %1.fC/%.1fF is below lower threshold value of %.1fC/%.1fF" % ( _celsius, celsius2fahrenheit( _celsius ), _temperature_lower_threshold, celsius2fahrenheit( _temperature_lower_threshold ) ) ) # Take decisive action! GPIO.output( _temperature_led, 1 ) # Safe operating temperature? elif _celsius <= _temperature_upper_threshold and _celsius >= _temperature_lower_threshold: GPIO.output( _temperature_led, 0 ) # Safe! sleep( _poll_interval ) |
[ end dht22_actionable.py ]
您的輸出不應和下圖中我的終端輸出內容相同。將450C/842F的熱風槍吹過一個裝滿水的小金屬碗,以驗證DHT22機房環境控制器(DCREC)已經功能正常。在您的應用中,請確保GPIO引腳連接到了一些完好的應用模組,例如MOSFET驅動繼電器或雙擴音器。現在開始行動吧!
您可以在下圖中看到我的麵包板。在右下角,DHT22正在運行,它會以數字的形式向我的Raspberry Pi報告。在頂部中間,兩個LED亮起,警告我的桌面計算環境不在最佳操作範圍內。
我對此感到非常意外和震驚。