极客造物:简易Raspberry Pi温湿度传感器
这篇文章来源于DevicePlus.com英语网站的翻译稿。

目录
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 启动!

1. 简介

能够在任意环境中轻松感知环境湿度的能力非常重要,因为湿度不仅会影响人的舒适度,还会影响人类机体的运作。我们在本文中将要使用的双模传感器非常适用于创客项目,例如改善HVAC、气象站和物联网恒温器,尤其是与仅在Raspbian上可用的大量高质量软件包相结合之后。您可以在Pi(或Linux终端)上试试这个:
  1. wget \ http://archive.raspbian.org/raspbian/dists/stable/main/binary-armhf/Packages.xz \
  2. -O - 2>/dev/null | xz -dfc | grep -c '^Package: ' \
  3. | 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环境中好得多。湿度对此有所帮助。很多人没有发现这一点,而您现在已经获悉这个小技巧了。

了解了这些内容,现在我们继续讨论硬件部分。

1.1 认识DHT22:一种温湿度传感器

该使用什么硬件?当然,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秒内就可以完成,非常好。
dht22_pinout.jpg.jpg
引脚从左到右分别是1:VCC(3V3),2:SIGNAL,3:NC(未连接),4:GND。您还需要一个从引脚2到引脚1的10kΩ上拉电阻。

当且仅当您遇到抖动(通常发生在长线缆电路上)状况时,需要在VCC和GND之间添加一个100nF电容。

1.2 您将要学到的内容

学习完本文内容后,您将能够轻松感知相对温度和湿度。我添加了一些辅助函数,使您无需谷歌工具就可以将完成“摄氏度”和“华氏度”之间的转换。每次都手动转换会比较麻烦。为了您的方便,我们添加两个小的辅助函数:
  1. # Celsius to fahrenheit: F = ( C * 1.8 ) + 32
  2. def celsius2fahrenheit( _celsius ):
  3.   _fahrenheit = ( "%.2f" % (( _celsius * 1.8 ) + 32) )
  4.   return float( _fahrenheit )
  5. # Fahrenheit to celsius: C = ( F - 32 ) * 5/9
  6. def fahrenheit2celsius( _fahrenheit ):
  7.   _celsius = ( "%.2f" % (( _fahrenheit - 32 ) * 5/9 ))
  8.   return float( _celsius )
在第二部分的dht22_simple.py和dht22_actionable.py中也有这两个函数。

在我们研究DHT22的过程中,将会深入探索“DHT22机房环境控制器”或DCREC的构建和操作,该器件能够对传感器数据进行响应。您可以将dht22_actionable.py作为湿度项目的模板(基于DHT22),如果您具备了硬件和安装技能,就可以完成几乎所有的工作了。阅读完python脚本后,您也将会掌握GPIO输出控制。

2. 将您的Raspberry Pi与DHT22传感器连接

DHT22非常易于使用。此处无需处理I2C总线,它是I/O的一个数据引脚,是一种半双工总线,也许您对这个术语更熟悉。

您可以从技术规格书 获取有关脉冲长度、间隔等信息,但如果您想马上开始,请首先按照此Raspberry Pi设置指南确保您的Pi已准备就绪。

准备好后,将下面的脚本复制粘贴到您的Raspberry Pi GUI编辑器中(听说Pluma很好用),并将文件保存为“rpi_prepare.sh”。

[ begin rpi_prepare.sh ]
  1. #! /usr/bin/env bash
  2. set -eu -o pipefail
  3. DEBIAN_FRONTEND="noninteractive"
  4. DEBIAN_PRIORITY="critical"
  5. DEBCONF_NOWARNINGS="yes"
  6. export DEBIAN_FRONTEND DEBIAN_PRIORITY DEBCONF_NOWARNINGS
  7. _pkg_list="pigpio wiringpi python-rpi.gpio
  8. python3-rpi.gpio rpi.gpio-common git python-gpiozero
  9. python-gpiozero-doc python3-gpiozero python-setuptools-git python3-setuptools-git python3-dev python3-pip"
  10. # Upgrade system and installed packages - uncomment where
  11. # relevant
  12. sudo apt update || ech o failed to update index list
  13. #sudo dpkg --configure -a || ech o failed to fix interrupted \
  14. upgrades
  15. #sudo apt --fix-broken --fix-missing install || ech o failed \
  16. to fix conflicts
  17. #sudo apt -y --allow-downgrades --fix-broken --fix-missing \
  18. #dist-upgrade
  19. # Install $_pkg_list
  20. sudo apt update
  21. sudo apt-get -y install $_pkg_list
  22. # Make 'pip3' bigly fresh? Yes.
  23. sudo python3 -m pip --upgrade pip setuptools wheel
  24. # Get Adafruit_DHT Python library
  25. sudo pip3 install Adafruit_DHT
  26. read -p "[?] Reboot? y/N: " _foo
  27. if [ X"$_foo" = X"y" -o X"$_foo" = X"Y" ]
  28. then
  29.   ech o "[!] Rebooting in 5 seconds, CTRL+C to abort ..."
  30.   for i in $( seq 1 5 ) ; do ech o -n . ; sleep 1 ; done ; ech o
  31.   sudo reboot
  32. fi
[ end rpi_prepare.sh ]

该脚本用于安装和更新Python3的“pip3”程序,以及安装一些有用的GPIO软件。将其复制到Pi后,使用以下命令运行:
bash rpi_prepare.sh

2.1.1 BOM

Raspberry Pi 4https://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

2.1.2 启动!

将它们全部连接起来,这一步很简单,请按照以下图示进行连接。
dht22_simple_diagram.png
首先,将DHT22放在面包板上,并在引脚1和引脚2之间添加10kΩ上拉电阻。然后将BOARD1/3V3连接到面包板上的红色导轨,BOARD6/GND连接到黑色导轨,将BCM24/BOARD18连接到DHT22上的引脚2。现在,用一根导线从红色导轨连接到DHT22的引脚1,用另一根导线从黑色导轨连接到引脚4。然后将以下脚本复制粘贴到您的Pi终端:
  1. #! /usr/bin/env python3
  2. # Demonstrate reading DHT22 sensor using the
  3. # Adafruit_DHT library
  4. # DHT22 pinout (left to right):
  5. # 1: VCC(3.3-6V)
  6. # 2: SIGNAL
  7. # 3: UNUSED
  8. # 4: GND
  9. # Notes:
  10. # - 10kOhm pull-up resistor from SIG to VCC.
  11. # - Use 3V3 for VCC, or the DHT22 will heat up.
  12. # - Indentation: 2 whitespaces per level, no tabs.
  13. import Adafruit_DHT
  14. from time import sleep
  15. p=print # Alias
  16. # Note: Use >=2000ms polling intervals
  17. _poll_interval = 2 # Seconds
  18. _dht_pin = 24 # BCM24/BOARD18
  19. _dht = Adafruit_DHT.DHT22
  20. def celsius2fahrenheit( _celsius ):
  21.   _fahrenheit = ( "%.1f" % (( _celsius * 1.8 ) + 32) )
  22.   return float( _fahrenheit )
  23. def fahrenheit2celsius( _fahrenheit ):
  24.   _celsius = ( "%.1f" % (( _fahrenheit - 32 ) * 5/9 ))
  25.   return float( _celsius )
  26. if __name__ == '__main__':
  27.   while True:
  28.     ( _humidity, _celsius ) = Adafruit_DHT.read_retry( _dht, _dht_pin )
  29.     p( "Humidity => %.1f%% RH" % _humidity )
  30.     p( "Temperature => %.2fF" % celsius2fahrenheit( _celsius ), end='/' )
  31.     p( "%.2fC" % _celsius )
  32.     sleep( _poll_interval )
[ end dht22_simple.py ]

输出应如下所示。如果没有输出任何内容,您可能遇到了运行超时的问题。这种情况有时候会发生,但是是不应该会发生的。按下CTRL+C中断程序,并检查所有连接是否正确。

dht22_simple.png

在截图的执行过程中,我将热风枪的喷嘴轻轻靠近DHT22,同时用红外温度计测量DHT22。这两个读数可以彼此验证,以保证实验的严谨性。

2.2 DHT22 机房控制器

现在,我们将做一些比仅仅通过湿度传感器和热敏电阻感知环境更有趣的事情—制作DHT22机房环境控制器。在阅读下面的dht22_actionable.py之前,需要对其操作进行简短的解释。我们设置两个Raspberry Pi GPIO引脚作为输出(BCM25/BOARD22和BCM23/BOARD16),建立与DHT22传感器的连接,然后我们循环几个条件语句来检查所处环境是否满足公认的“适于计算的最佳湿度和温度条件”。

