跳转到内容

DHT 温度传感器集成

DHT 温度传感器集成

本节详细介绍如何在 ESP32 中集成 DHT 温湿度传感器,包括库配置、数据读取和代码编写。学习完成后,您将能够:

  • 安装和配置 DHT 传感器库
  • 编写温湿度数据读取代码
  • 处理传感器读取失败的情况
  • 理解 DHT 传感器的时序要求和限制

在开始本节之前,请确保:

  • 已完成硬件接线
  • ESP32 开发环境已配置(Arduino IDE 或 PlatformIO)
  • 具备基本的 C/C++ 编程知识
  • 了解 ESP32 GPIO 操作方法

在 Arduino IDE 中安装 DHT 传感器库:

1. 打开 Arduino IDE
2. 点击 工具 → 管理库 (Sketch → Include Library → Manage Libraries)
3. 搜索 "DHT sensor library" by Adafruit
4. 选择最新版本,点击安装
5. 安装依赖库 "Adafruit Unified Sensor Lib"

库信息

  • 库名称:DHT sensor library
  • 作者:Adafruit
  • 版本:1.4.4+
  • 功能:支持 DHT11、DHT22、DHT21 等型号

在 PlatformIO 中配置库依赖:

; platformio.ini
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
lib_deps =
adafruit/DHT sensor library@^1.4.4
adafruit/Adafruit Unified Sensor@^1.1.9
#include <DHT.h>
#include <DHT_U.h>
// DHT 传感器配置
#define DHTPIN 4 // 数据引脚连接到 GPIO 4
#define DHTTYPE DHT22 // DHT22 (AM2302),如使用 DHT11 则改为 DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(115200);
Serial.println("DHT22 Sensor Test");
dht.begin(); // 初始化 DHT 传感器
}
void loop() {
// 等待 2 秒(DHT22 的最小读取间隔)
delay(2000);
// 读取湿度值
float humidity = dht.readHumidity();
// 读取温度值(摄氏度)
float temperature = dht.readTemperature();
// 读取温度值(华氏度)
float fahrenheit = dht.readTemperature(true);
// 检查读取是否成功
if (isnan(humidity) || isnan(temperature)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
// 计算体感温度(热指数)
float heatIndex = dht.computeHeatIndex(fahrenheit, humidity);
// 打印结果
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.print("°C / ");
Serial.print(fahrenheit);
Serial.print("°F, Humidity: ");
Serial.print(humidity);
Serial.print("%, Heat Index: ");
Serial.print(heatIndex);
Serial.println("°F");
}

使用非阻塞延时模式替代 delay():

#include <DHT.h>
#define DHTPIN 4
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
// 非阻塞定时器变量
unsigned long previousMillis = 0;
const unsigned long interval = 3000; // 每 3 秒读取一次
// 存储读取值
float temperature = 0;
float humidity = 0;
bool sensorError = false;
void setup() {
Serial.begin(115200);
dht.begin();
Serial.println("Non-Blocking DHT22 Reader Started");
}
void loop() {
unsigned long currentMillis = millis();
// 非阻塞定时读取
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
readSensorData();
}
// 此处可执行其他任务
// 例如:处理 MQTT 连接、接收命令等
}
void readSensorData() {
float newHumidity = dht.readHumidity();
float newTemperature = dht.readTemperature();
if (isnan(newHumidity) || isnan(newTemperature)) {
sensorError = true;
Serial.println("Sensor read failed - will retry next cycle");
return;
}
sensorError = false;
temperature = newTemperature;
humidity = newHumidity;
Serial.print("Updated - Temp: ");
Serial.print(temperature);
Serial.print("°C, Humidity: ");
Serial.print(humidity);
Serial.println("%");
}

为提高测量稳定性,可采样多次取平均值:

