AGS10是一款采用数字信号输出的MEMS TVOC传感器。配置了专用的数字模块采集技术和气体感应传感技术,确保了产品具有极高的可靠性与卓越的长期稳定性,同时具有低功耗、高灵敏度、快速响应、成本低、驱动电路简单等特点。
一、模块来源
采购链接:
二、规格参数
工作电压 : 3.0-6.0 V
典型功率 : 75mW
采样周期 : ≥2s
接口速率 :I2C从机模式(≤15kHz)
预热时间 : ≥120s
工作温度 : 0~50℃
工作湿度 : 0~95%RH
寿命 : >5年(25℃,清洁空气中)
输出单位 : ppb
测量范围 : 0~99999 ppb
典型精度( 25℃/50%RH): 25% 读数
标准测试气体 : 乙醇
模块尺寸:15*10.6mm
以上信息见厂家资料文件
三、移植过程
1、查看资料
工作原理
AGS10传感器采用标准I 2C通信协议,适应多种设备。IIC的物理接口包含串行数据信号(SDA)与串行时钟信号(SCL)两个接口。两个接口需通过1kΩ~10kΩ电阻上拉至VDD。SDA用于读、写传感器数据。SCL上电必须保持高电平直到进行IIC通信开始,否则会引起I 2C通讯不良。当I 2C通信时SCL用于主机与传感器之间的通讯同步。多个I2C设备可以共享总线,但是只能允许一个主机设备出现在总线上。既然采用的是IIC,那么我们需要知道它的IIC通信地址。
读取TVOC数据的步骤:
2、引脚选择
3、移植至工程
移植步骤中的导入.c和.h文件与传感器章节的【DHT11温湿度传感器】相同,只是将.c和.h文件更改为bsp_ags10.c与bsp_ags10.h。这里不再过多讲述,移植完成后面修改相关代码。
在文件bsp_ags10.c中,编写如下代码。
c
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
* Change Logs:
* Date Author Notes
* 2024-04-01 LCKFB-LP first version
*/
#include "bsp_ags10.h"
#include "board.h"
/******************************************************************
* 函 数 名 称:ags10_gpio_init
* 函 数 说 明:对AGS10的IIC引脚初始化
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:LC
* 备 注:
******************************************************************/
void ags10_gpio_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_AGS10, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_SDA|GPIO_SCL;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(PORT_AGS10, &GPIO_InitStructure);
GPIO_SetBits(PORT_AGS10, GPIO_SDA|GPIO_SCL);
}
//起始信号
void AGS10_IIC_Start(void)
{
AGS10_SDA_OUT();
AGS10_SDA(1);
AGS10_SCL(1);
delay_1us(5);
AGS10_SDA(0);
delay_1us(5);
AGS10_SCL(0);
delay_1us(5);
}
//停止信号
void AGS10_IIC_Stop(void)
{
AGS10_SDA_OUT();
AGS10_SCL(0);
AGS10_SDA(0);
AGS10_SCL(1);
delay_1us(5);
AGS10_SDA(1);
delay_1us(5);
}
//发送非应答
void AGS10_IIC_Send_Nack(void)
{
AGS10_SDA_OUT();
AGS10_SCL(0);
AGS10_SDA(0);
AGS10_SDA(1);
AGS10_SCL(1);
delay_1us(5);
AGS10_SCL(0);
AGS10_SDA(0);
}
//发送应答
void AGS10_IIC_Send_Ack(void)
{
AGS10_SDA_OUT();
AGS10_SCL(0);
AGS10_SDA(1);
AGS10_SDA(0);
AGS10_SCL(1);
delay_1us(5);
AGS10_SCL(0);
AGS10_SDA(1);
}
/**********************************************************
* 函 数 名 称:I2C_WaitAck
* 函 数 功 能:等待从机应答
* 传 入 参 数:无
* 函 数 返 回:1=非应答 0=应答
* 作 者:LC
* 备 注:无
**********************************************************/
unsigned char AGS10_I2C_WaitAck(void)
{
char ack = 0;
unsigned char ack_flag = 10;
AGS10_SCL(0);
AGS10_SDA(1);
AGS10_SDA_IN();
delay_1us(5);
AGS10_SCL(1);
delay_1us(5);
while( (AGS10_GETSDA()==1) && ( ack_flag ) )
{
ack_flag--;
delay_1us(5);
}
//非应答
if( ack_flag <= 0 )
{
AGS10_IIC_Stop();
return 1;
}
else//应答
{
AGS10_SCL(0);
AGS10_SDA_OUT();
}
return ack;
}
//发送一个字节
void AGS10_IIC_Send_Byte(uint8_t dat)
{
int i = 0;
AGS10_SDA_OUT();
AGS10_SCL(0);
for( i = 0; i < 8; i++ )
{
AGS10_SDA( (dat & 0x80) >> 7 );
delay_1us(1);
AGS10_SCL(1);
delay_1us(5);
AGS10_SCL(0);
delay_1us(5);
dat<<=1;
}
}
//接收一个字节
unsigned char AGS10_IIC_Read_Byte(void)
{
unsigned char i,receive=0;
AGS10_SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
AGS10_SCL(0);
delay_1us(5);
AGS10_SCL(1);
delay_1us(5);
receive<<=1;
if( AGS10_GETSDA() )
{
receive |= 1;
}
}
AGS10_SCL(0);
return receive;
}
//********************************************************************
//函数名称:Calc_CRC8
//功能 :CRC8 计算,初值:0xFF,多项式:0x31(x8 + x5 + x4 +1)
//参数 :u8* dat:需要校验数据的首地址;u8 Num:CRC 校验数据长度
//返回 :crc:计算出的校验值
//********************************************************************
uint8_t Calc_CRC8(uint8_t *dat, uint8_t Num)
{
uint8_t i, byte, crc=0xFF;
for(byte=0; byte<Num; byte++)
{
crc ^= (dat[byte]);
for( i = 0; i < 8; i++ )
{
if(crc & 0x80) crc = ( crc << 1 ) ^ 0x31;
else crc = ( crc << 1 );
}
}
return crc;
}
/**********************************************************
* 函 数 名 称:ags10_read
* 函 数 功 能:读取AGS10的TVOC浓度数据
* 传 入 参 数:无
* 函 数 返 回:1: 通信失败
* 2:发送失败
* 3:等待超时
* 4: 校验失败
* 作 者:LCKFB
* 备 注:
**********************************************************/
uint32_t ags10_read(void)
{
uint8_t timeout = 0;
uint8_t data[5] = {0};
uint32_t TVOC_data = 0;
AGS10_IIC_Start();
AGS10_IIC_Send_Byte(0X34);
if( AGS10_I2C_WaitAck() == 1 ) return 1;
AGS10_IIC_Send_Byte(0X00);
if( AGS10_I2C_WaitAck() == 1 ) return 2;
AGS10_IIC_Stop();
do{
delay_1ms(1);
timeout++;
AGS10_IIC_Start();
AGS10_IIC_Send_Byte(0X35);
}while( (AGS10_I2C_WaitAck() == 1) && (timeout >= 50) );
//如果超时
if( timeout >= 50 ) return 3;
data[0] = AGS10_IIC_Read_Byte();
AGS10_IIC_Send_Ack();
data[1] = AGS10_IIC_Read_Byte();
AGS10_IIC_Send_Ack();
data[2] = AGS10_IIC_Read_Byte();
AGS10_IIC_Send_Ack();
data[3] = AGS10_IIC_Read_Byte();
AGS10_IIC_Send_Ack();
data[4] = AGS10_IIC_Read_Byte();
AGS10_IIC_Send_Nack();
AGS10_IIC_Stop();
if( Calc_CRC8(data,4) != data[4] )
{
// printf("Check failed\r\n");
return 4;
}
TVOC_data = (data[1]<<16) | (data[2]<<8) | data[3] ;
return TVOC_data;
}
1
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
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
在文件bsp_ags10.h中,编写如下代码。
c
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
* Change Logs:
* Date Author Notes
* 2024-04-01 LCKFB-LP first version
*/
#ifndef _BSP_AGS10_H_
#define _BSP_AGS10_H_
#include "stm32f10x.h"
//端口移植
#define RCC_AGS10 RCC_APB2Periph_GPIOB
#define PORT_AGS10 GPIOB
#define GPIO_SDA GPIO_Pin_8
#define GPIO_SCL GPIO_Pin_9
//设置SDA输出模式
#define AGS10_SDA_OUT() {\
GPIO_InitTypeDef GPIO_InitStructure;\
GPIO_InitStructure.GPIO_Pin = GPIO_SDA;\
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;\
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;\
GPIO_Init(PORT_AGS10, &GPIO_InitStructure);\
}
//设置SDA输入模式
#define AGS10_SDA_IN() {\
GPIO_InitTypeDef GPIO_InitStructure;\
GPIO_InitStructure.GPIO_Pin = GPIO_SDA;\
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;\
GPIO_Init(PORT_AGS10, &GPIO_InitStructure);\
}
//获取SDA引脚的电平变化
#define AGS10_GETSDA() GPIO_ReadInputDataBit(PORT_AGS10, GPIO_SDA)
//SDA与SCL输出
#define AGS10_SDA(x) GPIO_WriteBit(PORT_AGS10, GPIO_SDA, (x?Bit_SET:Bit_RESET) )
#define AGS10_SCL(x) GPIO_WriteBit(PORT_AGS10, GPIO_SCL, (x?Bit_SET:Bit_RESET) )
void ags10_gpio_init(void);
uint32_t ags10_read(void);
#endif
1
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
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
四、移植验证
在main.c中编写以下代码。
c
/*
* 立创开发板软硬件资料与相关扩展板软硬件资料官网全部开源
* 开发板官网:www.lckfb.com
* 技术支持常驻论坛,任何技术问题欢迎随时交流学习
* 立创论坛:https://oshwhub.com/forum
* 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
* 不靠卖板赚钱,以培养中国工程师为己任
* Change Logs:
* Date Author Notes
* 2024-04-01 LCKFB-LP first version
*/
#include "stm32f10x.h"
#include "board.h"
#include "bsp_uart.h"
#include "stdio.h"
#include "bsp_ags10.h"
int main(void)
{
board_init();
uart1_init(115200);
//AGS10有害气体传感器初始化
ags10_gpio_init();
printf("Start\r\n");
while(1)
{
//显示TVOC浓度
printf("TVOC = %d ppb\r\n",ags10_read() );
delay_1ms(1000);
}
}
1
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
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
上电效果:
模块代码下载链接: