由 WildboarG 贡献,Ai-Thinker 进行整理
Ai-WB2 读取DHT11温湿度传感器
WB2 读取DHT11温湿度传感器
说明
DHT11 既能检测温度又能检测湿度,不过 DHT11 的精度和测量范围都要低于 DS18B20,其温度测量范围为 0~50℃,误差在±2℃;湿度的测量范围为 20%~90%RH(Relative Humidity 相对湿度—指空气中水汽压与饱和水汽压的百分比),误差在±5%RH。
DHT11 电路很简单,只需要将 DATA 引脚连接单片机的一个 I/O 即可,不过该引脚需要上拉一个 5K 的电阻,DHT11 的供电电压为 3~5.5V。
数据格式为:8bit 湿度整数数据+8bit 湿度小数数据+8bit 温度整数数据+8bit 温度小数数据+8bit 校验和,一共 5 字节(40bit)数据。
由于 DHT11 分辨率只能精确到个位,所以小数部分是数据全为 0。校验和为前 4 个字节数据相加,校验的目的是为了保证数据传输的准确性。
DHT11 只有在接收到开始信号后才触发一次温湿度采集,如果没有接收到主机发送复位信号,DHT11 不主动进行温湿度采集。当数据采集完毕且无开始信号后,DHT11 自动切换到低速模式。
注意:由于 DHT11 时序要求非常严格,所以在操作时序的时候,为了防止中断干扰总线时序,先关闭总中断,操作完毕后再打开总中断。( 一次通信大概4ms左右)
电路连接

通讯时序

代码
手把手敲
- 新建一个工程
dht11
📜 点击展开:> wb2-cli create
sh
> wb2-cli create
> Create New Project:dht11
> successfuly- 进入路径下编写
main.c
📜 点击展开完整代码
c
#
include
<stdio.h>
#
include
<FreeRTOS.h>
#
include
<task.h>
#
include
<bl_gpio.h>
#
include
<bl_timer.h>
#
include
<blog.h>
#
include
<dht11.h>
#
define
GPIO_DHT 4
//定义工作引脚
extern
unsigned
int
rec_data[
4
];
int
main
(
void
)
{
// add your code here
bl_gpio_enable_output(GPIO_DHT,
0
,
0
);
printf
(
"start DTH11\r\n"
);
while
(
1
) {
DHT11_REC_Data();
bl_timer_delay_us(
1000
*
1000
);
printf
(
"Temperature:%d°C Humidity:%d%% \r\n"
, rec_data[
2
], rec_data[
0
]);
}
}- 编写
dht11.h
📜 点击展开完整代码
c
#
ifndef
__DHT11_H__
#
define
__DHT11_H__
#
include
"bl_timer.h"
#
include
<bl_gpio.h>
#
define
GPIO_DHT 4
#
define
dht11_high bl_gpio_output_set(GPIO_DHT, 1)
#
define
dht11_low bl_gpio_output_set(GPIO_DHT, 0)
#
define
Read_Data bl_gpio_input_get_value(GPIO_DHT)
void
DHT11_GPIO_Init_OUT
(
void
)
;
void
DHT11_GPIO_Init_IN
(
void
)
;
void
DHT11_Start
(
void
)
;
unsigned
char
DHT11_REC_Byte
(
void
)
;
void
DHT11_REC_Data
(
void
)
;
#
endif- 编写
dht11.c驱动函数
📜 点击展开完整代码
c
#
include
"dht11.h"
// 数据存放
unsigned
int
rec_data[
4
];
// 做为输出
void
DH11_GPIO_Init_OUT
(
void
)
{ bl_gpio_enable_output(GPIO_DHT,
0
,
0
); }
// 做为输入
void
DH11_GPIO_Init_IN
(
void
)
{ bl_gpio_enable_input(GPIO_DHT,
0
,
0
); }
// 主机发送开始信号
void
DHT11_Start
(
void
)
{
DH11_GPIO_Init_OUT();
// 输出模式
dht11_high;
// 先拉高
bl_timer_delay_us(
30
);
dht11_low;
// 拉低电平至少18us
bl_timer_delay_us(
20
*
1000
);
dht11_high;
// 拉高电平20~40us
bl_timer_delay_us(
30
);
DH11_GPIO_Init_IN();
// 输入模式
}
// 获取一个字节
char
DHT11_Rec_Byte
(
void
)
{
unsigned
char
i =
0
;
unsigned
char
data =
0
;
for
(i =
0
; i <
8
; i++)
// 1个数据就是1个字节byte,1个字节byte有8位bit
{
while
(Read_Data ==
0
)
;
// 从1bit开始,低电平变高电平,等待低电平结束
bl_timer_delay_us(
30
);
// 延迟30us是为了区别数据0和数据1,0只有26~28us
data <<=
1
;
// 左移
if
(Read_Data ==
1
)
// 如果过了30us还是高电平的话就是数据1
{
data |=
1
;
// 数据+1
}
while
(Read_Data ==
1
)
;
// 高电平变低电平,等待高电平结束
}
return
data;
}
// 获取数据
void
DHT11_REC_Data
(
void
)
{
unsigned
int
R_H =
0
, R_L =
0
, T_H =
0
, T_L =
0
;
unsigned
char
RH =
0
, RL =
0
, TH =
0
, TL =
0
, CHECK =
0
;
DHT11_Start();
// 主机发送信号
dht11_high;
// 拉高电平
if
(Read_Data ==
0
)
// 判断DHT11是否响应
{
while
(Read_Data ==
0
)
;
// 低电平变高电平,等待低电平结束
while
(Read_Data ==
1
)
;
// 高电平变低电平,等待高电平结束
R_H = DHT11_Rec_Byte();
R_L = DHT11_Rec_Byte();
T_H = DHT11_Rec_Byte();
T_L = DHT11_Rec_Byte();
CHECK = DHT11_Rec_Byte();
// 接收5个数据
dht11_low;
// 当最后一bit数据传送完毕后,DHT11拉低总线 50us
bl_timer_delay_us(
55
);
// 这里延时55us
dht11_high;
// 随后总线由上拉电阻拉高进入空闲状态。
if
(R_H + R_L + T_H + T_L ==
CHECK)
// 和检验位对比,判断校验接收到的数据是否正确
{
RH = R_H;
RL = R_L;
TH = T_H;
TL = T_L;
}
}
rec_data[
0
] = RH;
rec_data[
1
] = RL;
rec_data[
2
] = TH;
rec_data[
3
] = TL;
}- 完成然后编译
📜 点击展开:make -j32
bash
make -j32- 烧录
📜 点击展开:make flash
bash
make flash显示
打开串口助手看一下结果

连接图

用小玩意飞了两根线,效果还是很不错

