DHT22 是一种常见的温湿度传感器,能够测量环境的温度和相对湿度,并通过单总线协议传输数据。它工作原理简单可靠,适合应用于环境监测领域。
如何启动DHT22传感器,使用什么通信协议。
DHT22 的工作原理
1. 传感器结构
- 湿度检测:通过电容式湿度传感器测量空气中水汽含量。
- 温度检测:通过NTC热敏电阻测量温度。
- 数据处理:传感器内部包含一个 8 位微控制器,用于处理温湿度信号并将其编码为数字信号。
- 通信接口:单总线协议(One-Wire),通过一个数据引脚传输所有信息。
2. 工作流程
-
初始化阶段:
- MCU 向 DHT22 发送启动信号:通过拉低数据线(通常 1ms 以上)并随后释放。
- DHT22 响应一个握手信号:先输出一个低电平(80us),再输出一个高电平(80us)。
-
数据传输阶段:
- DHT22 开始以时序形式发送 40 位数据(湿度和温度)。
- 数据以位为单位传输,每个位的时序如下:
- 起始低电平:50us。
- 高电平持续时间表示位值:
- 低于 30us:逻辑 0。
- 高于 70us:逻辑 1。
-
数据内容:
- 40 位数据分为 5 个字节:
- 前 16 位:湿度数据(高 8 位和低 8 位)。
- 中间 16 位:温度数据(高 8 位和低 8 位)。
- 最后 8 位:校验和(用于验证数据正确性)。
- 温度和湿度均为 16 位整数(带符号的温度值)。
- 40 位数据分为 5 个字节:
-
数据结束阶段:
- DHT22 拉低数据线,标志通信结束。
3. 通信时序
以下是关键时序:
- 初始化信号:MCU 拉低数据线 1~20ms。
- 响应信号:
- DHT22 发送低电平 80us。
- 随后发送高电平 80us。
- 数据时序:
- 每一位的数据由一个 50us 的低电平起始。
- 逻辑 0:低电平后高电平持续约 26~28us。
- 逻辑 1:低电平后高电平持续约 70us。
4. 数据格式
-
湿度数据(16 位):
- 高 8 位 + 低 8 位,单位为 0.1% RH。
- 例如:
0x02 0x58
表示湿度为 60.0% RH。
-
温度数据(16 位):
- 高 8 位 + 低 8 位,单位为 0.1°C。
- 例如:
0x01 0x2C
表示温度为 30.0°C。 - 温度为负值时,高 8 位的最高位为 1。
- 例如:
0xFF 0x9C
表示温度为 -10.0°C。
-
校验和:
- 校验和 = (湿度高 8 位 + 湿度低 8 位 + 温度高 8 位 + 温度低 8 位)取低 8 位。
#include "main.h"
#include <stdint.h>
#define DHT22_PORT GPIOA
#define DHT22_PIN GPIO_PIN_1
uint8_t DHT22_data[5]; // 存储从 DHT22 接收的 5 字节数据
// 设置 GPIO 为输出模式
void DHT22_SetPinOutput() {
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = DHT22_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(DHT22_PORT, &GPIO_InitStruct);
}
// 设置 GPIO 为输入模式
void DHT22_SetPinInput() {
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = DHT22_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(DHT22_PORT, &GPIO_InitStruct);
}
// 读取 DHT22 数据
uint8_t DHT22_ReadData(uint8_t *humidity, uint8_t *temperature) {
uint8_t i, j;
uint16_t raw_data = 0;
// 初始化传感器
DHT22_SetPinOutput();
HAL_GPIO_WritePin(DHT22_PORT, DHT22_PIN, GPIO_PIN_RESET); // 拉低电平 1ms
HAL_Delay(1);
HAL_GPIO_WritePin(DHT22_PORT, DHT22_PIN, GPIO_PIN_SET); // 拉高电平 20-40us
delay_us(30);
DHT22_SetPinInput(); // 切换到输入模式
// 检测 DHT22 的响应信号
uint32_t timeout = 1000;
while (HAL_GPIO_ReadPin(DHT22_PORT, DHT22_PIN) == GPIO_PIN_SET) {
if (--timeout == 0) return 1; // 超时返回
}
// 等待低电平结束
timeout = 1000;
while (HAL_GPIO_ReadPin(DHT22_PORT, DHT22_PIN) == GPIO_PIN_RESET) {
if (--timeout == 0) return 1;
}
// 等待高电平结束
timeout = 1000;
while (HAL_GPIO_ReadPin(DHT22_PORT, DHT22_PIN) == GPIO_PIN_SET) {
if (--timeout == 0) return 1;
}
// 读取 40 位数据
for (j = 0; j < 5; j++) {
for (i = 0; i < 8; i++) {
// 等待数据起始信号
while (HAL_GPIO_ReadPin(DHT22_PORT, DHT22_PIN) == GPIO_PIN_RESET);
// 计算高电平持续时间
delay_us(40);
if (HAL_GPIO_ReadPin(DHT22_PORT, DHT22_PIN) == GPIO_PIN_SET) {
raw_data |= (1 << (7 - i)); // 如果高电平持续超过 40us,则为 1
while (HAL_GPIO_ReadPin(DHT22_PORT, DHT22_PIN) == GPIO_PIN_SET);
}
}
DHT22_data[j] = raw_data;
raw_data = 0;
}
// 校验和检测
if (DHT22_data[4] != (DHT22_data[0] + DHT22_data[1] + DHT22_data[2] + DHT22_data[3])) {
return 2; // 校验和错误
}
// 数据解析
*humidity = DHT22_data[0];
*temperature = DHT22_data[2];
return 0; // 成功
}