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)
树莓派 3.3V GPIO4 GND 10kΩ →3.3V DHT22 温湿度传感器 VCC DATA NC GND

代码实现

使用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