DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。其成本低、长期稳定、可以测量相对湿度和温度测量,并可以只使用一根数据线进行温湿度采集。
一、模块来源
二、规格参数
工作电压:3-5.5V
工作电流:1MA
测量分辨率:8 bit
湿度量程: 20 - 90 %RH
湿度精度:±5 %RH
温度量程: 0 - 50 ℃
温度精度:±2 ℃
通信协议:单总线
管脚数量:3 Pin(2.54mm间距排针)
以上信息见厂家资料文件
三、移植过程
我们的目标是将例程移植至MSPM0G3507开发板上【实现读取温湿度的功能】。首先要获取资料,查看数据手册应如何实现读取数据,再移植至我们的工程。
1、查看资料
DHT11使用的是单总线通信,即发送数据与接收数据都在一根数据线上,通过规定的时序进行控制。
从左向右看,时序一开始,主机信号就保持着高电平,所以引脚初始化完毕时,及时给引脚输出高电平。因为模块的数据线要求空闲时,要保持高电平状态。(其实模块上已经接了上拉电阻,使数据线一直保持高电平)
根据时序图可以知道,主机(开发板)发送一次开始信号,待主机开始信号结束后,DHT11 发送响应信号,送出 温湿度数据,并触发一次数据采集给下一次数据读取作准备。因此完成一次数据读取需要进行起始信号、响应信号、数据接收、结束信号。
读取数据步骤:
- 起始信号:主机(开发板)接入数据线的I/O输出低电平,且低电平保持时间不能小于 18ms。
- 响应信号:等待模块的响应信号到来。将数据线改为输入模式,如果接入到低电平,说明接收到模块的响应。
- 数据传输:主机接收模块发送的40位数据,其中,位数据 ‘0’ 表示54us的低电平,27us的高电平;位数据 ‘1’ 表示54us的低电平,74us的高电平。两个格式的分辨主要是高电平的输出时长不同。
- 结束信号:模块的数据线输出 40 位数据后,是以低电平结束,它会继续输出低电平 54 微秒后转为输入状态,主机需要转为输出状态,输出高电平释放总线。
DHT11_GPIO_Mode_OUT();//转为输出模式
DATA_GPIO_OUT(1);//主机释放总线
2
数据接收完成,但是这40位数据要如何转化为温湿度数据?并如何保证传输的数据没有错误?
DHT11模块一次完整的数据传输为40bit,高位先出。 数据格式:
INFO
湿度小数部分数据一直为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,两者不一致说明数据不准确,丢弃这次数据,重新接收。
2、引脚选择
VCC | 5V |
DAT | GPIO13 |
GND | GND |
接下来我们配置 SYSCONFIG
- 双击 c2000.syscfg 文件,打开它。
- 点击 ADD 添加GPIO配置
- 添加配置【根据下方图片进行添加】
Ctrl + S
保存配置文件Ctrl + B
构建工一次工程(可能会报错,我们不用管!)然后我们所有设定的引脚和功能就会在 board.h 中定义。因为这个文件我们包含进了 tjx_init.h 所以我们只需要引用 tjx_init.h 即可。【这里的 tjx_init.h 就充当了芯片头文件的作用】
3、代码编写
我们在工程中新建 module_driver
,并在其中新建两个文件 bsp_dht11.c
和 bsp_dht11.h
将头文件路径添加到编译器中
在文件bsp_dht11.c中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#include "bsp_dht11.h"
#include "stdio.h"
#define DHT11_DEBUG 0 // 调试信息 1:开启 0:关闭
#define DHT11_TIMEOUT 1000 // 超时阈值
float temperature = 0;
float humidity = 0;
/******************************************************************
* 函 数 名 称:DHT11_GPIO_Mode_OUT
* 函 数 说 明:配置DHT11的数据引脚为输出模式
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void DHT11_GPIO_Mode_OUT(void)
{
EALLOW;
GPIO_setDirectionMode(DHT11_DAT, GPIO_DIR_MODE_OUT);
EDIS;
}
/******************************************************************
* 函 数 名 称:DHT11_GPIO_Mode_IN
* 函 数 说 明:配置DHT11的数据引脚为输入模式
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void DHT11_GPIO_Mode_IN(void)
{
EALLOW;
GPIO_setDirectionMode(DHT11_DAT, GPIO_DIR_MODE_IN);
EDIS;
}
/******************************************************************
* 函 数 名 称:DHT11_Start
* 函 数 说 明:开始DHT11测量
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:无
******************************************************************/
void DHT11_Start(void)
{
DHT11_GPIO_Mode_OUT(); // 输出模式
DATA_GPIO_OUT(1);
DATA_GPIO_OUT(0);
delay_ms(19); // 保持18+ms低电平
DATA_GPIO_OUT(1);
delay_us(25); // 主机释放总线
DHT11_GPIO_Mode_IN(); // 切换输入模式
}
/******************************************************************
* 函 数 名 称:DHT11_CheckResponse
* 函 数 说 明:检查DHT11从机的相应是否正确
* 函 数 形 参:无
* 函 数 返 回:1:正确 0:错误
* 作 者:LC
* 备 注:无
******************************************************************/
uint8_t DHT11_CheckResponse(void)
{
uint32_t timeout = 0;
// 等待从机响应发送电平响应(低电平)(80µs)
timeout = DHT11_TIMEOUT;
while(DATA_GPIO_IN && timeout--)
{
if(timeout == 0)
{
lc_printf("DHT11_CheckResponse Failed[1]!!\r\n");
return 0; // 失败
}
}
// 等待从机响应发送电平响应(高电平)(80µs)
timeout = DHT11_TIMEOUT;
while((!DATA_GPIO_IN) && timeout--)
{
if(timeout == 0)
{
lc_printf("DHT11_CheckResponse Failed[2]!!\r\n");
return 0; // 失败
}
}
// 进入前导低电平
timeout = DHT11_TIMEOUT;
while(DATA_GPIO_IN && timeout--)
{
if(timeout == 0)
{
lc_printf("DHT11_CheckResponse Failed[3]!!\r\n");
return 0; // 失败
}
}
return 1;
}
/******************************************************************
* 函 数 名 称:DHT11_ReadBit
* 函 数 说 明:读取一位数据位
* 函 数 形 参:无
* 函 数 返 回:0 或 1
* 作 者:LC
* 备 注:无
******************************************************************/
uint8_t DHT11_ReadBit(void)
{
uint8_t bit = 0;
uint8_t timeCount = 0;
uint32_t timeout;
// 等待前导低电平过去
// 等待信号线由低变高
timeout = DHT11_TIMEOUT;
while((!DATA_GPIO_IN) && timeout--)
{
if(timeout == 0)
{
lc_printf("DHT11_ReadBit Failed[1]!!\r\n");
return 0;
}
}
// 判断是0还是1?
timeout = DHT11_TIMEOUT;
while(DATA_GPIO_IN && timeout--)
{
timeCount++;
delay_us(1);
if(timeout == 0)
{
lc_printf("DHT11_ReadBit Failed[2]!!\r\n");
return 0; // 失败
}
}
// 只要大于30us的高电平即可判断为数据1
if(timeCount >= 30)
bit = 1; // 数据1
else
bit = 0; // 数据0
return bit;
}
/******************************************************************
* 函 数 名 称:DHT11_Read_Data
* 函 数 说 明:根据时序读取温湿度数据
* 函 数 形 参:无
* 函 数 返 回:0=数据校验失败 其他=错误
* 作 者:LC
* 备 注:无
******************************************************************/
unsigned int DHT11_Read_Data(void)
{
int i;
uint8_t data[5] = {0};
uint64_t val = 0;
// 开始起始信号
DHT11_Start();
// 检查响应是否合规
if(0 == DHT11_CheckResponse())
{
lc_printf("DHT11_CheckResponse Failed!!\r\n");
return 0;
}
// 数据读取核心(40-bit)
for(i = 0; i < 40; i++)
{
val <<= 1;
val |= DHT11_ReadBit();
}
// 校验与数据提取
data[0] = (val >> 32) & 0xFF; // 湿度整数
data[1] = (val >> 24) & 0xFF; // 湿度小数
data[2] = (val >> 16) & 0xFF; // 温度整数
data[3] = (val >> 8) & 0xFF; // 温度小数
data[4] = val & 0xFF; // 校验和
#if DHT11_DEBUG
lc_printf("data[0] = %d\r\n",data[0]);
lc_printf("data[1] = %d\r\n",data[1]);
lc_printf("data[2] = %d\r\n",data[2]);
lc_printf("data[3] = %d\r\n",data[3]);
lc_printf("data[4] = %d\r\n",data[4]);
#endif
// 校验计算:前4字节和 = 第5字节
if ((data[4] != (data[0] + data[1] + data[2] + data[3])) ||
(data[4] == 0)) {
lc_printf("CheckSum Failed!!!\r\n");
return 0; // 校验失败
}
// 保存温湿度
humidity = data[0] + (data[1] * 0.1f); // 湿度(%)
temperature = data[2] + (data[3] * 0.1f); // 温度(℃)
#if DHT11_DEBUG
lc_printf("T: %d\r\n",(int)temperature);
lc_printf("H: %d\r\n",(int)humidity);
#endif
return 1;
}
/******************************************************************
* 函 数 名 称:Get_temperature
* 函 数 说 明:获取温度数据
* 函 数 形 参:无
* 函 数 返 回:温度值
* 作 者:LC
* 备 注:使用前必须先调用 DHT11_Read_Data 读取有数据
******************************************************************/
float Get_temperature(void)
{
return temperature;
}
/******************************************************************
* 函 数 名 称:Get_humidity
* 函 数 说 明:获取湿度数据
* 函 数 形 参:无
* 函 数 返 回:湿度值
* 作 者:LC
* 备 注:使用前必须先调用 DHT11_Read_Data 读取有数据
******************************************************************/
float Get_humidity(void)
{
return humidity;
}
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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
在文件bsp_dht11.h中,编写如下代码。
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 文档网站:wiki.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 嘉立创社区问答:https://www.jlc-bbs.com/lckfb
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*/
#ifndef __BSP_DHT11_H__
#define __BSP_DHT11_H__
#include "tjx_init.h"
//设置DHT11输出高或低电平
#define DATA_GPIO_OUT(x) GPIO_writePin(DHT11_DAT, x)
//获取DHT11数据引脚高低电平状态
#define DATA_GPIO_IN GPIO_readPin(DHT11_DAT)
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
四、移植验证
在 empty_driverlib_main.c
中输入代码如下:
#include "driverlib.h"
#include "device.h"
#include "board.h"
#include "c2000ware_libraries.h"
#include "tjx_init.h"
#include "bsp_dht11.h"
void main(void)
{
/* The initialization code automatically generated by CCS [Start] */
Device_init();
Device_initGPIO();
Interrupt_initModule();
Interrupt_initVectorTable();
Board_init();
C2000Ware_libraries_init();
EINT;
ERTM;
/* The initialization code automatically generated by CCS [End] */
lc_printf("\r\n= = = = = = = = = = = = = = = = = = = = = = = = =\r\n");
lc_printf("\r\n=== Welcome to use the LC-TJX-TMS320F28P550 ====\r\n");
lc_printf("\r\n============== www.lckfb.com ===================\r\n");
lc_printf("\r\n============== wiki.lckfb.com ==================\r\n");
lc_printf("\r\n= = = = = = = = = = = = = = = = = = = = = = = = =\r\n");
while(1)
{
float temp = 0.0;
float humi = 0.0;
int ret = 0;
// 从传感器读取数据
ret = DHT11_Read_Data();
temp = Get_temperature();
humi = Get_humidity();
if(ret)
{
lc_printf("\nTemperature == %d.%02d\r\n", (int)temp, (int)(temp*100)%100);
lc_printf("Humidity == %d.%02d\r\n", (int)humi, (int)(humi*100)%100);
}
else
{
lc_printf("Read Error!!\r\n");
}
// RGB的B灯亮起,G灯熄灭
GPIO_writePin(RGB_B, 0);
GPIO_writePin(RGB_G, 1);
delay_ms(500);
// RGB的G灯亮起,B灯熄灭
GPIO_writePin(RGB_B, 1);
GPIO_writePin(RGB_G, 0);
delay_ms(500);
}
}
__interrupt void INT_Debug_Serial_RX_ISR(void)
{
//清除接收中断标志位
SCI_clearInterruptStatus(SCIA_BASE, SCI_INT_RXFF);
//清除中断标志位
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}
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
上电效果:
【代码下载】
- 跳转到
下载中心
去下载CCS模块移植代码:【点击跳转🚀】