基于STM32的SGP30芯片开发例程

2023-11-16

/**/
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);

	
}

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于STM32的SGP30芯片开发例程 的相关文章

随机推荐

  • C++ 调用tensorflow

    安装protobuf 3 6 安装依赖软件 sudo apt get install autoconf automake libtool curl make g unzip 克隆版本为3 6 0的protobuf源码 git clone b
  • 8.翻转子串

    题目描述 假定我们都知道非常高效的算法来检查一个单词是否为其他字符串的子串 请将这个算法编写成一个函数 给定两个字符串s1和s2 请编写代码检查s2是否为s1旋转而成 要求只能调用一次检查子串的函数 给定两个字符串s1 s2 请返回bool
  • 1-如何安装ROS

    如何安装ROS 大家好 我是如何 今天尝试在Ubantu下安装ROS Robot Operating System 测试环境 虚拟机VMware Ubantu20 04 准备步骤 添加ROS软件源 sudo sh c echo deb ht
  • C++之普通成员函数、虚函数以及纯虚函数的区别与用法要点

    C 之普通成员函数 虚函数以及纯虚函数的区别与用法要点 作者 luoweifu 字体 增加 减小 类型 转载 时间 2015 07 21 我要评论 本篇文章主要介绍了C 中的普通成员函数 虚函数以及纯虚函数 非常的详细 有需要的朋友可以参考
  • localstorage在uc无痕模式失效问题;

    做项目的时候发现localstorage在uc 无痕模式下失效 但是其他浏览器不会出现此类问题 补充 我的解决方案是使用cookie代替localstorage 但是有大神给出了解决方案我觉得非常nice 附 https www jians
  • Thrift快速入门和简单示例

    文章目录 Thrift介绍 Thrift的架构 Thrift的特性 开发速度快 接口维护简单 学习成本低 多语言 跨语言支持 稳定 广泛使用 快速入门例子 编译安装 创建Thrift IDL文件 通过编译器编译user thrift文件 生
  • 马踏棋盘问题(C-数据结构)

    题目 在8 8的国际象棋棋盘中 给出马的初始位置 求出马踏遍棋盘每个位置的路线图 棋盘中每个位置只能走一次 思路 国际象棋中 马走的规则和中国象棋相似 为斜两格行走 即向任意方向走两格 再向与前面行走方向垂直的方向走一格 每个位置最多可以向
  • C语言,BMP格式解析,生成不同位深的图片。

    0 前言 目录 0 前言 1 BMP格式详解 1 1图片的构成 1 2BMP格式 1 2 1文件头 1 2 2位图信息头 1 2 3调色板 1 2 4位图数据 2 生成 3 总结 最近工作任务繁重且对我来说小有难度 但是没有困难的事情做起来
  • 《XNA游戏开发》简介

    一 XNA简介 XNA是基于DirectX的游戏开发环境 以C 为开发语言 以 NET Framework 为基础 并加入游戏应用所需之函式库所构成的 XNA Framework 可开发XNA for Windows Phone游戏 Xbo
  • html的<form>表单的基本介绍及使用说明

  • 本地、服务器文件互传命令

    1 从服务器复制文件 文件夹到本地 scp r ZSL 192 168 53 54 data ZSL json D WorkSpace PyCharm myfiel 加上r可以复制整个文件夹 不加r只能复制单个文件 2 从本地复制文件夹到服
  • protocol buffer 简单使用

    protocol buffer占用空间小 传输速率高 并且是跨平台的 每个语言都有一套解释protocol buffer的特殊方式 我就介绍一下C 如何解析protocol buffer 首先我们要自己编译Protogen 地址 如下 ht
  • Synchronized 锁升级(无锁、偏向锁、轻量级锁、重量级锁)

    一概念 是Java中一个关键字 是JVM层面提供的同步锁机制 用于保证多线程访问同一资源的可见性 互斥性 即当一个线程已经获取资源锁时 其他试图获取的线程只能等待或者阻塞在那里 访问静态 synchronized 方法占用的锁是当前类的锁
  • C++标准库学习(三)--队列和string类

    今天学习了C 的queue和string类的基本操作 queue是自带的队列 应用很是方便 要注意 pop函数并不返回pop出的值 include
  • FlowUs 使用攻略:如何快速制作 Web 应用(PWA)

    最近在寻找 Notion 的替代品过程中 我发现了 FlowUs 虽然是后起之秀 但不是唯 Notion 亦步亦趋 FLowUs 有两个很重要的特性打动了我 支持文件夹页面 一直以来 虽然 Notion 等产品十分强大 试图取代 Offic
  • powershell(二)对数据库的增删改查

    数据库配置 Database 数据库名称 数据库实例名 Server localhost SQL2008 用户名 UserName sa 密码 Password 数据库密码 连接数据库 SqlConn New Object System D
  • Databend 设计概述

    Databend 是一个开源的 完全面向云架构的新式数仓 它提供快速的弹性扩展能力 并结合云的弹性 简单性和低成本 使 Data Cloud 构建变得更加容易 Databend 把数据存储在像 AWS S3 Azure Blob 这些云上的
  • Java自定义注解的使用

    注解的定义 注解是一种能被添加到java源代码中的元数据 可以看做是是一种特殊标记 可以在包 类 参数和方法上使用 可以进行一些特殊的处理 访问修饰符必须为public 不写默认为public 元注解 JDK中有一些元注解来修饰注解 主要包
  • 浏览器提示:你的连接不是专用连接的解决方法

    解决方法 1 调整键盘为英文输入状态 2 鼠标点击当前页面任意位置 然后依次按键 thisisunsafe 输入完成后 页面会自动刷新 即可正常访问
  • 基于STM32的SGP30芯片开发例程

    2021 03 10新增 附上SGP30的官方资料和STM32F103的开发例程 链接 https pan baidu com s 1pnUTTcXzY1GqiWg 6QcB5Q 提取码 92m9 复制这段内容后打开百度网盘手机App 操作