STM32和ESP32分别驱动SGP30获取二氧化碳浓度

目录

1 SGP30介绍

2.STM32驱动代码

3.ESP32驱动代码


1 SGP30介绍

      SGP30是一种高性能气体传感器,用于检测室内空气中的二氧化碳(CO2)和挥发性有机化合物(TVOS)。它由Sensirion公司设计和生产,采用了最新的传感器技术和算法,能够提供准确可靠的气体测量数据。SGP30采用先进的MOX(金属氧化物)传感器技术,能够快速、准确地测量二氧化碳和挥发性有机化合物的浓度。它可以检测从室内空气中释放出的有害气体,例如甲醛、醇类、酮类和酯类化合物等。SGP30的测量范围广泛,可测量的CO2浓度范围为400ppm至60,000ppm,TVOS浓度范围为0ppb至60,000ppb。

       SGP30具有高灵敏度、低功耗和可靠性。它采用数字通信接口,可以轻松集成到各种应用中。此外,SGP30还具有温度和湿度补偿功能,可以提高测量的准确性和稳定性。SGP30广泛应用于室内空气质量监测、室外空气污染监测、智能家居系统、工业过程控制和航空航天等领域。它可以帮助用户实时监测和控制室内空气质量,提供一个舒适、健康的生活和工作环境。

      SGP30在智能家居、农业环境检测等相关课程设计或毕业设计中经常出现,作为一款检测精度高,检测速度快的传感器,下面将使用标准库读取SGP30二氧化碳的值,ESP32使用库读取SGP30的二氧化碳值与TVOC值。

2.STM32驱动代码

stm32与sgp30接线

PB0       SCL

PB1       SDA

VCC      VCC

GND      GND

stm32与oled屏幕接线

PB8       SCL

PB9        SDA

VCC       VCC

GND       GND

sgp30.c

#include "sgp30.h"
#include "Delay.h"



void SGP30_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(SGP30_SCL_GPIO_CLK | SGP30_SDA_GPIO_SDA, ENABLE);

  GPIO_InitStructure.GPIO_Pin = SGP30_SCL_GPIO_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(SGP30_SCL_GPIO_PORT, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = SGP30_SDA_GPIO_PIN;
  GPIO_Init(SGP30_SDA_GPIO_PORT, &GPIO_InitStructure);
}


void SDA_OUT(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = SGP30_SDA_GPIO_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(SGP30_SDA_GPIO_PORT, &GPIO_InitStructure);
}

void SDA_IN(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = SGP30_SDA_GPIO_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(SGP30_SDA_GPIO_PORT, &GPIO_InitStructure);
}

//产生IIC起始信号
void SGP30_IIC_Start(void)
{
  SDA_OUT();
  SGP30_SDA_HIGH;
  SGP30_SCL_HIGH;
  delay_us(20);

//  SGP30_SDA = 0;	//START:when CLK is high,DATA change form high to low
	SGP30_SDA_LOW;
  delay_us(20);
//  SGP30_SCL = 0; 	//钳住I2C总线,准备发送或接收数据
	SGP30_SCL_LOW;
}

//产生IIC停止信号
void SGP30_IIC_Stop(void)
{
  SDA_OUT();
//  SGP30_SCL = 0;
//  SGP30_SDA = 0;	//STOP:when CLK is high DATA change form low to high
	SGP30_SCL_LOW;
	SGP30_SDA_LOW;
  delay_us(20);
//  SGP30_SCL = 1;
//  SGP30_SDA = 1;	//发送I2C总线结束信号
	SGP30_SCL_HIGH;
	SGP30_SDA_HIGH;
  delay_us(20);
}

//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 SGP30_IIC_Wait_Ack(void)
{
  u8 ucErrTime = 0;
  SDA_IN();
//  SGP30_SDA = 1;
	SGP30_SDA_HIGH;
  delay_us(10);
//  SGP30_SCL = 1;
	SGP30_SCL_HIGH;
  delay_us(10);
  while(SGP30_SDA_READ())
  {
    ucErrTime++;
    if(ucErrTime > 250)
    {
      SGP30_IIC_Stop();
      return 1;
    }
  }
//  SGP30_SCL = 0;  		//时钟输出0
	SGP30_SCL_LOW;
  return 0;
}

//产生ACK应答
void SGP30_IIC_Ack(void)
{
//  SGP30_SCL = 0;
	SGP30_SCL_LOW;
  SDA_OUT();
//  SGP30_SDA = 0;
	SGP30_SDA_LOW;
  delay_us(20);
//  SGP30_SCL = 1;
	SGP30_SCL_HIGH;
  delay_us(20);
//  SGP30_SCL = 0;
	SGP30_SCL_LOW;
}

