温湿度传感器

在嵌入式开发中,温湿度传感器是一类用于测量环境温度湿度设备,广泛应用于气候监测、家用电器、物联网(IoT)设备、工业自动化等领域。它们能够感知环境中的温度和湿度变化,并将这些信息以电信号(0 和 1)的形式传递给微控制器(MCU)或处理单元。

温湿度传感器的工作原理

温湿度传感器通常将温度和湿度这两个参数集成在一个传感器芯片上,它们的工作原理如下:

温度传感器部分

  • 温度测量常使用热敏电阻、热电偶、或半导体温度传感器来感知温度。
    • 热敏电阻:通过材料电阻值随温度变化而变化的特性来测量温度。
    • 半导体温度传感器:基于 PN 结的电压特性,随着温度变化产生可测量的电压变化。
    • 热电偶:由两种不同金属连接形成,当温度变化时产生电势差。

湿度传感器部分

  • 湿度测量一般通过电容式湿度传感器或电阻式湿度传感器来完成。
    • 电容式湿度传感器:由一层吸湿性介质组成,介质吸收空气中的水分导致电容变化,从而测量湿度。
    • 电阻式湿度传感器:感湿材料的电阻随空气湿度变化而变化,电阻值的变化反映空气中的湿度。

常见的温湿度传感器种类

嵌入式开发中,使用最广泛的温湿度传感器主要有以下几类:

DHT 系列传感器

  • DHT11 和 DHT22 是常见的低成本温湿度传感器,具有数字输出,易于与微控制器连接。
    • DHT11:精度较低,温度测量范围为 050℃,湿度测量范围为 20%90%RH(相对湿度)。
    • DHT22:精度较高,温度测量范围为 -4080℃,湿度测量范围为 0%100%RH。
    • 通信方式:单总线协议,通常用一根数据线来传输温度和湿度数据,简单易用。

SHT 系列传感器

  • SHT3x、SHT4x 系列是 Sensirion 公司生产的高精度温湿度传感器,广泛用于工业和高精度应用。
    • 精度:温度测量精度高达 ±0.1℃,湿度测量精度 ±1.5%RH。
    • 通信方式:采用 I2C 或 SPI 接口,数据传输速度快,适合对精度要求较高的应用。

AM2302(DHT22 的改进版)

  • 与 DHT22 类似,AM2302 是精度更高的温湿度传感器。
    • 温度测量范围:-40~80℃。
    • 湿度测量范围:0~100%RH。

DHT11

DHT11 是一种常用的低成本温湿度传感器,广泛用于简单的环境监测应用。它可以同时测量环境的温度和湿度,并通过单线数字接口与微控制器通信,易于使用。

温度测量:DHT11 使用一个 NTC 热敏电阻作为温度感应器,感知周围环境的温度变化。热敏电阻的电阻值会随着温度变化而变化,传感器内部将此电阻变化转换为温度数据。

湿度测量:DHT11 使用电容式湿度传感器来检测湿度。传感器内有一个吸湿性聚合物层,这一层的电容会随着空气中水分含量(湿度)的变化而变化。传感器通过测量这一电容变化来计算空气湿度。

通信协议

DHT11 使用单线数字通信协议来与微控制器通信,这意味着它只需一个数据线即可传输温湿度数据。通信流程通常如下:

  1. 初始化:微控制器向传感器发送一个低电平启动信号(至少 18ms),然后释放数据线(至少 10us)。

  2. 响应信号:DHT11 传感器发送一个响应信号(响应低高电平,低电平至少 78us,高电平至少 80us),告诉微控制器它已经准备好数据。

  3. 数据传输:DHT11 以位(bit)的形式将温度和湿度数据(共 40 位)传给微控制器。数据传输分为两个部分:

    • 湿度数据(16 位):包含湿度的整数和小数部分。

    • 温度数据(16 位):包含温度的整数和小数部分。

  4. 校验位:最后传感器发送一个 8 位的校验码,用于确认数据是否传输正确。

DHT11 温湿度传感器的通信时序参数

DHT11shixucanshu

数据时序图

DHT11shjushixu

信息格式说明

DHT11geshishuom

接收到的 40 位数据示例

DHT11shili

STC8H

使用 DHT11 模块

引脚图

DHT11yinjiao

