3、读取DHT22传感器数据:编写Python脚本读取温湿度、数据格式化与校验、常见读取错误处理
好,咱们进入实战环节。上一章我们把DHT22接好了线,也确认了树莓派能识别到它。现在,该写代码了。
说实话,我第一次写DHT22的读取脚本时,以为就是调个库、打印个数据那么简单。结果呢?数据读出来全是None,或者直接报错。后来我才明白——DHT22这个传感器,脾气有点怪。它需要严格的时序,而且对读取间隔有要求。
这一章,我会带你写一个健壮的读取脚本。不是那种跑一次就完事的demo,而是能用在真实项目里的代码。
3.1 安装必要的库
在树莓派上读取DHT22,最常用的库是Adafruit_DHT。不过要注意,这个库已经停止更新了。我个人更推荐用pigpio或者dht11库。但为了兼容性和教学方便,咱们还是用Adafruit_DHT,因为它最简单。
安装命令如下:
sudo pip3 install Adafruit_DHT
如果你用的是树莓派系统,可能还需要安装build-essential和python3-dev:
sudo apt-get update
sudo apt-get install build-essential python3-dev
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 数据格式化与校验
你想想看,如果直接打印temp和hum,会得到什么?一堆小数点后好多位的数字。比如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("数据异常,丢弃")
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("传感器可能坏了,请检查硬件")
3.5 避坑指南
我曾经在一个大棚项目里吃过亏。当时传感器装在温室里,距离树莓派有5米远。用的还是普通的杜邦线。结果呢?数据读取成功率不到50%。后来换成屏蔽线,问题就解决了。
所以,给你几个建议:
- 线长不要超过3米,否则信号衰减严重
- 读取间隔至少2秒,DHT22的采样频率就这么低
- 上拉电阻不能省,4.7kΩ到10kΩ都行
- 第一次读取往往不准,建议丢弃前两次数据
嗯,这一章的内容就这些。代码不多,但都是实战经验。下一章,我们会把这些数据存到数据库里,这样就能做历史分析了。