完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
/**/
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); } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1814 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1631 浏览 1 评论
1098 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
738 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1690 浏览 2 评论
1950浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
753浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
585浏览 3评论
604浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
568浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-29 19:46 , Processed in 0.765505 second(s), Total 77, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (威廉希尔官方网站 图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号