DHT11 温湿度模块

产品概述

DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,应用领域:暖通

空调;汽车;消费品;气象站;湿度调节器;除湿器;家电;医疗;自动控制

image-20220721225948515

特点

  • 相对湿度和温度测量
  • 全部校准,数字输出
  • 长期稳定性
  • 超长的信号传输距离:20米
  • 超低能耗:休眠
  • 4 引脚安装:可以买封装好的
  • 完全互换 : 直接出结果,不用转化

接线

单片机 DHT11
VCC VCC
GND GND
P1.1 DATA

数据传送逻辑

只有一根数据线DATA,上官一号发送序列指令给DHT11模块,模块一次完整的数据传输为40bit,高位先出

数据格式

8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验和

通讯过程时序图

image-20220721230414860

时序分析

a : dht = 1 b :dht = 0 延时30ms c: dht = 1 在60us后读d点,如果d点是低电平(被模块拉低),说明模块存在!

代码实现

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
#include "REG52.H"
#include "INTRINS.H"
sbit ledone = P3 ^ 7;
sbit dht = P1 ^ 0; // DHT out数据线在P1.0口
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;

_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k)
;
} while (--j);
} while (--i);
}

void Delay30ms() //@11.0592MHz
{
unsigned char i, j;

i = 54;
j = 199;
do
{
while (--j)
;
} while (--i);
}
void Delay60us() //@11.0592MHz
{
unsigned char i;

i = 25;
while (--i)
;
}

void check_DHT()
{
// a : dht = 1
dht = 1;
// b :dht = 0
dht = 0;
// 延时30ms
Delay30ms();
// c: dht = 1
dht = 1;
// 在60us后读d点,如果d点是低电平(被模块拉低),说明模块存在!
Delay60us();
if (dht == 0)
{
ledone = 0;
}
}
void main()
{
Delay1000ms();
Delay1000ms();
ledone = 1;
check_DHT();
while (1);
}

DHT模块初始化

时许分析

image-20220810193205055

这里需要判断模块高低电平的时间 延迟时间不好把握

这里 我使用whiile(Dht)的方法 卡 模块的 高电平 与 低电平

DHT11传输0的时序分析

image-20220810193424195

DHT11传输1的时序分析

image-20220810193444610

DHT数据 大小为 40bit 所以 我一共读五轮 每轮读8次