//不产生ACK应答
void SGP30_IIC_NAck(void)
{
//  SGP30_SCL = 0;
	SGP30_SCL_LOW;
  SDA_OUT();
//  SGP30_SDA = 1;
	SGP30_SDA_HIGH;
  delay_us(20);
//  SGP30_SCL = 1;
	SGP30_SCL_HIGH;
  delay_us(20);
//  SGP30_SCL = 0;
	SGP30_SCL_LOW;
}

//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void SGP30_IIC_Send_Byte(u8 txd)
{
  u8 t;
  SDA_OUT();
//  SGP30_SCL = 0; 	    	//拉低时钟开始数据传输
	SGP30_SCL_LOW;
  for(t = 0; t < 8; t++)
  {
    if((txd & 0x80) >> 7)
//      SGP30_SDA = 1;
			SGP30_SDA_HIGH;
    else
//      SGP30_SDA = 0;
		SGP30_SDA_LOW;
    txd <<= 1;
    delay_us(20);
//    SGP30_SCL = 1;
		SGP30_SCL_HIGH;
    delay_us(20);
//    SGP30_SCL = 0;
		SGP30_SCL_LOW;
    delay_us(20);
  }
  delay_us(20);

}

//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u16 SGP30_IIC_Read_Byte(u8 ack)
{
  u8 i;
  u16 receive = 0;
  SDA_IN();
  for(i = 0; i < 8; i++ )
  {
//    SGP30_SCL = 0;
		SGP30_SCL_LOW;
    delay_us(20);
//    SGP30_SCL = 1;
		SGP30_SCL_HIGH;
    receive <<= 1;
    if(SGP30_SDA_READ())
      receive++;
    delay_us(20);
  }
  if (!ack)
    SGP30_IIC_NAck();//发送nACK
  else
    SGP30_IIC_Ack(); //发送ACK
  return receive;
}


//初始化IIC接口
void SGP30_Init(void)
{
  SGP30_GPIO_Init();
  SGP30_Write(0x20, 0x03);
//	SGP30_ad_write(0x20,0x61);
//	SGP30_ad_write(0x01,0x00);
}


void SGP30_Write(u8 a, u8 b)
{
  SGP30_IIC_Start();
  SGP30_IIC_Send_Byte(SGP30_write); //发送器件地址+写指令
  SGP30_IIC_Wait_Ack();
  SGP30_IIC_Send_Byte(a);		//发送控制字节
  SGP30_IIC_Wait_Ack();
  SGP30_IIC_Send_Byte(b);
  SGP30_IIC_Wait_Ack();
  SGP30_IIC_Stop();
  delay_ms(100);
}

u32 SGP30_Read(void)
{
  u32 dat;
  u8 crc;
  SGP30_IIC_Start();
  SGP30_IIC_Send_Byte(SGP30_read); //发送器件地址+读指令
  SGP30_IIC_Wait_Ack();
  dat = SGP30_IIC_Read_Byte(1);
  dat <<= 8;
  dat += SGP30_IIC_Read_Byte(1);
  crc = SGP30_IIC_Read_Byte(1); //crc数据,舍去
  crc = crc;  //为了不让出现编译警告
  dat <<= 8;
  dat += SGP30_IIC_Read_Byte(1);
  dat <<= 8;
  dat += SGP30_IIC_Read_Byte(0);
  SGP30_IIC_Stop();
  return(dat);
}



sgp30.h

#ifndef __SG_H
#define __SG_H
#include "stm32f10x.h"

//#define  SGP30_SCL   PBout(0)
//#define  SGP30_SDA   PBout(1)

#define  SGP30_SCL_LOW    GPIO_ResetBits ( GPIOB, GPIO_Pin_0 )
#define  SGP30_SCL_HIGH    GPIO_SetBits ( GPIOB, GPIO_Pin_0 )

#define  SGP30_SDA_LOW    GPIO_ResetBits ( GPIOB, GPIO_Pin_1 )
#define  SGP30_SDA_HIGH    GPIO_SetBits ( GPIOB, GPIO_Pin_1 )
//#define  SGP30_SDA   PBout(1)

// USART GPIO 引脚宏定义
#define  SGP30_SCL_GPIO_CLK        RCC_APB2Periph_GPIOB
#define  SGP30_SCL_GPIO_PORT       GPIOB
#define  SGP30_SCL_GPIO_PIN        GPIO_Pin_0

#define  SGP30_SDA_GPIO_SDA        RCC_APB2Periph_GPIOB
#define  SGP30_SDA_GPIO_PORT       GPIOB
#define  SGP30_SDA_GPIO_PIN        GPIO_Pin_1

