2.51 AHT21 温湿度传感器
2.51.1 模块来源
采购链接: AHT21 数字温湿度传感器模块 AHT21B I2C 通讯响应迅速 抗干扰强 资料下载链接: https://pan.baidu.com/s/12rCrA8ozeorLzBcYHk-PPg 提取码:CJ68
**图 2.51.1-1 产品实物展示**2.51.2 规格参数
**工作电压:**2.2-5.5V **工作电流:**250~980uA 温度测量范围:-40~80℃ 温度测量精度:±0.5℃ **湿度测量范围:**0~100%RH 湿度测量精度:±3%RH **通信方式: **IIC **管脚数量:**4 Pin 文件 2.51.2-1 产品规格书
2.51.3 移植过程
我们的目标是在梁山派 GD32F470 上能够测量温湿度的功能。首先要获取资料,查看数据手册应如何实现,再移植至我们的工程。
2.51.3.1 查看资料
模块应用电路
AHT21 地址
数据手册上说明,在启动传输后,随后传输的 IIC 首字节包括 7 位的 IIC 设备地址 0x38 和一个 SDA 方向位 x(读 R:‘1',写 W:‘0’)。所以根据是写命令还是读命令又分有两个地址。写时的地址:0X70;读时的地址:0X71。
传感器读取流程
- 上电后要等待不少于 100ms,读取温湿度值之前,通过发送 0x71 获取一个字节的 状态字,如果状态字和 0x18 相与后不等于 0x18,初始化 0x1B、0x1C、0x1E 寄存器,详细 初始化流程请参照我司官网例程;如果相等,执行下一步。
- 2.等待 10ms 发送 0xAC 命令(触发测量),此命令参数有两个字节,第一个字节为 0x33, 第二个字节为 0x00。
- 3.等待 80ms 待测量完成,如果读取状态字 Bit[7]为 0,表示测量完成,然后可以连续 读取六个字节;否则继续等待。
- 4.当接收完六个字节后,紧接着下一个字节是 CRC 校验数据,用户可以根据需要读 出,如果接收端需要 CRC 校验,则在接收完第六个字节后发 ACK 应答,否则发 NACK 结束, CRC 初始值为 0XFF,CRC8 校验多项式为: CRC[7:0]=1+x 4 + x 5 + x 8 5.计算温湿度值。
注:在第一步的校准状态检验只需要上电时检查,在正常采集过程无需操作。
传感器在采集时需要时间,主机发出测量指令(0xAC)后,延时 80 毫秒以上再读 取转换后的数据并判断返回的状态位是否正常。若状态比特位[Bit7]为 0 代表数据可正常读取,为 1 时传感器为忙状态,主机需要等待数据处理完成
数据处理
我们接收完成数据之后,还要将数据进行整理,再转换为我们实际的温湿度数据。
其中的 Srh、St 代表的是读取到的 20 位数据。
2.51.3.2 引脚选择
######### AHT21 | ######### 立创·梁山派 | ######### 接线图 |
---|
2.51.3.3 移植至工程
移植步骤中的导入.c 和.h 文件与上一节相同,只是将.c 和.h 文件更改为 bsp_aht21.c 与 bsp_aht21.h。见 2.2.3.3 移植至工程。这里不再过多讲述。移植完成后面修改相关代码。
在文件 bsp_aht21.c 中,编写如下代码。
/********************************************************************************
* 测试硬件:立创·梁山派开发板GD32F470ZGT6 使用主频200Mhz 晶振25Mhz
* 版 本 号: V1.0
* 修改作者: LCKFB
* 修改日期: 2023年08月04日
* 功能介绍:
******************************************************************************
* 梁山派软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:club.szlcsc.com
* 其余模块移植手册:https://dri8c0qdfb.feishu.cn/docx/EGRVdxunnohkrNxItYTcrwAnnHe
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*********************************************************************************/
#include "bsp_aht21.h"
#include "systick.h"
#include "bsp_usart.h"
#include "stdio.h"
static float temperature = 0;
static float humidity = 0;
/******************************************************************
* 函 数 名 称:aht21_gpio_init
* 函 数 说 明:对AHT21的IIC引脚初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LCKFB
* 备 注:
******************************************************************/
void aht21_gpio_init(void)
{
//打开SDA与SCL的引脚时钟
rcu_periph_clock_enable(RCU_AHT21_SCL);
rcu_periph_clock_enable(RCU_AHT21_SDA);
//设置SCL引脚模式为上拉输出
gpio_mode_set(PORT_AHT21_SCL, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_AHT21_SCL);
//设置引脚为开漏模式,翻转速度2MHz
gpio_output_options_set(PORT_AHT21_SCL, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO_AHT21_SCL);
//设置引脚输出高电平SCL等待信号
gpio_bit_write(PORT_AHT21_SCL, GPIO_AHT21_SCL, SET);
//设置SDA引脚
gpio_mode_set(PORT_AHT21_SDA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_AHT21_SDA);
gpio_output_options_set(PORT_AHT21_SDA, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO_AHT21_SDA);
gpio_bit_write(PORT_AHT21_SDA, GPIO_AHT21_SDA, SET);
}
/******************************************************************
* 函 数 名 称:IIC_Start
* 函 数 说 明:发送起始信号
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LCKFB
* 备 注:无
******************************************************************/
void IIC_Start(void)
{
SDA_OUT();
SDA(1);
SCL(1);
delay_1us(5);
SDA(0);
delay_1us(5);
SCL(0);
delay_1us(5);
}
/******************************************************************
* 函 数 名 称:IIC_Stop
* 函 数 说 明:停止信号
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LCKFB
* 备 注:无
******************************************************************/
void IIC_Stop(void)
{
SDA_OUT();
SCL(0);
SDA(0);
SCL(1);
delay_1us(5);
SDA(1);
delay_1us(5);
}
/******************************************************************
* 函 数 名 称:IIC_Send_Nack
* 函 数 说 明:发送非应答
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LCKFB
* 备 注:无
******************************************************************/
void IIC_Send_Nack(void)
{
SDA_OUT();
SCL(0);
SDA(0);
SDA(1);
SCL(1);
delay_1us(5);
SCL(0);
SDA(0);
}
/******************************************************************
* 函 数 名 称:IIC_Send_Ack
* 函 数 说 明:发送应答
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LCKFB
* 备 注:无
******************************************************************/
void IIC_Send_Ack(void)
{
SDA_OUT();
SCL(0);
SDA(1);
SDA(0);
SCL(1);
delay_1us(5);
SCL(0);
SDA(1);
}
/**********************************************************
* 函 数 名 称:I2C_WaitAck
* 函 数 功 能:等待从机应答
* 传 入 参 数:无
* 函 数 返 回:1=非应答 0=应答
* 作 者:LCKFB
* 备 注:无
**********************************************************/
unsigned char I2C_WaitAck(void)
{
char ack = 0;
unsigned char ack_flag = 10;
SCL(0);
SDA(1);
SDA_IN();
delay_1us(5);
SCL(1);
delay_1us(5);
while( (GETSDA()==1) && ( ack_flag ) )
{
ack_flag--;
delay_1us(5);
}
//非应答
if( ack_flag <= 0 )
{
IIC_Stop();
return 1;
}
else//应答
{
SCL(0);
SDA_OUT();
}
return ack;
}
/******************************************************************
* 函 数 名 称:IIC_Send_Byte
* 函 数 说 明:发送一个字节
* 函 数 形 参:dat:发送的字节数据
* 函 数 返 回:无
* 作 者:LCKFB
* 备 注:无
******************************************************************/
void IIC_Send_Byte(uint8_t dat)
{
int i = 0;
SDA_OUT();
SCL(0);
for( i = 0; i < 8; i++ )
{
SDA( (dat & 0x80) >> 7 );
delay_1us(1);
SCL(1);
delay_1us(5);
SCL(0);
delay_1us(5);
dat<<=1;
}
}
/******************************************************************
* 函 数 名 称:IIC_Read_Byte
* 函 数 说 明:接收一个字节
* 函 数 形 参:无
* 函 数 返 回:接收到的数据
* 作 者:LCKFB
* 备 注:无
******************************************************************/
unsigned char IIC_Read_Byte(void)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
SCL(0);
delay_1us(5);
SCL(1);
delay_1us(5);
receive<<=1;
if( GETSDA() )
{
receive |= 1;
}
}
SCL(0);
return receive;
}
/******************************************************************
* 函 数 名 称:aht21_read_status
* 函 数 说 明:读取AHT21的状态寄存器
* 函 数 形 参:无
* 函 数 返 回:读取到的状态数据
* 作 者:LCKFB
* 备 注:无
******************************************************************/
uint8_t aht21_read_status(void)
{
uint8_t status_register_address = 0x71;
uint8_t status_byte;
IIC_Start();
IIC_Send_Byte( status_register_address );
if( I2C_WaitAck() == 1 ) printf("warning -1\r\n");
status_byte = IIC_Read_Byte();
IIC_Send_Nack();
IIC_Stop();
return status_byte;
}
/******************************************************************
* 函 数 名 称:aht21_send_gather_command
* 函 数 说 明:向AHT21发送采集命令
* 函 数 形 参:无
* 函 数 返 回:1:器件识别失败
* 2:发送采集命令失败
* 3:发送数据1失败
* 4:发送数据2失败
* 作 者:LCKFB
* 备 注:无
******************************************************************/
uint8_t aht21_send_gather_command(void)
{
uint8_t device_addr = 0x70;//器件地址
uint8_t gather_command = 0xac;//采集命令
uint8_t gather_command_parameter_1 = 0x33;//采集参数1
uint8_t gather_command_parameter_2 = 0x00;//采集参数2
IIC_Start();
IIC_Send_Byte(device_addr);//发送器件地址
if( I2C_WaitAck() == 1 ) return 1;
IIC_Send_Byte(gather_command);//发送采集命令
if( I2C_WaitAck() == 1 ) return 2;
IIC_Send_Byte(gather_command_parameter_1);//发送采集参数1
if( I2C_WaitAck() == 1 ) return 3;
IIC_Send_Byte(gather_command_parameter_2);//发送采集参数2
if( I2C_WaitAck() == 1 ) return 4;
IIC_Stop();
return 0;
}
/******************************************************************
* 函 数 名 称:aht21_device_init
* 函 数 说 明:通过命令字节初始化AHT21
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LCKFB
* 备 注:无
******************************************************************/
void aht21_device_init(void)
{
uint8_t device_addr = 0x70;//器件地址
uint8_t init_command = 0xBE;//初始化命令
uint8_t init_command_parameter_1 = 0x08;//采集参数1
uint8_t init_command_parameter_2 = 0x00;//采集参数2
IIC_Start();
IIC_Send_Byte(device_addr);//发送器件地址
if( I2C_WaitAck() == 1 ) printf("warning -5\r\n");
IIC_Send_Byte(init_command);//发送初始化命令
if( I2C_WaitAck() == 1 ) printf("warning -6\r\n");
IIC_Send_Byte(init_command_parameter_1);//发送初始化参数1
if( I2C_WaitAck() == 1 ) printf("warning -7\r\n");
IIC_Send_Byte(init_command_parameter_2);//发送初始化参数2
if( I2C_WaitAck() == 1 ) printf("warning -8\r\n");
IIC_Stop();
}
/******************************************************************
* 函 数 名 称:aht21_read_data
* 函 数 说 明:读取温湿度
* 函 数 形 参:无
* 函 数 返 回:1:未校准 2:读取超时 0:读取成功
* 作 者:LCKFB
* 备 注:无
******************************************************************/
char aht21_read_data(void)
{
uint8_t data[6] = {0};
uint32_t temp = 0;
uint8_t aht21_status_byte = 0;
uint8_t timeout = 0;
//读取AHT21的状态
aht21_status_byte = aht21_read_status();
//如果未校准,则返回1
if( (aht21_status_byte & (1<<3)) == 0 )
{
aht21_device_init();
delay_1ms(50);
return 1;
}
//发送采集命令
aht21_send_gather_command();
do
{
delay_1ms(1);
timeout++;
//读取AHT21的状态
aht21_status_byte = aht21_read_status();
}while( ( ( aht21_status_byte & (1<<7) ) != 0 ) && ( timeout >= 80 ) );
//如果读取超时,则返回2
if( timeout >= 80 ) return 2;
IIC_Start();
IIC_Send_Byte(0x71);
if( I2C_WaitAck() == 1 ) printf("error -1\r\n");
IIC_Read_Byte();//读取状态,不需要保存
IIC_Send_Ack();
//读取6位数据
data[0] = IIC_Read_Byte();
IIC_Send_Ack();
data[1] = IIC_Read_Byte();
IIC_Send_Ack();
data[2] = IIC_Read_Byte();
IIC_Send_Ack();
data[3] = IIC_Read_Byte();
IIC_Send_Ack();
data[4] = IIC_Read_Byte();
IIC_Send_Ack();
data[5] = IIC_Read_Byte();
IIC_Send_Nack();
IIC_Stop();
//整合湿度数据
temp = (data[0]<<12) | (data[1]<<4);
temp = temp | (data[2]>>4);
//换算湿度数据
//2的20次方 = 1048576
humidity = temp / 1048576.0 * 100.0;
//整合湿度数据
temp = ( (data[2]&0x0f)<< 16 ) | (data[3]<<8);
temp = temp | data[4];
//换算湿度数据
//2的20次方 = 1048576
temperature = temp / 1048576.0 * 200.0 - 50;
return 0;
}
/******************************************************************
* 函 数 名 称:get_temperature
* 函 数 说 明:返回读取过的温度
* 函 数 形 参:无
* 函 数 返 回:温度值
* 作 者:LCKFB
* 备 注:使用前,请确保调用 aht21_read_data 采集过数据
******************************************************************/
float get_temperature(void)
{
return temperature;
}
/******************************************************************
* 函 数 名 称:get_humidity
* 函 数 说 明:返回读取过的湿度
* 函 数 形 参:无
* 函 数 返 回:湿度值
* 作 者:LCKFB
* 备 注:使用前,请确保调用 aht21_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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
在文件 bsp_aht21.h 中,编写如下代码。
/********************************************************************************
* 测试硬件:立创·梁山派开发板GD32F470ZGT6 使用主频200Mhz 晶振25Mhz
* 版 本 号: V1.0
* 修改作者: LCKFB
* 修改日期: 2023年08月04日
* 功能介绍:
******************************************************************************
* 梁山派软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:club.szlcsc.com
* 其余模块移植手册:https://dri8c0qdfb.feishu.cn/docx/EGRVdxunnohkrNxItYTcrwAnnHe
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*********************************************************************************/
#ifndef _BSP_AHT21_H_
#define _BSP_AHT21_H_
#include "gd32f4xx.h"
#define RCU_AHT21_SCL RCU_GPIOD
#define PORT_AHT21_SCL GPIOD
#define GPIO_AHT21_SCL GPIO_PIN_4
#define RCU_AHT21_SDA RCU_GPIOD
#define PORT_AHT21_SDA GPIOD
#define GPIO_AHT21_SDA GPIO_PIN_5
#define SDA_IN() {gpio_mode_set(PORT_AHT21_SDA, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_AHT21_SDA);} //SDA输入模式
#define SDA_OUT() {gpio_mode_set(PORT_AHT21_SDA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_AHT21_SDA);} //SDA输出模式
#define SCL(BIT) gpio_bit_write( PORT_AHT21_SCL, GPIO_AHT21_SCL, BIT?SET:RESET)
#define SDA(BIT) gpio_bit_write( PORT_AHT21_SDA, GPIO_AHT21_SDA, BIT?SET:RESET)
#define GETSDA() gpio_input_bit_get( PORT_AHT21_SDA, GPIO_AHT21_SDA)
void aht21_gpio_init(void);
char aht21_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
2.51.4 移植验证
在自己工程中的 main 主函数中,编写如下。
/********************************************************************************
* 测试硬件:立创·梁山派开发板GD32F470ZGT6 使用主频200Mhz 晶振25Mhz
* 版 本 号: V1.0
* 修改作者: LC
* 修改日期: 2023年06月12日
* 功能介绍: 增加AHT21驱动、增加1us延时、增加串口0调试、增加GD32串口标准库
******************************************************************************
* 梁山派软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:club.szlcsc.com
* 其余模块移植手册:【立创·梁山派开发板】模块移植手册
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
*********************************************************************************/
#include "gd32f4xx.h"
#include "systick.h"
#include "bsp_usart.h"
#include "bsp_aht21.h"
#include "stdio.h"
/******************************************************************
* 函 数 名 称:main
* 函 数 说 明:主函数
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者: LC
* 备 注:无
******************************************************************/
int main(void)
{
float Float_Num=0;
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
//滴答定时器初始化 1us
systick_config();
//串口0初始化(调试)
usart_gpio_config( 115200U );
//AHT21初始化
aht21_gpio_init();
delay_1ms(1000);
while(1)
{
printf("%d\r\n",aht21_read_data());
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
41
42
43
44
45
46
47
48
49
50
51
52
53
移植现象:串口输出采集到的温湿度。
移植成功示例,见文件 2.51.4-1 。
文件 2.51.4-1 移植成功示例