[i=s] 本帖最后由 WildboarG 于 2025-4-11 16:06 编辑 [/i]
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左右)
电路连接

通讯时序

代码
手把手敲
> wb2-cli create
> Create New Project:dht11
> successfuly
#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]);
}
}
#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
#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
make flash
显示
打开串口助手看一下结果

连接图

用小玩意飞了两根线,效果还是很不错
链接
图三摘自lovzx的Ai-M61-32SU DHT11温湿度传感器