#define  SGP30_SDA_READ()           GPIO_ReadInputDataBit(SGP30_SDA_GPIO_PORT, SGP30_SDA_GPIO_PIN)

#define SGP30_read  0xb1  //SGP30的读地址
#define SGP30_write 0xb0  //SGP30的写地址


void SGP30_IIC_Start(void);				//发送IIC开始信号
void SGP30_IIC_Stop(void);	  			//发送IIC停止信号
void SGP30_IIC_Send_Byte(u8 txd);			//IIC发送一个字节
u16 SGP30_IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 SGP30_IIC_Wait_Ack(void); 				//IIC等待ACK信号
void SGP30_IIC_Ack(void);					//IIC发送ACK信号
void SGP30_IIC_NAck(void);				//IIC不发送ACK信号
void SGP30_IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 SGP30_IIC_Read_One_Byte(u8 daddr,u8 addr);	
void SGP30_Init(void);				  
void SGP30_Write(u8 a, u8 b);
u32 SGP30_Read(void);



#endif


main.c

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "sgp30.h"


u32 CO2Data,TVOCData;//定义CO2浓度变量与TVOC浓度变量
int sgp30_dat;

int main(void)
{
	OLED_Init();//初始化OLED
    OLED_Clear();//清屏
	delay_init();
	SGP30_Init();   //初始化SGP30
	delay_ms(100);
	SGP30_Write(0x20,0x08);
	OLED_ShowString(1, 1, "CO2:");
	sgp30_dat = SGP30_Read();//读取SGP30的值
		while(CO2Data == 400)
	{
		SGP30_Write(0x20,0x08);
		sgp30_dat = SGP30_Read();//读取SGP30的值
		CO2Data = (sgp30_dat & 0xffff0000) >> 16;//取出CO2浓度值

		delay_ms(500);
	}

    while(1)
    {
     	SGP30_Write(0x20,0x08);
		sgp30_dat = SGP30_Read();//读取SGP30的值
		CO2Data = (sgp30_dat & 0xffff0000) >> 16;//取出CO2浓度值
	    OLED_ShowNum(1, 9, CO2Data, 4);		
    }


}
	

3.ESP32驱动代码

      使用单片机:ESP32-WROOM

      单片机选型如下,Arduino UNO也可使用下面的代码,将单片机的种类进行更换即可

     ESP32-WROOM与sgp30接线

22           SCL

21            SDA

VCC        VCC

GND        GND

       完成接线后烧录程序后,打开串口监视器,选择波特率为115200即可查看读取的TVOC值和二氧化碳浓度值

#include <Wire.h>
#include "Adafruit_SGP30.h"
Adafruit_SGP30 sgp;
#define SCL 22
#define SDA 21
/* return absolute humidity [mg/m^3] with approximation formula
* @param temperature [°C]
* @param humidity [%RH]
*/
uint32_t getAbsoluteHumidity(float temperature, float humidity) 
{
    
    const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature));
    const uint32_t absoluteHumidityScaled = static_cast<uint32_t>(1000.0f * absoluteHumidity); // [mg/m^3]
    return absoluteHumidityScaled;
}


void TVOC_CO2()
{
  int counter = 0;
  if (! sgp.IAQmeasure()) {
    Serial.println("Measurement failed");
    return;
  }
  Serial.print("TVOC "); Serial.print(sgp.TVOC); Serial.print(" ppb\t");
  Serial.print("eCO2 "); Serial.print(sgp.eCO2); Serial.println(" ppm");

  if (! sgp.IAQmeasureRaw()) {
    Serial.println("Raw Measurement failed");
    return;
  }
  Serial.print("Raw H2 "); Serial.print(sgp.rawH2); Serial.print(" \t");
  Serial.print("Raw Ethanol "); Serial.print(sgp.rawEthanol); Serial.println("");
 
  delay(1000);

  counter++;
  if (counter == 30) {
    counter = 0;

    uint16_t TVOC_base, eCO2_base;
    if (! sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) {
      Serial.println("Failed to get baseline readings");
      return;
    }
    Serial.print("****Baseline values: eCO2: 0x"); Serial.print(eCO2_base, HEX);
    Serial.print(" & TVOC: 0x"); Serial.println(TVOC_base, HEX);
  }
}

void setup() {
  Serial.begin(115200);
  Wire.begin(SDA,SCL);

  if (! sgp.begin())
  {
    while (1);
  }
  Serial.print("Found SGP30 serial #");
  Serial.print(sgp.serialnumber[0], HEX);
  Serial.print(sgp.serialnumber[1], HEX);
  Serial.println(sgp.serialnumber[2], HEX);

}

void loop() 
{
TVOC_CO2();
}

  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值