LCD1602显示

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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
//此代码没有封装,又臭又长,慎用! 
//接线:LCD1602数据选用P0口, RS接P1.0 RW接P1.1 EN接P1.4
//DHT11:数据线接P3.3口
#include "reg52.h"
#include "intrins.h"
sbit ledOne = P3 ^ 7;
sbit dht = P3 ^ 3; //模块的data插在p3.3
sbit fengshan = P1 ^ 6;
char datas[5];
sfr AUXR = 0x8E;
#define databuffer P0 //定义8位数据线,Po端口组
sbit RS = P1 ^ 0;
sbit RW = P1 ^ 1;
sbit EN = P1 ^ 4;
char temp[8];
char huma[8];
void check_busy()
{
char tmp = 0x80;
databuffer = 0x80;
while (tmp & 0x80)
{
// 1000 0000
RS = 0;
RW = 1;
EN = 0;
_nop_();
EN = 1;
_nop_();
_nop_();
tmp = databuffer;
EN = 0;
_nop_();
}
}
void Write_Cmd_Func(char cmd)
{
check_busy();
RS = 0;
RW = 0;
EN = 0;
_nop_();
databuffer = cmd;
_nop_();
EN = 1;
_nop_();
_nop_();
EN = 0;
_nop_();
}
void Write_Data_Func(char dataShow)
{
check_busy();
RS = 1;
RW = 0;
EN = 0;
_nop_();
databuffer = dataShow;
_nop_();
EN = 1;
_nop_();
_nop_();
EN = 0;
_nop_();
}
void Delay15ms() //@11.0592MHz
{
unsigned char i, j;
i = 27;
j = 226;
do {
while (--j)
;
} while (--i);
}
void Delay5ms() //@11.0592MHz
{
unsigned char i, j;
i = 9;
j = 244;
do {
while (--j)
;
} while (--i);
}
void UartInit(void) // 9600bps@11.0592MHz
{
AUXR = 0x01;
SCON = 0x40; //配置串口工作方式1,REN不使能接收
TMOD &= 0xF0;
TMOD |= 0x20; //定时器1工作方式位8位自动重装
TH1 = 0xFD;
TL1 = 0xFD; // 9600波特率的初值
TR1 = 1; //启动定时器
}
void sendByte(char data_msg)
{
SBUF = data_msg;
while (!TI)
;
TI = 0;
}
void sendString(char *str)
{
while (*str != '\0')
{
sendByte(*str);
str++;
}
}
void Delay30ms() //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do {
while (--j)
;
} while (--i);
}
void Delay60us() //@11.0592MHz
{
unsigned char i;
i = 25;
while (--i)
;
}
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do {
do {
while (--k)
;
} while (--j);
} while (--i);
}
void DHT11_Start()
{
dht = 1;
dht = 0; //延时30ms
Delay30ms();
dht = 1;
//卡d点;
while (dht)
;
//卡e点 while (!dht) 卡f点:while(dht) while (dht);
while (!dht)
;
while (dht)
;
}
void Delay40us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 15;
while (--i)
;
}
void Read_Data_From_DHT()
{
int i; //轮
int j; //每一轮读多少次
char tmp;
char flag;
DHT11_Start();
for (i = 0; i < 5; i++)
{ //卡g点while(!dht) 有效数据都是高电平,持续时间不一样,50us读,低电平0 高 电平
for (j = 0; j < 8; j++)
{
while (!dht)
; //等待卡g点
Delay40us();
if (dht == 1)
{
flag = 1;
while (dht)
;
}
else
{
flag = 0;
}
tmp = tmp << 1;
tmp |= flag;
}
datas[i] = tmp;
}
}
void LCD1602_INIT()
{
//(1)延时 15ms
Delay15ms();
//(2)写指令 38H(不检测忙信号)
Write_Cmd_Func(0x38);
//(3)延时 5ms
Delay5ms();
//(4)以后每次写指令,读/写数据操作均需要检测忙信号 //(5)写指令 38H:显示模式设置
Write_Cmd_Func(0x38);
//(6)写指令 08H:显示关闭
Write_Cmd_Func(0x08);
//(7)写指令 01H:显示清屏
Write_Cmd_Func(0x01);
//(8)写指令 06H:显示光标移动设置
Write_Cmd_Func(0x06);
//(9)写指令 0CH:显示开及光标设置

Write_Cmd_Func(0x0c);
}
void LCD1602_showLine(char row, char col, char *string)
{
switch (row)
{
case 1:
Write_Cmd_Func(0x80 + col);
while (*string)
{
Write_Data_Func(*string);
string++;
}
break;
case 2:
Write_Cmd_Func(0x80 + 0x40 + col);
while (*string)
{
Write_Data_Func(*string);
string++;
}
break;
}
}
void Build_Datas()
{

huma[0] = 'H';
huma[1] = datas[0] / 10 + 0x30;
huma[2] = datas[0] % 10 + 0x30;
huma[3] = '.';
huma[4] = datas[1] / 10 + 0x30;
huma[5] = datas[1] % 10 + 0x30;
huma[6] = '%';
huma[7] = '\0';
temp[0] = 'T';
temp[1] = datas[2] / 10 + 0x30;
temp[2] = datas[2] % 10 + 0x30;
temp[3] = '.';
temp[4] = datas[3] / 10 + 0x30;
temp[5] = datas[3] % 10 + 0x30;
temp[6] = 'C';
temp[7] = '\0';
}
void main()
{
Delay1000ms();
UartInit();
LCD1602_INIT();
Delay1000ms();
Delay1000ms();
ledOne = 0;
while (1)
{
Delay1000ms();
Read_Data_From_DHT();
if (datas[2] > 24) { fengshan = 0; }
Build_Datas();
sendString(huma);
sendString("\r\n");
sendString(temp);
sendString("\r\n");
LCD1602_showLine(1, 2, huma);
LCD1602_showLine(2, 2, temp);
}
}

