3、读取DHT22传感器数据:编写Python脚本读取温湿度、数据格式化与校验、常见读取错误处理

好,咱们进入实战环节。上一章我们把DHT22接好了线,也确认了树莓派能识别到它。现在,该写代码了。

说实话,我第一次写DHT22的读取脚本时,以为就是调个库、打印个数据那么简单。结果呢?数据读出来全是None,或者直接报错。后来我才明白——DHT22这个传感器,脾气有点怪。它需要严格的时序,而且对读取间隔有要求。

这一章,我会带你写一个健壮的读取脚本。不是那种跑一次就完事的demo,而是能用在真实项目里的代码。

3.1 安装必要的库

在树莓派上读取DHT22,最常用的库是Adafruit_DHT。不过要注意,这个库已经停止更新了。我个人更推荐用pigpio或者dht11库。但为了兼容性和教学方便,咱们还是用Adafruit_DHT,因为它最简单。

安装命令如下:

sudo pip3 install Adafruit_DHT

如果你用的是树莓派系统,可能还需要安装build-essentialpython3-dev

sudo apt-get update
sudo apt-get install build-essential python3-dev
注意: 如果你用的是树莓派4B或更高版本,Adafruit_DHT库可能会报错。我在项目中遇到过这个问题,解决方案是改用pigpio库。不过咱们先按标准流程走,遇到问题再换。

3.2 编写基础读取脚本

好,库装好了。咱们写第一个脚本。我会把代码拆开讲,这样你更容易理解。

import Adafruit_DHT
import time

# 定义传感器类型和引脚
SENSOR = Adafruit_DHT.DHT22
PIN = 4  # 我习惯用GPIO4,也就是物理引脚7

def read_dht22():
    humidity, temperature = Adafruit_DHT.read_retry(SENSOR, PIN)
    return humidity, temperature

# 主循环
while True:
    hum, temp = read_dht22()
    if hum is not None and temp is not None:
        print(f"温度: {temp:.1f}°C, 湿度: {hum:.1f}%")
    else:
        print("读取失败,重试中...")
    time.sleep(2)  # DHT22读取间隔至少2秒

这段代码很简单对吧?但有几个坑,我得跟你说清楚。

3.3 数据格式化与校验

你想想看,如果直接打印temphum,会得到什么?一堆小数点后好多位的数字。比如23.456789°C。这在显示上很不友好。

我个人习惯保留一位小数就够了。用f"{temp:.1f}"就能搞定。

但格式化只是表面功夫。真正重要的是数据校验。DHT22偶尔会读出离谱的值,比如温度-999°C,或者湿度120%。为什么会这样?多半是时序干扰或者电源波动。

所以,我建议加一层校验:

def validate_data(temperature, humidity):
    """校验温湿度数据是否在合理范围内"""
    if temperature is None or humidity is None:
        return False
    # 温度范围:-40°C ~ 80°C
    if temperature < -40 or temperature > 80:
        return False
    # 湿度范围:0% ~ 100%
    if humidity < 0 or humidity > 100:
        return False
    return True

# 使用示例
hum, temp = read_dht22()
if validate_data(temp, hum):
    print(f"有效数据 - 温度: {temp:.1f}°C, 湿度: {hum:.1f}%")
else:
    print("数据异常,丢弃")
小技巧: 我在温室项目里还加了一层“突变检测”。如果当前温度比上一次高了10°C以上,那大概率是传感器抽风了。这种数据直接扔掉,不记录。

3.4 常见读取错误处理

DHT22的读取错误,我总结下来主要有三种。咱们一个个说。

错误类型 现象 原因 解决方案
超时错误 程序卡住,或者返回None 传感器未响应,可能是接线松动 检查接线,增加重试机制
校验和错误 数据读出来了,但明显不对 数据传输过程中被干扰 丢弃数据,等待下次读取
持续失败 连续多次读取失败 传感器损坏或电源不足 检查供电,更换传感器

针对这些错误,我写了一个更健壮的读取函数:

import Adafruit_DHT
import time

SENSOR = Adafruit_DHT.DHT22
PIN = 4
MAX_RETRIES = 5  # 最大重试次数

def robust_read():
    """带重试机制的DHT22读取函数"""
    for attempt in range(MAX_RETRIES):
        try:
            humidity, temperature = Adafruit_DHT.read_retry(SENSOR, PIN)
            if humidity is not None and temperature is not None:
                # 数据校验
                if -40 <= temperature <= 80 and 0 <= humidity <= 100:
                    return temperature, humidity
                else:
                    print(f"第{attempt+1}次尝试:数据超出范围")
            else:
                print(f"第{attempt+1}次尝试:读取返回None")
        except Exception as e:
            print(f"第{attempt+1}次尝试出错:{e}")
        
        time.sleep(1)  # 等待1秒后重试
    
    # 所有重试都失败
    print("严重错误:连续5次读取失败")
    return None, None

# 使用
temp, hum = robust_read()
if temp is not None:
    print(f"最终数据 - 温度: {temp:.1f}°C, 湿度: {hum:.1f}%")
else:
    print("传感器可能坏了,请检查硬件")
核心要点: 不要相信任何一次读取的数据。DHT22的读取成功率大概在95%左右,也就是说每20次读取就有1次可能出错。所以,校验和重试是必须的。

3.5 避坑指南

我曾经在一个大棚项目里吃过亏。当时传感器装在温室里,距离树莓派有5米远。用的还是普通的杜邦线。结果呢?数据读取成功率不到50%。后来换成屏蔽线,问题就解决了。

所以,给你几个建议:

  • 线长不要超过3米,否则信号衰减严重
  • 读取间隔至少2秒,DHT22的采样频率就这么低
  • 上拉电阻不能省,4.7kΩ到10kΩ都行
  • 第一次读取往往不准,建议丢弃前两次数据

嗯,这一章的内容就这些。代码不多,但都是实战经验。下一章,我们会把这些数据存到数据库里,这样就能做历史分析了。