#include <DHT.h>
#define DHTPIN 4
#define DHTTYPE DHT22
#define SAMPLE_COUNT 5 // 采样次数
DHT dht(DHTPIN, DHTTYPE);
struct SensorReading {
float temperature;
float humidity;
};
SensorReading getAveragedReading() {
float tempSum = 0;
float humSum = 0;
int validSamples = 0;
for (int i = 0; i < SAMPLE_COUNT; i++) {
float t = dht.readTemperature();
float h = dht.readHumidity();
if (!isnan(t) && !isnan(h)) {
tempSum += t;
humSum += h;
validSamples++;
}
delay(100); // 采样间隔 100ms
}
SensorReading result = {0, 0};
if (validSamples > 0) {
result.temperature = tempSum / validSamples;
result.humidity = humSum / validSamples;
}
return result;
}
void setup() {
Serial.begin(115200);
dht.begin();
Serial.println("Averaged DHT22 Reader");
}
void loop() {
SensorReading reading = getAveragedReading();
if (reading.temperature == 0 && reading.humidity == 0) {
Serial.println("All samples failed!");
} else {
Serial.print("Averaged - Temp: ");
Serial.print(reading.temperature, 1); // 1 位小数
Serial.print("°C, Humidity: ");
Serial.print(reading.humidity, 1);
Serial.println("% (based on " + String(validSamples) + " samples)");
}
delay(5000);
}

DHT22 使用单总线协议与微控制器通信:

1. MCU 将数据线拉低至少 18ms (启动信号)
2. MCU 释放数据线并拉高 20-40μs
3. DHT22 将数据线拉低 80μs (响应信号)
4. DHT22 将数据线拉高 80μs (准备发送)
5. DHT22 发送 40 位数据 (5 字节)
- 字节 0: 湿度整数部分
- 字节 1: 湿度小数部分
- 字节 2: 温度整数部分
- 字节 3: 温度小数部分
- 字节 4: 校验和
6. 校验和 = 字节0 + 字节1 + 字节2 + 字节3 (仅低 8 位)

时序要求

  • 启动信号低电平时间:≥ 18ms
  • 数据位 “0”:高电平 26-28μs
  • 数据位 “1”:高电平 70μs
  • 读取间隔:≥ 2 秒

售前提示:DHT22 的最大采样率为 2 次/秒(每 500ms 一次),但在实际应用中建议 3-5 秒读取一次以降低功耗。这对于绝大多数环境监测场景已经足够。

void verifySensor() {
Serial.println("=== DHT22 Verification ===");
Serial.print("Sensor model: DHT22 (AM2302)\n");
Serial.print("Reading interval: 3 seconds\n");
Serial.print("Expected accuracy: ±0.5°C, ±2% RH\n\n");
// 读取 10 次数据并输出
for (int i = 1; i <= 10; i++) {
float t = dht.readTemperature();
float h = dht.readHumidity();
if (!isnan(t) && !isnan(h)) {
Serial.print("Sample ");
Serial.print(i);
Serial.print(": ");
Serial.print(t, 1);
Serial.print("°C, ");
Serial.print(h, 1);
Serial.println("%");
}
delay(3000);
}
Serial.println("\n=== Verification Complete ===");
}

验证检查清单

  • 串口输出温度值稳定,波动在 ±0.5°C 以内
  • 湿度值符合当前环境(握在手中湿度应上升)
  • 无 NaN 或无效值输出
  • 采样间隔稳定在设定值

症状:每次读取都返回 NaN

可能原因

  • 上拉电阻缺失
  • 引脚定义错误
  • DHT 传感器损坏

解决方案

  1. 确认 DHT22 DATA 引脚有 4.7kΩ-10kΩ 上拉电阻
  2. 确认 DHTPIN 定义与接线一致
  3. 尝试更换传感器模块

症状:偶尔返回 NaN,但大多数时候正常

可能原因

  • 电源噪声干扰
  • 传感器老化
  • 线缆过长

解决方案

  1. 在传感器 VCC 和 GND 之间添加 100μF 去耦电容
  2. 缩短传感器与 ESP32 之间的连线(< 20cm)
  3. 在软件中添加重试逻辑
  • 推荐: 将 DHT 传感器安装在通风良好的位置,远离热源
  • 推荐: 在户外使用时增加防水外壳
  • 推荐: 定期校准传感器(每 6-12 个月)
  • 避免: 传感器靠近 ESP32 WiFi 天线(射频干扰)
  • 避免: 高湿度环境(>90% RH)长期使用
  • 避免: 阳光直射传感器(会导致温度测量偏高)

本节要点总结:

  1. DHT 库配置:Arduino IDE 使用库管理器安装,PlatformIO 配置 lib_deps
  2. 代码实现:调用 dht.readTemperature()dht.readHumidity() 获取数据
  3. 错误处理:使用 isnan() 检查读取是否成功
  4. 精度限制:DHT22 精度 ±0.5°C / ±2%RH,每 2 秒最多读取一次
  5. 非阻塞设计:使用 millis() 定时替代 delay(),避免阻塞主循环