DHT11温湿度传感器
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。其成本低、长期稳定、可以测量相对湿度和温度测量,并可以只使用一根数据线进行温湿度采集。
模块来源
采购链接:
https://item.taobao.com/item.htm?spm=a230r.1.14.23.735720126ougj3&id=522553143872&ns=1&abbucket=12
资料下载链接:
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间距排针)
左侧信息见厂家资料文件2.1.2-1 产品规格书
移植过程
我们的目标是在立创开发板GD32E230C8T6上能够实现读取温湿度的功能。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。
查看资料
DHT11使用的是单总线通信,即发送数据与接收数据都在一根数据线上,通过规定的时序进行控制。
从左向右看,时序一开始,主机信号就保持着高电平,所以引脚初始化完毕时,及时给引脚输出高电平。因为模块的数据线要求空闲时,要保持高电平状态。(其实模块上已经接了上拉电阻,使数据线一直保持高电平)
根据时序图可以知道,主机(立创GD32E230C8T6)发送一次开始信号,待主机开始信号结束后,DHT11 发送响应信号,送出 温湿度数据,并触发一次数据采集给下一次数据读取作准备。因此完成一次数据读取需要进行起始信号、响应信号、数据接收、结束信号。
读取数据步骤:
- 起始信号:主机(立创GD32E230C8T6)接入数据线的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的高电平。两个格式的分辨主要是高电平的输出时长不同。
#define CHECK_TIME 28 //超过0值的高电平时间
for(i=0;i<40;i++)//循环接收40位数据
{
timeout = 5000;
//等待低电平过去
while( ( !DATA_GPIO_IN ) && (timeout > 0) ) timeout--; //54us
delay_uus(CHECK_TIME);//等待超过位数据0值的高电平时间
if ( DATA_GPIO_IN )//如果还是高电平,说明是1值
{
val=(val<<1)+1;
}
else //如果是低电平,说明是0值
{
val<<=1;
}
timeout = 5000;
//如果当前还是高电平,等待高电平过去,准备接收下一位数据
while( DATA_GPIO_IN && (timeout > 0) ) timeout-- ;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 结束信号:模块的数据线输出 40 位数据后,是以低电平结束,它会继续输出低电平 54 微秒后转为输入状态,主机需要转为输出状态,输出高电平释放总线。
DHT11_GPIO_Mode_OUT();//转为输出模式
DATA_GPIO_OUT(1);//主机释放总线
2
数据接收完成,但是这40位数据要如何转化为温湿度数据?并如何保证传输的数据没有错误?
DHT11模块一次完整的数据传输为40bit,高位先出。 数据格式:
8bit湿度整数数据 + 8bit湿度小数数据 + 8bi温度整数数据 + 8bit温度小数数据 + 8bit校验和
注意:湿度小数部分数据一直为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,两者不一致说明数据不准确,丢弃这次数据,重新接收。
以下为数据处理的实现代码:
//val为接收到的40位数据。
// 湿高8 + 湿低8 + 温高8 + 温低8
verify_num = (val>>32) + (val>>24) + (val>>16) + (val>>8);
//计算的校验和 与 接收的校验和 的差为0说明一致,不为0说明不一致
//(val&0xff)是因为val的大小为64位,我们只需要val的最后8位校验和
verify_num = verify_num - (val&0xff);
//进行校验
if( verify_num )//如果不为0,说明校验失败
{
// 校验错误
return 0;
}
else //校验成功
{
//数据处理
humidity = (val>>32)&0xff; //湿度前8位(小数点前数据)
small_point = (val>>24)&0x00ff; //湿度后8位(小数点后数据)
small_point = small_point * 0.1; //换算为小数点
humidity = humidity + small_point; //小数前+小数后
printf("湿度:%.2f\r\n",humidity);
temperature = (val>>16)&0x0000ff; //温度前8位(小数点前数据)
small_point = (val>>8)&0x000000ff; //温度后8位(小数点后数据)
small_point = small_point * 0.1; //换算为小数点
temperature = temperature + small_point;//小数前+小数后
printf("温度:%.2f\r\n",temperature);
return val>>8; //返回未处理的数据
}
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
引脚选择
该模块有3个引脚,具体引脚连接见 表2.1.3.2 各引脚连接 。
移植至工程
打开自己的工程。(这里工程参考入门手册工程模板)
新建两个文件。
点击生成的文件,分别保存并命名为 bsp_dht11.c 与 bsp_dht11.h 。
将 bsp_dht11.c 和 bsp_uart.c 添加至工程目录。
然后我们就会发现文件夹和.c文件出现在了项目目录中。
在文件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 "systick.h" //主要使用延时函数,如果没有该.h文件,请将自己的延时文件导入
#include "stdio.h"
float temperature = 0;
float humidity = 0;
/******************************************************************
* 函 数 名 称:DHT11_GPIO_Init
* 函 数 说 明:DHT11温湿度传感器初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void DHT11_GPIO_Init(void)
{
// 开启时钟
rcu_periph_clock_enable(RCU_DHT11);
/* 配置为输出模式 上拉模式 */
gpio_mode_set(PORT_DHT11,GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_DHT11);
/* 配置为推挽输出 50MHZ */
gpio_output_options_set(PORT_DHT11,GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_DHT11);
gpio_bit_set(PORT_DHT11, GPIO_DHT11);
}
/******************************************************************
* 函 数 名 称:DHT11_GPIO_Mode_OUT
* 函 数 说 明:配置DHT11的数据引脚为输出模式
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void DHT11_GPIO_Mode_OUT(void)
{
/* 配置为输出模式 上拉模式 */
gpio_mode_set(PORT_DHT11,GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_DHT11);
/* 配置为推挽输出 50MHZ */
gpio_output_options_set(PORT_DHT11,GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_DHT11);
}
/******************************************************************
* 函 数 名 称:DHT11_GPIO_Mode_IN
* 函 数 说 明:配置DHT11的数据引脚为输入模式
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void DHT11_GPIO_Mode_IN(void)
{
/* 配置为输入模式 上拉模式 */
gpio_mode_set(PORT_DHT11,GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_DHT11);
}
/******************************************************************
* 函 数 名 称:DHT11_Read_Data
* 函 数 说 明:根据时序读取温湿度数据
* 函 数 形 参:无
* 函 数 返 回:0=数据校验失败 其他=温湿度未处理的数据
* 作 者:LC
* 备 注:无
******************************************************************/
unsigned int DHT11_Read_Data(void)
{
int i;
long long val=0;
int timeout=0;
float small_point=0;
unsigned char verify_num = 0;//验证值
DATA_GPIO_OUT(0);//数据线输出低电平
delay_ms(19); //起始信号保持时间19ms
DATA_GPIO_OUT(1);//主机释放总线
delay_us( 20 );//拉高等待
DHT11_GPIO_Mode_IN();//数据线转为输入模式
//如果前面没有错误,则模块会发出低电平的应答信号,所以直接等待DHT11拉高,80us
timeout = 5000;
while( (! DATA_GPIO_IN ) && ( timeout >0 ) )timeout--; //等待高电平的到来
//模块当前处于拉高准备输出数据,所以直接等待DHT11拉低,80us
timeout = 5000;//设置超时时间
//DATA_GPIO_IN=0时,while条件不成立退出while 说明接收到响应信号
//当timeout<=0时,while条件不成立退出while 说明超时
while( DATA_GPIO_IN && ( timeout >0 ) )timeout-- ; //等待低电平的到来
#define CHECK_TIME 28 //实测发现超过0值的高电平时间
for(i=0;i<40;i++)//循环接收40位数据
{
timeout = 5000;
while( ( !DATA_GPIO_IN ) && (timeout > 0) ) timeout--; //等待低电平过去
delay_us(CHECK_TIME);//超过0值的高电平时间
if ( DATA_GPIO_IN )//如果还是高电平,说明是1值
{
val=(val<<1)+1;
}
else //如果是低电平,说明是0值
{
val<<=1;
}
timeout = 5000;
while( DATA_GPIO_IN && (timeout > 0) ) timeout-- ; //如果还是高电平
}
DHT11_GPIO_Mode_OUT();//转为输出模式
DATA_GPIO_OUT(1);//主机释放总线
// 湿高8 + 湿低8 + 温高8 + 温低8
verify_num = (val>>32) + (val>>24) + (val>>16) + (val>>8);
//计算的校验和 与 接收的校验和 的差为0说明一致,不为0说明不一致
verify_num = verify_num - (val&0xff);
//进行校验
if( verify_num )
{
// 校验错误
return 0;
}
else //校验成功
{
//数据处理
humidity = (val>>32)&0xff;//湿度前8位(小数点前数据)
small_point = (val>>24)&0x00ff;//湿度后8位(小数点后数据)
small_point = small_point * 0.1;//换算为小数点
humidity = humidity + small_point;//小数前+小数后
// printf("湿度:%.2f\r\n",humidity);
temperature = (val>>16)&0x0000ff;//温度前8位(小数点前数据)
small_point = (val>>8)&0x000000ff;//温度后8位(小数点后数据)
small_point = small_point * 0.1;//换算为小数点
temperature = temperature + small_point;//小数前+小数后
// printf("温度:%.2f\r\n",temperature);
return val>>8; //返回未处理的数据
}
}
/******************************************************************
* 函 数 名 称:Get_temperature
* 函 数 说 明:获取温度数据
* 函 数 形 参:无
* 函 数 返 回:温度值
* 作 者:LC
* 备 注:使用前必须先调用 DHT11_Read_Data 读取有数据
******************************************************************/
float Get_temperature(void)
{
return temperature;
}
/******************************************************************
* 函 数 名 称:Get_humidity
* 函 数 说 明:获取湿度数据
* 函 数 形 参:无
* 函 数 返 回:湿度值
* 作 者:LC
* 备 注:使用前必须先调用 DHT11_Read_Data 读取有数据
******************************************************************/
float Get_humidity(void)
{
return humidity;
}
在文件bsp_dht11.h中,编写如下代码。
#ifndef _BSP_DHT11_H_
#define _BSP_DHT11_H_
#include "gd32e23x.h"
/**************引脚修改此处****************/
#define RCU_DHT11 RCU_GPIOB
#define PORT_DHT11 GPIOB
#define GPIO_DHT11 GPIO_PIN_0
//设置DHT11输出高或低电平
#define DATA_GPIO_OUT(x) gpio_bit_write(PORT_DHT11, GPIO_DHT11, x?SET:RESET)
//获取DHT11数据引脚高低电平状态
#define DATA_GPIO_IN gpio_input_bit_get(PORT_DHT11, GPIO_DHT11)
extern float temperature;
extern float humidity;
void DHT11_GPIO_Init(void);//引脚初始化
unsigned int DHT11_Read_Data(void);//读取模块数据
float Get_temperature(void);//返回读取模块后的温度数据
float Get_humidity(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
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
移植验证
在自己工程中的main主函数中,编写如下。
/******************************************************************************
* 测试硬件:立创开发板·GD32E230C8T6 使用主频72Mhz 晶振8Mhz
* 版 本 号: V1.0
* 修改作者: www.lckfb.com
* 修改日期: 2023年11月02日
* 功能介绍:
*****************************************************************************
* 梁山派软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:club.szlcsc.com
* 其余模块移植手册:【立创·GD32E230C8T6开发板】模块移植手册
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
******************************************************************************/
#include "gd32e23x.h"
#include "systick.h"
#include <stdio.h>
#include "bsp_dht11.h"
#include "bsp_usart.h"
int main(void)
{
systick_config();
usart_gpio_config(115200);
DHT11_GPIO_Init(); //DHT11引脚初始化
delay_1ms(1000);
printf("DHT11 demo start\r\n");
while(1)
{
//读取模块数据
DHT11_Read_Data();
//显示读取后的温度数据
printf("temperature = %.2f\r\n", Get_temperature() );
//显示读取后的湿度数据
printf("humidity = %.1f\r\n", Get_humidity() );
delay_1ms(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
30
31
32
33
34
35
36
37
38
39
40
移植现象