每当湿度或温度超出范围时,_humidity_led或_temperature_led都会亮起。但它也可以用于驱动电路,例如IRLZ24N MOSFET或继电器驱动电路。您可以利用自己现有的设备来实现所有这些功能。

准备好所有的元器件,如果有缺少的东西,请访问下文BOM中的连接。

2.2.1 BOM
Raspberry Pi 4https://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
2x ROHM SLR343BC4TT32 3mm LEDhttps://www.infinite-electronic.hk/product/LAPIS-Semiconductor_SLR343BC4TT32.aspx
杜邦电线https://www.newark.com/adafruit/824/wire-gauge-28awg/dp/88W2794
面包板https://www.newark.com/mcm/21-19082/breadboardjumper-kit-with-binding/dp/79X3995
10kΩ 电阻https://www.newark.com/multicomp-pro/mccfr0w4j0103a50/carbon-film-resistor-10kohm-250mw/dp/58K5002
2x 330Ω 电阻https://www.newark.com/multicomp-pro/mccfr0w4j0331a50/carbon-film-resistor-330-ohm-250mw/dp/58K5042

2.2.2 启动!

如下图所示完成所有连接。保留上次Raspberry Pi GPIO BCM25/BOARD22和BCM23/BOARD16的引脚连接,3V3/BOARD1和GND/BOARD6的连接和上次相同。在您的Pi准备好运行程序之前不要给电路通电,在此之前仔细检查所有连接。确认没有任何问题后,通电并执行下文中的dht22_actionable.py。

