基于STM32的SGP30芯片开发例程

/**/
2021/03/10新增
附上SGP30的官方资料和STM32F103的开发例程
链接:https://pan.baidu.com/s/1pnUTTcXzY1GqiWg_6QcB5Q
提取码:92m9
复制这段内容后打开百度网盘手机App,操作更方便哦-
/
/

/*****************************************/
2021/01/16新增
下面的程序我已经在STM32F070上测试成功了,如果有需要的可以私信我,我将整理资料并上传到资料里。
/****************************************/

给大家讲解以下SGP30这款芯片的开发例程。

我们首先看一下芯片手册。我们可以从电气属性看到供电信息。
我们可以从电气属性看到供电信息。
引脚图
各个引脚的功能图。

在这里插入图片描述
在这里插入图片描述
芯片手册还给出了推荐电路图,这样我们就可以将芯片电路设计出来了。

在这里插入图片描述
典型的IIC总线,所以直接使用IIC就可以通讯。
在这里插入图片描述
这里显示了芯片地址0x58,并且说明了每个命令和返回数据都是十六位的数据,并且发送的命令的十六位包含三位CRC校验,接收的数据后面跟了八位的CRC校验。

在这里插入图片描述
空气质量信号
上面第一段这里主要说明了三件事,第一,为了保证补偿计算,这个测量信号要大于1s去发送;第二,返回两个值CO2和TVOC的值,即2位CO2数据+1位CO2的CRC校验+2位TVOC数据+1位TVOC的CRC校验;第三,开始检测的前十五秒作为零点浓度。
第二段就是讲述了关于补偿基线的内容,可以每次读取基线或者自设补偿基线,自设补偿基线先发送Init_air_quality命令,再发送Set_baseline命令,再就是零点和补偿都会被保存到内存中。每次重新输入自设补偿基线,都要重启和复位。

在这里插入图片描述
传感器原值
上面主要说明了参与补偿校准的原值数据,有两个数据,一个是OH的值,另一个是H2的值。返回的值为2位数据(一位H2的值,另一位是OH的值)+1位CRC校验,给出了参考浓度、实时浓度与参考原值、实时原值之间的换算关系。

在这里插入图片描述
湿度补偿
芯片有内部的湿度补偿,也可以从外部的温湿度去读取湿度补偿,用湿度补偿命令输入就行。可以发送0x0000来关闭湿度补偿。

在这里插入图片描述
芯片特征集
芯片特征集就是软件版本号。
在这里插入图片描述
测量示例
这里讲述了测量示例的命令、CRC位数、测量间隔长度和发送接收的简易介绍图。

在这里插入图片描述
在这里插入图片描述
软件复位
软件复位指令。

在这里插入图片描述
芯片序列号
芯片序列号就是芯片的出厂编号。
在这里插入图片描述
CRC校验计算
CRC-8的校验计算方法。

下面就剩封装和其他的一些参数了。

到这里我们编写程序就非常简单明了了。

首先,我们先把头文件写好。

#ifndef _SGP30_H
#define _SGP30_H
#include "sys.h"

//I2C部分

#define IIC_CLOCK           RCC_AHBPeriph_GPIOA
#define IIC_GPIO            GPIOA
#define IIC_SCL_PIN         GPIO_Pin_0
#define IIC_SDA_PIN         GPIO_Pin_1

/* 定义I2C总线连接的GPIO端口, 用户只需要修改下面4行代码即可任意改变SCL和SDA的引脚 */
#define I2C_SCL_1()     GPIO_SetBits(GPIOA,GPIO_Pin_0)
#define I2C_SCL_0()     GPIO_ResetBits(GPIOA,GPIO_Pin_0)
#define I2C_SDA_1()			GPIO_SetBits(GPIOA,GPIO_Pin_1)
#define I2C_SDA_0()     GPIO_ResetBits(GPIOA,GPIO_Pin_1)
#define I2C_SDA_READ()  GPIO_ReadInputDataBit(IIC_GPIO,IIC_SDA_PIN)

#define I2C_WR	0		/* 写控制bit */
#define I2C_RD	1		/* 读控制bit */

