/**/
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);
}
路漫漫其修远兮,吾将上下而求索,能力有限,如有错误,希望指出。