简介
SGP30是一款单一芯片,上具有多个传感元件的金属氧化物气体传感器,内集成4个气体传感元件,具有完全校准的空气质量输出信号。另外,SGP易于集成,能够将金属氧化物气体传感器集成到移动设备中,为智能家居、家电和物联网应用中的环境监测开辟了新的可能性。SGP30模块通常包括一个集成的传感器芯片和相应的电路,使其能够方便地与微控制器连接。它通常通过I2C总线与微控制器通信,可以轻松地集成到各种不同的嵌入式系统中。
电气特征
1.供电电压3.3V或5V ;
2.IIC通信接口,输出TVOC和CO2eq信号
3.采用进口高灵敏SGP30甲醛传感器,芯片供电电压为1.8V;
4.功耗40mA;
5.板载1.8V LDO芯片为SGP30供电,所以输入电源可为3.3V或5V。
原理图
信号输出
SGP30是一款单一芯片,上具有多个传感元件的金属氧化物气体传感器,内集成4个气体传感元件,具有完全校准的空气质量输出信号,主要输出参数如下:
其中挥发有机物-TVOC测量范围:0-60000ppb;
CO2浓度测量范围:400-60000ppm。
设备通信
通讯时序
从传感器可以看到SDA方向。粗体SDA线由传感器控制;普通SDA线由微控制器控制。
注意,SDA有效读取时间是由前一个开关的下降沿触发的。
设备IIC地址
SGP30 I2C从机地址为0X58,则SGP30写地址为(0X58<<1)|0X00=0XB0,读地址为(0X58<<1)|0X01=0XB1。
测量通信
测量通信序列由START条件、I2C写头(7位I2C设备地址加上0作为写位)和16位测量命令组成。每个字节的正确接收由传感器指示。它把SDA引脚低(ACK位)后下降沿的第8 SCL时钟表示接收。接收到测量命令后,SGP30开始测量。
在传感器完成测量后,主机可以通过发送START条件和l2C读头来读取测量结果。传感器将确认接收到读报头,并以数据进行响应。响应数据长度如(测量命令)图所示,以数据字为单位,其中一个字由两个字节的数据和一个字节的CRC校验和组成。每个字节必须由微控制器以ACK条件确认,以便传感器继续发送数据。如果传感器在任何字节的数据之后没有收到来自主机的ACK,它将不会继续发送数据。
在接收到数据最后一个字的校验和后,必须发送XCK和STOP条件(如下图)。如果I2C主机对后续数据(例如CRC字节或后续数据字节)不感兴趣,则可以在任何数据字节之后使用XCK和STOP条件终止读取传输,以节省时间。
测量命令
上面测量命令中,主要用的两个:一个是0X2003为初始化命令,另一个是0X2008为获取采集数据。SGP获取数据的过程为:模块上电后发送0X2003进行初始化,初始化期间,CO2和TVOC固定为400和0,需要的时间在15秒左右,接着发送0X2008进行数据采集,采集时间也是差不多15秒左右,最后采集到的数据格式为:2位CO2数据+1位CO2CRC校验+2位TVOC数据+1位CRC校验。
校验和计算
硬件连接
STM32 | SGP30 | OLED |
---|---|---|
VCC | VCC | VCC |
GND | GND | GND |
PB9 | SCL | - |
PB8 | SDA | - |
PB6 | - | SCL |
PB5 | - | SDA |
代码
main.c
#include "stm32f10x.h"
#include "OLED_I2C.h"
#include "delay.h"
#include "SGP30.h"
#include "SGP30_IIC.h"
#include "bsp_usart.h"
#include <stdio.h>
uint16_t TVOC = 0, CO2 = 0;
uint8_t TVOC_Buf[20] = {0}, CO2_Buf[20] = {0};
uint8_t ID[6]={0};
uint8_t i = 0;
int main(void)
{
USART_Config();
DelayInit();
I2C_Configuration();
OLED_Init();
OLED_Fill(0x00);//全屏灭
SGP30_GPIO_Init();
SGP30_init();
SGP30_get_serial_id(ID);
for( i = 0; i < 6; i++)
{
printf("%02X", ID[i]);
}
printf("\r\n");
while(1)
{
SGP30_read(&CO2, &TVOC);
sprintf(CO2_Buf,"CO2:%d dppm ",CO2);
sprintf(TVOC_Buf,"TVOC:%d dppb ",TVOC);
printf("SGP30---");
Usart_SendString(DEBUG_USARTx,CO2_Buf);
Usart_SendString(DEBUG_USARTx,TVOC_Buf);
OLED_ShowString(2,0,CO2_Buf,2);
OLED_ShowString(4,2,TVOC_Buf,2);
DelayMs(500);
}
}
SGP 30.c
#include "SGP30.h"
#include "delay.h"
uint8_t SGP30_checksum(const uint8_t* buf, uint32_t len)
{
const uint8_t Polynomial = 0x31;
uint8_t Initialization = 0XFF;
uint8_t i = 0, k = 0;
while(i < len)
{
Initialization ^= buf[i++];
for(k = 0; k < 8; k++)
{
if(Initialization & 0X80)
Initialization = (Initialization << 1) ^ Polynomial;
else
Initialization = (Initialization << 1);
}
}
return Initialization;
}
int SGP30_get_serial_id(uint8_t id[6])
{
uint8_t CMD[2];
uint8_t buf[10];
uint8_t crc[3];
CMD[0] = (SGP30_CMD_GET_SERIAL_ID & 0XFF00) >> 8;
CMD[1] = (SGP30_CMD_GET_SERIAL_ID & 0X00FF);
// IIC_WriteBuf(SGP30_ADDR, CMD, 2);
// DELAY_US(500);
IIC_ReadDataBuf(SGP30_ADDRESS, CMD,buf, 9);
//IIC_ReadDataBlock(SGP30_ADDR, buf, 9);
// return -2;
crc[0] = buf[2];
crc[1] = buf[5];
crc[2] = buf[8];
id[0] = buf[0];
id[1] = buf[1];
id[2] = buf[3];
id[3] = buf[4];
id[4] = buf[6];
id[5] = buf[7];
if(
SGP30_checksum(&id[0], 2) != crc[0] ||
SGP30_checksum(&id[2], 2) != crc[1] ||
SGP30_checksum(&id[4], 2) != crc[2]
)
return -3;
return 0;
}
void SGP30_soft_reset(void)
{
IIC_WriteReg(SGP30_ADDRESS, 0x00, 0x06);
// uint8_t CMD[2];
// // uint8_t buf[10];
// CMD[0] = (SGP30_CMD_REAST & 0XFF00) >> 8;
// CMD[1] = (SGP30_CMD_REAST & 0X00FF);
// IIC_WriteBuf(SGP30_ADDR, CMD, 2);
}
int SGP30_init(void)
{
uint8_t CMD[2];
// 软件复位
// sgp30_soft_reset();
//
// // 等待复位完成
// DELAY_MS(50);
CMD[0] = (SGP30_CMD_INIT_AIR_QUALITY & 0XFF00) >> 8;
CMD[1] = (SGP30_CMD_INIT_AIR_QUALITY & 0X00FF);
// 初始化控制测量参数
IIC_WriteBuf(SGP30_ADDRESS, CMD, 2);
// IIC_WriteReg(SGP30_ADDR, 0x00, 0x06);
return 0;
}
int SGP30_read(uint16_t* CO2, uint16_t* TVOC)
{
uint8_t CMD[2];
uint8_t buf[8] = {0};
CMD[0] = (SGP30_CMD_MEASURE_AIR_QUALITY & 0XFF00) >> 8;
CMD[1] = (SGP30_CMD_MEASURE_AIR_QUALITY & 0X00FF);
IIC_WriteBuf(SGP30_ADDRESS, CMD, 2);
// 等待测量完成
DelayMs(10);
// 读取收到的数据
IIC_ReadDataBuf(SGP30_ADDRESS, CMD,buf, 6);
// 校验CRC
// if (sgp30_checksum(&buf[3], 2) != buf[5])
// return -3;
*CO2 = ((uint16_t)buf[0] << 8) | buf[1];
*TVOC = ((uint16_t)buf[3] << 8) | buf[4];
return 0;
}
结果
串口打印数据:
OLED显示数据:
总结
以上是基于STM32驱动SGP30传感器进行空气质量检测的一个原理应用和代码展示,使用时需要注意的是,上电初始化过程中,CO2和TVOC固定为400和0,直到CO2和TVOC不为400和0时才算初始化完成。此外,刚开始读取数据时,可能会有较大的波动,这是正常的,因为气体传感器较容易受环境影响,过一会就会趋于稳定。