//SGP读取部分
#define SGP30_ADDR      								0x58
#define SGP30_Feature_Set   						0x0020
#define SGP30_Init_air_quality 					0x2003
#define SGP30_Measure_air_quality   		0x2008
#define SGP30_Get_baseline 							0x2015
#define SGP30_Set_baseline 							0x201e
#define SGP30_Set_humidity							0x2061
#define SGP30_Measure_test 							0x2032
#define SGP30_Get_feature_set_version		0x202f
#define SGP30_Measure_raw_signals				0x2050


void SGP30_I2C_Start(void);
void SGP30_I2C_SendByte(uint8_t _ucByte);
uint8_t SGP30_I2C_ReadByte(u8 ack);
uint8_t SGP30_I2C_WaitAck(void);
void SGP30_I2C_Ack(void);
void SGP30_I2C_NAck(void);
void SGP30_I2C_GPIO_Config(void);
uint8_t SGP30_I2C_CheckDevice(uint8_t _Address);
static u8 CRC_Check(u8 *check_data,u8 num,u8 check_crc);
uint32_t SGP30_I2C_Read_CO2_TVOC(uint8_t _Address);
void SGP30_DATA_IN_Cfg(void);
void SGP30_DATA_OUT_Cfg(void);
void  SGP30_Init(void);
#endif

然后就是主函数

#include "SGP30.h"
#include "delay.h"



/*
*********************************************************************************************************
*		函数名:			SGP30_I2C_Start
*		功能说明:		I2C开始指令
*		形参:				无
*		返回值:			无
*********************************************************************************************************
*/
void SGP30_I2C_Start(void)
{
	
		SGP30_DATA_OUT_Cfg();
		//当SCL高电平时,SDA出现一个下跳沿表示I2C总线信号开始
		I2C_SDA_1();
		I2C_SCL_1();
		delay_us(4);
		I2C_SDA_0();
		delay_us(4);
		I2C_SCL_0();
		delay_us(4);

}

/*
*********************************************************************************************************
*		函数名:			SGP30_I2C_Stop
*		功能说明:		I2C停止指令
*		形参:				无
*		返回值:			无
*********************************************************************************************************
*/
void SGP30_I2C_Stop(void)
{
		SGP30_DATA_OUT_Cfg();
		//当SCL高电平时,SDA出现一个上升沿
		I2C_SDA_0();
		I2C_SCL_1();
		delay_us(4);
		I2C_SDA_1();
	
}	

/*
*********************************************************************************************************
*		函数名:SGP30_I2C_SendByte
*		功能说明:CPU向I2C总线设备发送8bit数据
*		形参:_ucbyte :等待发送的字节
*		返回值:无
**********************************************************************************************************
*/

void SGP30_I2C_SendByte(uint8_t _ucByte)
{
		uint8_t i;
		SGP30_DATA_OUT_Cfg();
		/*先发送字节的高位bit7*/
		for(i =0;i<8;i++)
		{
				if(_ucByte & 0x80)				//每次判断最高位
				{
						I2C_SDA_1();
				}
				else
				{
						I2C_SDA_0();
				}
				
				delay_us(4);
				I2C_SCL_1();
				delay_us(4);
				I2C_SCL_0();
				if(i==7)
				{
						I2C_SDA_1();	//释放总线
				}
				_ucByte <<= 1;		//左移一个bit
				delay_us(4);
				
		}

}

/*
************************************************************************************************************
*		函数名:SGP30_I2C_ReadByte
*		功能说明:CPU从I2C总线设备读取8bit数据
*		形参:ack 是否应答
*		返回值:读到的数据
************************************************************************************************************
*/
uint8_t SGP30_I2C_ReadByte(u8 ack)
{
		uint8_t i;
		uint8_t value;
		SGP30_DATA_IN_Cfg();
		/*	读到第1个bit为数据的bit7 */
		value = 0;
		
		for(i=0;i<8;i++)
		{
				value <<= 1;
				I2C_SCL_1();
				delay_us(4);
				if(I2C_SDA_READ())
				{
						value++;
				}
				I2C_SCL_0();
				delay_us(4);
		}
		if(ack == 0)
			SGP30_I2C_NAck();
		else 
			SGP30_I2C_Ack();

		return value;
		

}


