2. 读取DHT22温湿度传感器数据
任务说明
本案例使用树莓派GPIO连接DHT22数字温湿度传感器,通过单总线协议读取温度(精度±0.5°C)和相对湿度(精度±2%RH)数据,并将结果输出到终端。DHT22每2秒可完成一次完整测量,数据帧为40位(16位湿度、16位温度、8位校验)。
硬件连接
DHT22传感器共4个引脚(部分模块为3针),连接关系如下:
- VCC(引脚1)→ 树莓派3.3V(物理引脚1)
- DATA(引脚2)→ 树莓派GPIO4(物理引脚7),需外接10kΩ上拉电阻至3.3V
- NC(引脚3)→ 悬空
- GND(引脚4)→ 树莓派GND(物理引脚6)
代码实现
使用Python的pigpio库实现DHT22时序读取。该库提供精确的GPIO电平变化时间戳,满足DHT22对微秒级时序的要求。代码包含完整的校验和验证与错误重试机制。
#!/usr/bin/env python3
import pigpio
import time
import sys
DHT22_PIN = 4
MAX_RETRIES = 5
class DHT22Reader:
def __init__(self, pi, gpio):
self.pi = pi
self.gpio = gpio
self.last_tick = None
self.bits = []
self.callback = pi.callback(gpio, pigpio.EITHER_EDGE, self._edge_cb)
def _edge_cb(self, gpio, level, tick):
if self.last_tick is not None:
diff = pigpio.tickDiff(self.last_tick, tick)
if level == 0: # 下降沿,记录高电平持续时间
self.bits.append(diff)
self.last_tick = tick
def read(self):
"""发送起始信号并读取40位数据,返回(湿度,温度)或None"""
for attempt in range(MAX_RETRIES):
self.bits = []
self.last_tick = None
# 发送起始信号:拉低至少18ms再释放
self.pi.set_mode(self.gpio, pigpio.OUTPUT)
self.pi.write(self.gpio, 0)
time.sleep(0.02)
self.pi.set_mode(self.gpio, pigpio.INPUT)
# 等待响应完成(约5ms)
time.sleep(0.01)
if len(self.bits) >= 42: # 起始+响应+40位数据
data = self._parse_bits()
if data:
return data
return None
def _parse_bits(self):
"""解析电平持续时间列表为温湿度值"""
# 跳过起始信号和响应信号(前2-3个边沿)
# DHT22数据位:50us=0,70us=1
bits = []
for duration in self.bits[3:43]: # 取40个数据位
bits.append(1 if duration > 60 else 0)
if len(bits) != 40:
return None
# 解析湿度(16位)、温度(16位)、校验(8位)
humidity = (bits[0] << 15) | (bits[1] << 14) | (bits[2] << 13) | (bits[3] << 12) | \
(bits[4] << 11) | (bits[5] << 10) | (bits[6] << 9) | (bits[7] << 8) | \
(bits[8] << 7) | (bits[9] << 6) | (bits[10] << 5) | (bits[11] << 4) | \
(bits[12] << 3) | (bits[13] << 2) | (bits[14] << 1) | bits[15]
temp_raw = (bits[16] << 15) | (bits[17] << 14) | (bits[18] << 13) | (bits[19] << 12) | \
(bits[20] << 11) | (bits[21] << 10) | (bits[22] << 9) | (bits[23] << 8) | \
(bits[24] << 7) | (bits[25] << 6) | (bits[26] << 5) | (bits[27] << 4) | \
(bits[28] << 3) | (bits[29] << 2) | (bits[30] << 1) | bits[31]
checksum = (bits[32] << 7) | (bits[33] << 6) | (bits[34] << 5) | (bits[35] << 4) | \
(bits[36] << 3) | (bits[37] << 2) | (bits[38] << 1) | bits[39]
# 校验:湿度高8位+湿度低8位+温度高8位+温度低8位 的低8位
byte_sum = ((humidity >> 8) + (humidity & 0xFF) +
(temp_raw >> 8) + (temp_raw & 0xFF)) & 0xFF
if byte_sum != checksum:
return None
# 温度最高位为符号位(1=负温)
if temp_raw & 0x8000:
temp_raw = -(temp_raw & 0x7FFF)
return (humidity / 10.0, temp_raw / 10.0)
def main():
pi = pigpio.pi()
if not pi.connected:
print("无法连接pigpio守护进程,请先运行: sudo pigpiod")
sys.exit(1)
try:
sensor = DHT22Reader(pi, DHT22_PIN)
print("DHT22传感器读取中(按Ctrl+C退出)...")
while True:
result = sensor.read()
if result:
humidity, temp = result
print(f"湿度: {humidity:.1f}%RH 温度: {temp:.1f}°C")
else:
print("读取失败,重试中...")
time.sleep(2)
except KeyboardInterrupt:
print("\n程序已退出")
finally:
sensor.callback.cancel()
pi.stop()
if __name__ == "__main__":
main()
运行与验证
依赖安装:
sudo apt-get install pigpio python3-pigpio
sudo systemctl enable pigpiod
sudo systemctl start pigpiod
运行程序:
python3 dht22_read.py
验证方法:程序启动后每2秒输出一组温湿度读数。判定标准:
- 输出湿度范围在0~100%RH之间,温度在-40~80°C之间(DHT22量程);
- 连续多次读数波动不超过±1%RH和±0.5°C(环境无突变时);
- 用手靠近传感器或对其哈气,读数应发生相应变化;
- 若输出“读取失败”,检查接线和上拉电阻,程序会自动重试。
预期输出示例(实际值取决于环境):
湿度: 45.2%RH 温度: 23.5°C
湿度: 45.1%RH 温度: 23.6°C