python3 dht22_actionable.py
dht22_actionable_diagram.png
[ begin dht22_actionable.py ]
  1. #! /usr/bin/env python3
  2. # Install prerequisite packages & Adafruit_DHT library
  3. """
  4. #! /bin/sh
  5. _pkg_list='python3-setuptools python3-pip python3-dev python3-rpi.gpio'
  6. sudo apt-get -y install $_pkg_list
  7. sudo python3 -m pip --upgrade pip setuptools wheel
  8. sudo pip3 install Adafruit_DHT
  9. """
  10. #
  11. # Ensure operating conditions in a
  12. # datacenter (your basement) are
  13. # within SAFE OPERATING HUMIDITY- AND
  14. # TEMPERATURE THRESHOLDS FOR OPTIMAL
  15. # COMPUTING CONDITIONS.
  16. #
  17. # Will fire BCM25/BOARD22 if humidity is
  18. # out of bounds, and BCM23/BOARD16 if
  19. # temperature is out of bounds.
  20. #
  21. # Uses RPi.GPIO Adafruit_DHT library,
  22. # tested on Raspbian, Dec. 2019
  23. #
  24. # DHT22 pinout (left to right):
  25. # 1: VCC(3.3-6V)
  26. # 2: SIGNAL
  27. # 3: UNUSED
  28. # 4: GND
  29. # Notes:
  30. # - 10kOhm pull-up resistor from SIG to VCC.
  31. # - 330ohm resistors in series with RPi
  32. #   GPIO pins and ROHM SLR343BC4TT32
  33. #   3mm LEDs.
  34. # - Use 3V3 for VCC, or the DHT22 will
  35. #   heat up.
  36. # - Indentation: 2 whitespaces per level, no
  37. #   tabs.
  38. import Adafruit_DHT
  39. from time import sleep
  40. import RPi.GPIO as GPIO
  41. import atexit
  42. GPIO.setwarnings( True )
  43. # Use BCM pin numbering instead of BOARD
  44. GPIO.setmode( GPIO.BCM )
  45. _humidity_led = 25 # BCM25/BOARD22
  46. _humidity_lower_threshold = 45.0
  47. _humidity_upper_threshold = 55.0
  48. _temperature_led = 23 # BCM23/BOARD16
  49. _temperature_lower_threshold = 20.0 # 20C/68F
  50. _temperature_upper_threshold = 24.0 # 24C/75F
  51. _poll_interval = 2 # Use intervals >=2secs
  52. _dht_pin = 24 # BCM24/BOARD18
  53. _dht = Adafruit_DHT.DHT22
  54. _debug = True
  55. p=print # Alias
  56. if _debug:
  57.   p( "[!] Setting up pin BCM_%i as OUTPUT for humidity LED ..." % _humidity_led )
  58.   p( "[!] Setting up pin BCM_%i as OUTPUT for temperature LED ..." %  _temperature_led )
  59. GPIO.setup( _humidity_led, GPIO.OUT )
  60. GPIO.setup( _temperature_led, GPIO.OUT )
  61. def exit_cleanly():
  62.   print( "[!] Cleaning up and exiting ..." )
  63.   GPIO.setwarnings( False )
  64.   GPIO.cleanup()
  65.   exit()
  66. def celsius2fahrenheit( _celsius ):
  67.   _fahrenheit = ( "%.1f" % (( _celsius * 1.8 ) + 32) )
  68.   return float( _fahrenheit )
  69. def fahrenheit2celsius( _fahrenheit ):
  70.   _celsius = ( "%.1f" % (( _fahrenheit - 32 ) * 5/9 ))
  71.   return float( _celsius )
  72. # Call exit_cleanly on normal exit and CTRL+C/KeyboardInterrupt/foo
  73. atexit.register( exit_cleanly )
  74. if __name__ == '__main__':
  75.   while True:
  76.         ( _humidity, _celsius ) = Adafruit_DHT.read_retry( _dht,
  77.         _dht_pin )
  78.         if _debug:
  79.           p( "[+] Humidity => %.1f%% RH" % _humidity )
  80.           p( "[+] Temperature => %.1fC" % _celsius, end='/' )
  81.           p( "%.1fF" % celsius2fahrenheit( _celsius ) )
  82.         # Let's be neat
  83.         _humidity = float( "%.1f" % _humidity )
  84.         _celsius = float( "%.1f" % _celsius )
  85.         # Humidity too high?
  86.         if _humidity > _humidity_upper_threshold:
  87.           p(
  88.         "[!] Humidity %.1f%% RH exceeds upper threshold value of %.1f%% RH" %
  89.         ( _humidity, _humidity_upper_threshold ) )
  90.           # Take decisive action!
  91.           GPIO.output( _humidity_led, 1 )
  92.         # Humidity too low?
  93.         elif _humidity < _humidity_lower_threshold:
  94.           p(
  95.         "[!] Humidity %.1f%% RH is below lower threshold value of %.1f%% RH" %  
  96.          ( _humidity, _humidity_lower_threshold ) )
  97.           # Take decisive action!
  98.           GPIO.output( _humidity_led, 1 )
  99.         # Safe operating humidity?
  100.         elif _humidity <= _humidity_upper_threshold and _humidity >= _humidity_lower_threshold:
  101.           GPIO.output( _humidity_led, 0 )
  102.           # Safe!
  103.         # Temperature too high?
  104.         if _celsius > _temperature_upper_threshold:
  105.           p( "[!] Temperature %.1fC/%.1fF exceeds upper threshold value of %.1fC/%.1fF" %
  106.           ( _celsius, celsius2fahrenheit( _celsius ), _temperature_upper_threshold,
  107.           celsius2fahrenheit( _temperature_upper_threshold ) ) )
  108.           # Take decisive action!
  109.           GPIO.output( _temperature_led, 1 )
  110.         # Temperature too low?
  111.         elif _celsius < _temperature_lower_threshold:
  112.           p( "[!] Temperature %1.fC/%.1fF is below lower threshold value of %.1fC/%.1fF" %
  113.           ( _celsius, celsius2fahrenheit( _celsius ), _temperature_lower_threshold,
  114.           celsius2fahrenheit( _temperature_lower_threshold ) ) )
  115.           # Take decisive action!
  116.           GPIO.output( _temperature_led, 1 )
  117.         # Safe operating temperature?
  118.         elif _celsius <= _temperature_upper_threshold and _celsius >= _temperature_lower_threshold:
  119.           GPIO.output( _temperature_led, 0 )
  120.           # Safe!
  121.         sl eep( _poll_interval )
[ end dht22_actionable.py ]

您的输出不应和下图中我的终端输出内容相同。将450C/842F的热风枪吹过一个装满水的小金属碗,以验证DHT22机房环境控制器(DCREC)已经功能正常。在您的应用中,请确保GPIO引脚连接到了一些完好的应用模块,例如MOSFET驱动继电器或双扩音器。现在开始行动吧!

dht22_actionable_hysteria.png

您可以在下图中看到我的面包板。在右下角,DHT22正在运行,它会以数字的形式向我的Raspberry Pi报告。在顶部中间,两个LED亮起,警告我的桌面计算环境不在最佳操作范围内。

我对此感到非常意外和震惊。
dht22_actionable_hysteria_2.jpg
               
来源:techclass.rohm