/*
************************************************************************************************************
*		函数名:SGP30_I2C_WaitAck
*		功能说明:CPU产生一个时钟,并读取器件的ACK应答信号
*		形参:无
*		返回值:返回0表示正确应答,1表示无器件相应
***********************************************************************************************************************
*/
uint8_t SGP30_I2C_WaitAck(void)
{
		uint8_t try_time = 100;							//连接超时次数
		SGP30_DATA_IN_Cfg();
		I2C_SDA_1();											//CPU释放SDA总线
		delay_us(4);
		I2C_SCL_1();											//CPU驱动SCL = 1,此时器件会返回ACK应答
		delay_us(4);		
		while(I2C_SDA_READ())							//等待SGP3030应答
		{
				try_time--;
				delay_us(4);
				if(try_time==0)									//超时,无响应
				{
						I2C_SCL_0();
						delay_us(4);
						return 1;
				
				}
		}
		I2C_SCL_0();
		delay_us(4);
		return 0;
}



/*
****************************************************************************************************************
*		函数名:SGP30_I2C_Ack
*		功能说明:CPU产生一个ACK信号
*		形参:无
*		返回值:无
****************************************************************************************************************
*/
void SGP30_I2C_Ack(void)
{
		SGP30_DATA_OUT_Cfg();
		I2C_SDA_0();			//CPU驱动SDA = 0
		delay_us(4);
		I2C_SCL_1();			//CPU产生一个时钟
		delay_us(4);
		I2C_SCL_0();
		delay_us(4);
		I2C_SDA_1();			//CPU释放SDA总线
}



/*
*****************************************************************************************************************
*		函数名:SGP30_I2C_NAck
*		功能说明:CPU产生1个NACK信号
*		形参:无
*		返回值:无
*****************************************************************************************************************
*/
void SGP30_I2C_NAck(void)
{
		SGP30_DATA_OUT_Cfg();
		I2C_SDA_1();		//CPU驱动SDA=1
		delay_us(4);
		I2C_SCL_1();		//CPU产生一个时钟
		delay_us(4);
		I2C_SCL_0();
		delay_us(4);	
}


/*
*****************************************************************************************************************
*		函数名:SGP30_I2C_GPIO_Config(void)
*		功能说明:配置I2C总线GPIO,采用模拟IO的方式实现
*		形参:无
*		返回值:无
*******************************************************************************************************************
*/
void SGP30_I2C_GPIO_Config(void)
{
		//库函数初始化通俗易懂
		GPIO_InitTypeDef GPIO_InitStrcuture;
	
		RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
	
		GPIO_InitStrcuture.GPIO_Mode = GPIO_Mode_OUT;			//开漏输出
		GPIO_InitStrcuture.GPIO_Pin = IIC_SDA_PIN|IIC_SCL_PIN;
		GPIO_InitStrcuture.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStrcuture.GPIO_OType = GPIO_OType_PP;
		GPIO_Init(IIC_GPIO,&GPIO_InitStrcuture);
}

/*********************************************************************************************************
** 函数名称: SGP_DAT_OUT_Cfg
** 功能描述: 配置SHT的DATA引脚输出
** 输   入: 无
** 输   出: 无
********************************************************************************************************/
void SGP30_DATA_OUT_Cfg(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;		
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOD, &GPIO_InitStructure);			
}
/*********************************************************************************************************
** 函数名称: SGP30_DAT_IN_Cfg
** 功能描述: 配置SHT的DATA引脚输入
** 输   入: 无
** 输   出: 无
********************************************************************************************************/
void SGP30_DATA_IN_Cfg(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;				
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;			
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;		// 上拉输入
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOD, &GPIO_InitStructure);				
}

/*
*****************************************************************************************************************
*		函数名:SGP30_I2C_CheckDevice
*		功能说明:检测I2C总线设备,CPU向发送设备地址,然后读取设备应答来判断设备是否存在
*		形参:_Address:设备的I2C总线地址
*		返回值:返回值0表示正确,返回1表示未探测到
*******************************************************************************************************************
*/
uint8_t SGP30_I2C_CheckDevice(uint8_t _Address)
{
		uint8_t ucAck;
//		SGP30_I2C_GPIO_Config();				//配置GPIO
		SGP30_I2C_Start();							//发送启动信号
	
		/* 发送设备地址+读写控制bit(0 = w, 1 = r)bit7 先传*/
		SGP30_I2C_SendByte(_Address|I2C_WR);
		ucAck = SGP30_I2C_WaitAck();		//检测设备的ACK应答
		SGP30_I2C_Stop();								//发送停止信号
		return ucAck;
}

/*
*****************************************************************************************************************
*		函数名:SGP30_I2C_Read_CO2_TVOC
*		功能说明:读取数据
*		形参:_Address:设备的I2C总线地址
*		返回值:返回值0表示正确,返回1表示未探测到
*******************************************************************************************************************
*/
uint32_t SGP30_I2C_Read_CO2_TVOC(uint8_t _Address)
{
		u32 Read_CO2_TVOC=0;
		u8  CRC_Check;
		SGP30_I2C_Start();							//发送启动信号	
		/* 发送设备地址+读写控制bit(0 = w, 1 = r)bit7 先传*/
		SGP30_I2C_SendByte(_Address<<1|I2C_WR);
		SGP30_I2C_WaitAck();		//检测设备的ACK应答
		SGP30_I2C_SendByte(0x20);
		SGP30_I2C_WaitAck();		//检测设备的ACK应答
		SGP30_I2C_SendByte(0x08);
		SGP30_I2C_WaitAck();		//检测设备的ACK应答
		SGP30_I2C_Stop();								//发送停止信号	
		delay_ms(1000);
		SGP30_I2C_Start();							//发送启动信号
		SGP30_I2C_SendByte(_Address<<1|I2C_RD);   //读取设备的特征集	
		SGP30_I2C_WaitAck();		//检测设备的ACK应答
		Read_CO2_TVOC |= (u16)(SGP30_I2C_ReadByte(1)<<8);
		Read_CO2_TVOC |= (u16)(SGP30_I2C_ReadByte(1));
		CRC_Check = SGP30_I2C_ReadByte(1);
		Read_CO2_TVOC |= (u32)(SGP30_I2C_ReadByte(1)<<24);
		Read_CO2_TVOC |= (u32)(SGP30_I2C_ReadByte(1)<<16);
		CRC_Check = SGP30_I2C_ReadByte(0);
		SGP30_I2C_Stop();								//发送停止信号
		return Read_CO2_TVOC;
}

/*
----------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------
*/
//CRC校验-8位
static u8 CRC_Check(u8 *check_data,u8 num,u8 check_crc)
{
		uint8_t bit;										//bit mask
		uint8_t crc = 0xFF;							//caculated checksum
		uint8_t byteCtr;								//byte counter
	
	
		//calculates 8Bit checksum with given polynomial x8+x5+x4+1
		for(byteCtr = 0; byteCtr < num; byteCtr++)
		{
				crc ^= (*(check_data+byteCtr));
				//CRC校验,最高为是1就^0x31
				for(bit = 8; bit > 0;--bit)
				{
						if(crc & 0x80)
							crc = (crc << 1)^0x31;
						else
							crc = (crc << 1);
				
				}
		}
		
		if(crc == check_crc)
			return 1;
		else
			return 0;
	
}


/*
			SGP30   初始化

*/
void  SGP30_Init(void)
{
		SGP30_I2C_GPIO_Config();				//配置GPIO
		SGP30_I2C_Start();							//发送启动信号
		/* 发送设备地址+读写控制bit(0 = w, 1 = r)bit7 先传*/
		SGP30_I2C_SendByte(SGP30_ADDR<<1);
		SGP30_I2C_WaitAck();		//检测设备的ACK应答
		SGP30_I2C_SendByte(0x20);
		SGP30_I2C_WaitAck();		//检测设备的ACK应答
		SGP30_I2C_SendByte(0x03);
		SGP30_I2C_WaitAck();		//检测设备的ACK应答	
		SGP30_I2C_Stop();								//发送停止信号		
		delay_ms(1000);

	
}

路漫漫其修远兮,吾将上下而求索,能力有限,如有错误,希望指出。

  • 30
    点赞
  • 222
    收藏
    觉得还不错? 一键收藏
  • 39
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 39
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值