分文件编程(推荐)

代码结构

image-20220811182648943

说明

  • config.h 接口定义
  • delay.h 延迟函数
  • dht11.h 温湿度模块
  • lcd1602.h LCD1602显示
  • uart.h 串口初始化
  • main 主函数

main.c

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
//接线:LCD1602数据选用P0口, RS接P1.0 RW接P1.1 EN接P1.4 
//DHT11:数据线接P3.3口
#include "reg52.h"
#include "intrins.h"
#include "delay.h"
#include"uart.h"
#include"lcd1602.h"
#include"dht11.h"
#include "config.h"
char temp[8];
char huma[8];

extern char datas[5];
void Build_Datas()
{
huma[0] = 'H';
huma[1] = datas[0] / 10 + 0x30;
huma[2] = datas[0] % 10 + 0x30;
huma[3] = '.';
huma[4] = datas[1] / 10 + 0x30;
huma[5] = datas[1] % 10 + 0x30;
huma[6] = '%';
huma[7] = '\0';
temp[0] = 'T';
temp[1] = datas[2] / 10 + 0x30;
temp[2] = datas[2] % 10 + 0x30;
temp[3] = '.';
temp[4] = datas[3] / 10 + 0x30;
temp[5] = datas[3] % 10 + 0x30;
temp[6] = 'C';
temp[7] = '\0';
}
void main()
{
Delay1000ms();
UartInit();
LCD1602_INIT();
Delay1000ms();
Delay1000ms();
ledOne = 0;
while (1)
{
Delay1000ms();
Read_Data_From_DHT();
if (datas[2] >= 24)
{ fengshan = 0; } //风扇开关
else
{
fengshan = 1 ;
}

Build_Datas();
sendString(huma);
sendString("\r\n");
sendString(temp);
sendString("\r\n");
LCD1602_showLine(1, 2, huma);
LCD1602_showLine(2, 2, temp);
}
}

config.h

1
2
sbit ledOne   = P3 ^ 7;
sbit fengshan = P1 ^ 6;

delay.c

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
#include "REG52.H"
#include<INTRINS.H>
void Delay30ms() //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do {
while (--j)
;
} while (--i);
}
void Delay60us() //@11.0592MHz
{
unsigned char i;
i = 25;
while (--i)
;
}
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do {
do {
while (--k)
;
} while (--j);
} while (--i);
}
void Delay40us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 15;
while (--i)
;
}
void Delay15ms() //@11.0592MHz
{
unsigned char i, j;
i = 27;
j = 226;
do {
while (--j)
;
} while (--i);
}
void Delay5ms() //@11.0592MHz
{
unsigned char i, j;
i = 9;
j = 244;
do {
while (--j)
;
} while (--i);
}

delay.h

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "REG52.H"
#include<INTRINS.H>
void Delay30ms(); //@11.0592MHz

void Delay60us(); //@11.0592MHz

void Delay1000ms(); //@11.0592MHz

void Delay15ms(); //@11.0592MHz

void Delay5ms(); //@11.0592MHz

void Delay40us(); //@11.0592MHz

dht11.c

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
#include "REG52.H"
#include"delay.h"
char datas[5];
sbit dht = P3 ^ 3; //模块的data插在p3.3

void DHT11_Start()
{
dht = 1;
dht = 0; //延时30ms
Delay30ms();
dht = 1;
//卡d点;
while (dht)
;
//卡e点 while (!dht) 卡f点:while(dht) while (dht);
while (!dht)
;
while (dht)
;
}

void Read_Data_From_DHT()
{
int i; //轮
int j; //每一轮读多少次
char tmp;
char flag;
DHT11_Start();
for (i = 0; i < 5; i++)
{ //卡g点while(!dht) 有效数据都是高电平,持续时间不一样,50us读,低电平0 高 电平
for (j = 0; j < 8; j++)
{
while (!dht)
; //等待卡g点
Delay40us();
if (dht == 1)
{
flag = 1;
while (dht)
;
}
else
{
flag = 0;
}
tmp = tmp << 1;
tmp |= flag;
}
datas[i] = tmp;
}
}

dht11.h

1
void Read_Data_From_DHT();

lcd1602.c

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
#include "REG52.H"
#include<INTRINS.H>
#include"delay.h"
#include"dht11.h"
#define databuffer P0 //定义8位数据线,Po端口组
sbit RS = P1 ^ 0;
sbit RW = P1 ^ 1;
sbit EN = P1 ^ 4;
void check_busy()
{
char tmp = 0x80;
databuffer = 0x80;
while (tmp & 0x80)
{
// 1000 0000
RS = 0;
RW = 1;
EN = 0;
_nop_();
EN = 1;
_nop_();
_nop_();
tmp = databuffer;
EN = 0;
_nop_();
}
}
void Write_Cmd_Func(char cmd)
{
check_busy();
RS = 0;
RW = 0;
EN = 0;
_nop_();
databuffer = cmd;
_nop_();
EN = 1;
_nop_();
_nop_();
EN = 0;
_nop_();
}
void Write_Data_Func(char dataShow)
{
check_busy();
RS = 1;
RW = 0;
EN = 0;
_nop_();
databuffer = dataShow;
_nop_();
EN = 1;
_nop_();
_nop_();
EN = 0;
_nop_();
}

void LCD1602_INIT()
{
//(1)延时 15ms
Delay15ms();
//(2)写指令 38H(不检测忙信号)
Write_Cmd_Func(0x38);
//(3)延时 5ms
Delay5ms();
//(4)以后每次写指令,读/写数据操作均需要检测忙信号 //(5)写指令 38H:显示模式设置
Write_Cmd_Func(0x38);
//(6)写指令 08H:显示关闭
Write_Cmd_Func(0x08);
//(7)写指令 01H:显示清屏
Write_Cmd_Func(0x01);
//(8)写指令 06H:显示光标移动设置
Write_Cmd_Func(0x06);
//(9)写指令 0CH:显示开及光标设置

Write_Cmd_Func(0x0c);
}
void LCD1602_showLine(char row, char col, char *string)
{
switch (row)
{
case 1:
Write_Cmd_Func(0x80 + col);
while (*string)
{
Write_Data_Func(*string);
string++;
}
break;
case 2:
Write_Cmd_Func(0x80 + 0x40 + col);
while (*string)
{
Write_Data_Func(*string);
string++;
}
break;
}
}

lcd1602.h

1
2
3

void LCD1602_INIT();
void LCD1602_showLine(char row, char col, char *string);

uart.c

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
#include "REG52.H"
#include "config.h"
sfr AUXR = 0x8E;
char buffer[12] ;
void UartInit(void) // 9600bps@11.0592MHz
{
AUXR = 0x01;
SCON = 0x50; //配置串口工作方式1,REN不使能接收
TMOD &= 0xF0;
TMOD |= 0x20; //定时器1工作方式位8位自动重装
TH1 = 0xFD;
TL1 = 0xFD; // 9600波特率的初值
TR1 = 1; //启动定时器
EA = 1 ; //开启总中断
ES = 1 ; // 开启串口中断
}
void sendByte(char data_msg)
{
SBUF = data_msg;
while (!TI)
;
TI = 0;
}
void sendString(char *str)
{
while (*str != '\0')
{
sendByte(*str);
str++;
}
}

void Uart_Handler() interrupt 4
{
char tmp ;
char i ;
if(RI)
{
RI = 0 ;
tmp = SBUF;
if(tmp == ":"){
i = 0 ;
}
buffer[i++] = tmp ;
if(buffer[0] == ':' && buffer[1] == 'o' && buffer[2] == 'p'){
fengshan = 1 ;
}
if(buffer[0] == ':' && buffer[1] == 'c' && buffer[2] == 'l'){
fengshan = 1 ;
}
}
}

uart.h

1
2
3
4
5
#include "REG52.H"
sfr AUXR = 0x8E;
void UartInit(void) ;// 9600bps@11.0592MHz
void sendByte(char data_msg);
void sendString(char *str);

接上蓝牙透传模块 可以在手机的蓝牙助手查看数据