DHT11温湿度传感器
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。其成本低、长期稳定、可以测量相对湿度和温度测量,并可以只使用一根数据线进行温湿度采集。
模块来源
采购链接:
https://item.taobao.com/item.htm?spm=a230r.1.14.23.735720126ougj3&id=522553143872&ns=1&abbucket=12#detail
资料下载链接:
https://pan.baidu.com/s/1HQEL699-Yl5Jh3Hp87_FlQ
资料提取码:2sgq
规格参数
工作电压:3-5.5V
工作电流:1MA
测量分辨率:8 bit
湿度量程: 20 - 90 %RH
湿度精度:±5 %RH
温度量程: 0 - 50 ℃
温度精度:±2 ℃
通信协议:单总线
管脚数量:3 Pin(2.54mm间距排针)
左侧信息见厂家资料文件1.2-1 产品规格书
原理解析
DHT11使用的是单总线通信,即发送数据与接收数据都在一根数据线上,通过规定的时序进行控制。资料数据见文件1.2-1 产品规格书.
从左向右看,时序一开始,主机信号就保持着高电平,所以引脚初始化完毕时,及时给引脚输出高电平。因为模块的数据线要求空闲时,要保持高电平状态。(其实模块上已经接了上拉电阻,使数据线一直保持高电平)
根据时序图可以知道,主机(ESP32S3)发送一次开始信号,待主机开始信号结束后,DHT11 发送响应信号,送出 温湿度数据,并触发一次数据采集给下一次数据读取作准备。因此完成一次数据读取需要进行起始信号、响应信号、数据接收、结束信号。
读取数据步骤:
- 起始信号:主机(ESP32S3)接入数据线的I/O输出低电平,且低电平保持时间不能小于 18ms
DATA_GPIO_OUT(0); //数据线输出低电平
delay_1ms(19); //起始信号保持时间19ms
DATA_GPIO_OUT(1); //主机释放总线
delay_uus( 20 ); //拉高等待
2
3
4
- 响应信号:等待模块的响应信号到来。将数据线改为输入模式,如果接入到低电平,说明接收到模块的响应。
DHT11_GPIO_Mode_IN();//数据线转为输入模式
//如果前面没有错误,则模块会发出低电平的应答信号,
//所以直接等待DHT11拉高,83us
timeout = 5000;
while( (! DATA_GPIO_IN ) && ( timeout >0 ) )
{
timeout--; //等待高电平的到来
}
//模块当前处于拉高准备输出数据,
//所以直接等待DHT11拉低,87us
timeout = 5000;//设置超时时间
while( DATA_GPIO_IN && ( timeout >0 ) )
{
timeout-- ; //等待低电平的到来
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- 数据传输:主机接收模块发送的40位数据,其中,位数据 ‘0’ 表示54us的低电平,27us的高电平;位数据 ‘1’ 表示54us的低电平,74us的高电平。两个格式的分辨主要是高电平的输出时长不同。
- 结束信号:模块的数据线输出 40 位数据后,是以低电平结束,它会继续输出低电平 54 微秒后转为输入状态,主机需要转为输出状态,输出高电平释放总线。
DHT11_GPIO_Mode_OUT();//转为输出模式
DATA_GPIO_OUT(1);//主机释放总线
2
数据接收完成,但是这40位数据要如何转化为温湿度数据?并如何保证传输的数据没有错误?
DHT11模块一次完整的数据传输为40bit,高位先出。 数据格式:
注意:湿度小数部分数据一直为0。
数据传送正确时,校验和数据等于“8bit湿度整数数据+8bit湿度小数数据 +8bi温度整数数据+8bit温度小数数据”所得结果的末8位。举几个例子。
示例一:接收的40位数据分别为:
校验和为 0011 0101 + 0000 0000 + 0001 1000 + 0000 0100 = 0101 0001,与接收的数据一致
湿度为 0011 0101 + 0000 0000 = 35 + 0 = 35%RH
温度为 0001 1000 0000 0100 = 24 + 4 = 24.4℃
示例二:接收的40位数据分别为:
校验和为 0011 0101 + 0000 0000 + 0001 1000 + 0000 0100 = 0101 0001,与接收的数据不一致
计算的数据为0101 0001,接收的数据为0100 1001,两者不一致说明数据不准确,丢弃这次数据,重新接收。
移植过程
引脚选择
该模块有3个引脚,具体引脚连接见 表1.4-1 各引脚连接。
移植至工程
我们的目标是将例程移植至ESP32-S3开发板上。已经为大家提供了完整的驱动代码,按照以下步骤,即可完成移植。
- 首先我们创建一个文件夹【dht11】,在【dht11】文件夹中新建两个文件(c文件和h文件)。
- 打开自己的工程,将我们刚刚创建的文件导入.c和.h文件路径。
- 在VSCode中打开main文件夹下的CMakeLists.txt文件
- 添加这些路径
代码写入
在 bsp_dht11.c 文件中写入:
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:club.szlcsc.com
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
* Change Logs:
* Date Author Notes
* 2023-11-02 LCKFB-yzh first version
*/
#include "bsp_dht11.h"
#include <stdio.h>
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "esp_err.h"
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/ledc.h"
#include <stdio.h>
#include "driver/uart.h"
#include "driver/gpio.h"
#include "rom/ets_sys.h"
float temperature = 0;
float humidity = 0;
void Delay_ms(uint16 ms)
{
vTaskDelay(ms / portTICK_PERIOD_MS);
}
//温湿度定义
uchar ucharFLAG,uchartemp;
float Humi,Temp;
uchar ucharT_data_H,ucharT_data_L,ucharRH_data_H,ucharRH_data_L,ucharcheckdata;
uchar ucharT_data_H_temp,ucharT_data_L_temp,ucharRH_data_H_temp,ucharRH_data_L_temp,ucharcheckdata_temp;
uchar ucharcomdata;
uchar Humi_small;
uchar Temp_small;
static void InputInitial(void)//设置端口为输入
{
esp_rom_gpio_pad_select_gpio(GPIO_DHT11);
gpio_set_direction(GPIO_DHT11, GPIO_MODE_INPUT);
}
static void OutputHigh(void)//输出1
{
esp_rom_gpio_pad_select_gpio(GPIO_DHT11);
gpio_set_direction(GPIO_DHT11, GPIO_MODE_OUTPUT);
gpio_set_level(GPIO_DHT11, 1);
}
static void OutputLow(void)//输出0
{
esp_rom_gpio_pad_select_gpio(GPIO_DHT11);
gpio_set_direction(GPIO_DHT11, GPIO_MODE_OUTPUT);
gpio_set_level(GPIO_DHT11, 0);
}
static uint8 getData()//读取状态
{
return gpio_get_level(GPIO_DHT11);
}
//读取一个字节数据
static void COM(void)
{
uchar i;
for(i=0;i<8;i++)
{
ucharFLAG=2;
//等待IO口变低,变低后,通过延时去判断是0还是1
while((getData()==0)&&ucharFLAG++) ets_delay_us(10);
ets_delay_us(35);//延时35us
uchartemp=0;
//如果这个位是1,35us后,还是1,否则为0
if(getData()==1)
uchartemp=1;
ucharFLAG=2;
//等待IO口变高,变高后,表示可以读取下一位
while((getData()==1)&&ucharFLAG++)
ets_delay_us(10);
if(ucharFLAG==1)
break;
ucharcomdata<<=1;
ucharcomdata|=uchartemp;
}
}
void DHT11(void) //温湿传感启动
{
OutputLow();
Delay_ms(19); //>18MS
OutputHigh();
InputInitial(); //输入
ets_delay_us(30);
if(!getData())//表示传感器拉低总线
{
ucharFLAG=2;
//等待总线被传感器拉高
while((!getData())&&ucharFLAG++)
ets_delay_us(10);
//等待总线被传感器拉低
while((getData())&&ucharFLAG++)
ets_delay_us(10);
COM();//读取第1字节,
ucharRH_data_H_temp=ucharcomdata;
COM();//读取第2字节,
ucharRH_data_L_temp=ucharcomdata;
COM();//读取第3字节,
ucharT_data_H_temp=ucharcomdata;
COM();//读取第4字节,
ucharT_data_L_temp=ucharcomdata;
COM();//读取第5字节,
ucharcheckdata_temp=ucharcomdata;
OutputHigh();
//判断校验和是否一致
uchartemp=(ucharT_data_H_temp+ucharT_data_L_temp+ucharRH_data_H_temp+ucharRH_data_L_temp);
if(uchartemp==ucharcheckdata_temp)
{
//校验和一致,
ucharRH_data_H=ucharRH_data_H_temp; // 湿度高8
ucharRH_data_L=ucharRH_data_L_temp; // 湿度低8
ucharT_data_H=ucharT_data_H_temp; // 温度高8
ucharT_data_L=ucharT_data_L_temp; // 温度低8
ucharcheckdata=ucharcheckdata_temp;
//保存温度和湿度
Humi = ucharRH_data_H;
Humi_small = ucharRH_data_L * 0.1;
Humi = Humi + Humi_small;
Temp = ucharT_data_H;
Temp_small = ucharT_data_L * 0.1;
Temp = Temp + Temp_small;
}
else
{
Humi=100;
Temp=100;
}
}
else //没用成功读取,返回0
{
Humi=0,
Temp=0;
}
OutputHigh(); //输出
}
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
在 bsp_dht11.h 文件中写入:
#ifndef _BSP_DHT11_H_
#define _BSP_DHT11_H_
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_rom_sys.h"
#include "esp_timer.h"
#define uchar unsigned char
#define uint8 unsigned char
#define uint16 unsigned short
/**************引脚修改此处****************/
#define GPIO_DHT11 1
void Delay_ms(uint16 ms);
void DHT11(void); //温湿传感启动
#endif
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
到这里移植完成了,请移步到 1.5 进行移植验证。
移植验证
在main.c中输入代码如下
#include <stdio.h>
#include <inttypes.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"
#include "esp_timer.h"
#include "freertos/FreeRTOSConfig.h"
#include "esp_task_wdt.h"
#include "dht11/bsp_dht11.h"
extern float Temp;
extern float Humi;
void app_main(void)
{
while(1)
{
//读取温湿度
DHT11();
//显示读取后的温度数据
printf("temperature = %.2f\r\n", Temp );
//显示读取后的湿度数据
printf("humidity = %.2f\r\n", Humi );
Delay_ms(1000); //延时
}
}
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
上电效果:
驱动代码: