Skip to content

由 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

显示

打开串口助手看一下结果

连接图

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

链接


Released under the MIT License. Build Time 2026-09-11 14:52:23