NG 通常表示没有接地没有连接。在具体电路中,建议结合设计者的注释或相关文档进一步确认它的确切含义。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// DHT11.h
#ifndef __DHT11_H
#define __DHT11_H

#include "STC8G_H_GPIO.h"

struct typedef {
float humidity; // 湿度
float temperature; // 温度
u8 is_ok; // 校验位:0 数据异常,1 数据正确

}DHT11_TRH;

#endif

void DHT11_Init();

void DHT11_GetTRH();
===============================================================================
// DHT11.c
#include "DHT11.h"

#define DHT11 P46 // 温湿度传感器数据引脚

#define HIGH 1 // 高电平
#define LOW 0 // 低电平

// 计算从设备输出的高低电平是否正确
#define calc_time(level, min, max, ErrMsg); count = 0; \
do { \
count++; \
NOP16();//(1us) 不同设备可能时间不同 \
} while(DHT11 == level); \
if(count < main || count > max) { \
printf("%s: %d\n", ErrMsg, count); \
return trh; \
}

void Delay20ms(void) { // @24.000MHz
unsigned char data i, j, k;

_nop_();
i = 3;
j = 112;
k = 91;
do {
do {
while(--k);
} while(--j);

} while(--i);
}

void GPIO_DHT11_Config(void){
GPIO_InitTypeDef GPIO_DHT11_Init;
GPIO_DHT11_Init.Mode = GPIO_PullUp; //IO模式, GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_DHT11_Init.Pin = GPIO_Pin_6; //要设置的端口

GPIO_Inilize(GPIO_P4, &GPIO_DHT11_Init);
}

void DHT11_Init(void) {
GPIO_DHT11_Config();
}

DHT11_TRH DhT11_GetTRH(void) {
DHT11_TRH trh;
int i, j;
u8 dat[5] = {0};
int count = 0;
trh.is_ok = 0; // 默认数据不准确

// 主机起始信号拉低时间
DHT11 = 0;
Delay20ms();
DHT11 = 1; // 拉高后 10~35us 内温湿度传感觉会进行相应;

// 主机释放总线时间,高电平持续 10~35 us
calc_time(HIGH, 10, 35, "主机释放时间有误");

// 响应低电平时间,低电平持续时间 78~88 us
calc_time(LOW, 78, 88, "响应低电平时间有误");

// 响应高电平时间,高电平持续 80~92 us
calc_time(HIGH, 80, 92, "响应高电平时间有无");

// 开始接收数据并校验是否正确(40 位)
for(i = 0; i < 5; i++) { // 五个字节
for(j = 7; j >= 0; j--) { // 每个字节八位
// 判断低电平是否有误
calc_time(LOW, 50, 58, "信号 0|1 低电平时间有误");
// 判断高电平是否有误
calc_time(LOW, 23, 74, "信号 0|1 低电平时间有误");

if(count > 48) { // 48 是 0|1 高电平的中间值
// 数组默认为 0,所以这里只需要根据位置修改为 1 即可
dat[i] |= 1 << j;
}
}
}
// 校验数据是否正确
if(dat[4] == dat[0] + dat[1] + dat[2] + dat[3]) {
trh.is_ok = 1;

// 组装温湿度
trh.humidity = dat[0] + dat[1] * 0.1;
// 温度小数位的最高位为标志位不参与运算
trh.humidity = dat[2] + (dat[3] & 0x7F) * 0.1;

if(dat[3] & 0x80) {
trh.humidity = -trh.humidity;
}
}
return trh;
}
===========================================================================
//main.c
#include "STC8G_H_GPIO.h"
#include "STC8G_H_NVIC.h"
#include "STC8G_H_Switch.h"
#inculude "STC8G_H_Delay.h"
#inculude "STC8G_H_UART.h"
#inculude "DHTll.h.h"

void UART_Config(void) {

}

void main() {
DHT11_TRH DHT11_trh;

EA = 1;

DHT11_Init();
UART_Config();

while(1) {
trh = DHT11_GetTRH();

if(trh.is_ok) {
printf("温度:%.2f\n", trh.temperature);
printf("湿度:%.2f\n", trh.humidity);
} else {
printf("数据有误,请重新获取~");
}

delay_ms(250);
delay_ms(250);
delay_ms(250);
delay_ms(250);

delay_ms(250);
delay_ms(250);
delay_ms(250);
delay_ms(250);
}
}