草庐IT

【mcuclub】CO2及TVOC检测-SGP30

单片机俱乐部--官方 2023-04-12 原文

一、实物图

二、原理图

编号名称功能
1VCC电源正
2GND电源地
3SDA串行地址和数据输入/输出
4SCL串行时钟输入

三、简介

SGP30是一款单一芯片上具有多个传感元件的金属氧化物室内气体传感器,内部集成4个气体传感元件,具有完全校准的空气质量输出信号,主要是对空气质量进行检测。可以输出:

TVOC(Total Volatile Organic Compounds,总挥发性有机物),量程为0~60000ppb;CO2浓度,量程400~60000ppm。

四、工作原理

SGP30的传感(MEMS)部分基于金属氧化物(MOx)纳米颗粒的加热膜。气敏材料——金属氧化物颗粒上吸附的氧气与目标气体发生反应,从而释放出电子。这导致由传感器测量的金属氧化物层的电阻发生改变。简而言之,还原性气体的出现造成气敏材料表面氧浓度降低,改变了半导体的电阻(或电导率)。后续通过电路(ASIC)部分对电阻进行检测、信号处理与转换等,最终获取到气体值。

五、通信协议(I2C通信)

1、I2C总线介绍

<1>I2C总线(Inter IC bus)是由Philips公司开发的一种通用数据总线。

<2>两根通信线:SCL(Serial Clock串行时钟线)、SDA(Serial Data串行数据线)。

<3>同步、半双工,带数据应答。

*注:同步(因为它有单独的时钟线)、半双工(SDA只有一根线,并且还要来回通信)

<4>通用的I2C总线,可以使各种设备的通信标准统一,对于厂家来说,使用成熟的方案可以缩短芯片设计周期、提高稳定性,对于应用者来说,使用通用的通信协议可以避免学习各种各样的自定义协议,降低了学习和应用的难度。

2、I2C电路规范

<1>所有I2C设备的SCL连在一起,SDA连在一起

<2>设备的SCL和SDA均要配置成开漏输出模式(硬件IIC)

*开漏输出模式——断开时引脚成浮空状态(电路断开,电压不稳定)

<3>SCL和SDA各添加一个上拉电阻,阻值一般为4.7K~10K左右

<4>开漏输出和上拉电阻的共同作用实现了“线与”的功能,此设计主要是为了解决多机通信互相干扰的问题。

3、I2C时序结构

起始信号:SCL高电平期间,SDA从高电平切换到低电平

停止信号:SCL高电平期间,SDA从低电平切换到高电平

代码如下:

/****

*******I2C总线启动信号

*****/

void SGP30_IIC_Start(void)

{

   SGP30_SDA = 1;

   SGP30_SCL = 1;

   SGP30_IIC_Delay(DELAY_TIME);

   SGP30_SDA = 0;

   SGP30_IIC_Delay(DELAY_TIME);

   SGP30_SCL = 0;

}

/****

*******I2C总线停止信号

*****/

void SGP30_IIC_Stop(void)

{

   SGP30_SDA = 0;

   SGP30_SCL = 1;

   SGP30_IIC_Delay(DELAY_TIME);

   SGP30_SDA = 1;

   SGP30_IIC_Delay(DELAY_TIME);

}

发送应答:在接收完一个字节之后,主机在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答。

接收应答:在发送完一个字节之后,主机在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)。

代码如下:

/****

*******发送应答或非应答信号

*****/

void SGP30_IIC_SendAck(bit ackbit)

{

   SGP30_SCL = 0;

   SGP30_SDA = ackbit;

   SGP30_IIC_Delay(DELAY_TIME);

   SGP30_SCL = 1;

   SGP30_IIC_Delay(DELAY_TIME);

   SGP30_SCL = 0;

   SGP30_SDA = 1;

   SGP30_IIC_Delay(DELAY_TIME);

}

/****

*******等待应答信号

*****/

bit SGP30_IIC_WaitAck(void)

{

   bit ackbit;

   SGP30_SDA = 1;

   SGP30_SCL = 1;

   SGP30_IIC_Delay(DELAY_TIME);

   ackbit = SGP30_SDA;

   SGP30_SCL = 0;

   SGP30_IIC_Delay(DELAY_TIME);

   return ackbit;

}

发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位在前),然后拉高SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节。

代码如下:

/****

*******I2C总线发送一个字节数据

*****/

void SGP30_IIC_SendByte(uchar byte)

{

   uchar i;

   SGP30_SCL = 0;

   for(i=0; i<8; i++)

   {

      if(byte & 0x80)

         SGP30_SDA = 1;

      else

         SGP30_SDA = 0;

      SGP30_IIC_Delay(DELAY_TIME);

      SGP30_SCL = 1;

      SGP30_IIC_Delay(DELAY_TIME);

      SGP30_SCL = 0;

      SGP30_IIC_Delay(DELAY_TIME);

      byte <<= 1;

   }

   SGP30_IIC_WaitAck();

}

接收一个字节:SCL低电平期间,从机将数据位依次放到SDA总线上(高位在前),然后拉高SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)

代码如下:

/****

*******I2C总线接收一个字节数据

*****/

uchar SGP30_IIC_RecByte(bit ackbit)

{

   uchar i, dat;

   SGP30_SDA = 1;

   for(i=0; i<8; i++)

   {

      SGP30_SCL = 1;

      SGP30_IIC_Delay(DELAY_TIME);

      dat <<= 1;

      if(SGP30_SDA)

         dat |= 1;

      SGP30_SCL = 0;

      SGP30_IIC_Delay(DELAY_TIME);

   }

   SGP30_IIC_SendAck(ackbit);

   return dat;

}

4、SGP30读取数据

I2C从机地址是0X58,由于地址只用到了7bit,最高位未使用,最低位为判断是读还是写,为0是读,为1是写,所以:

  • 对于写SGP30,地址为(0X58 << 1) = 0XB0
  • 对于读SGP30,地址为((0X58 << 1)) | 0X01 = 0XB1

SGP30的命令都是双字节的,先发高位,有如下命令:

常用的有两个,一个是0x2003为初始化SGP30命令,另一个0x2008为获取空气质量值命令。

SGP30获取的数据格式为:2位CO2数据+1位CO2的CRC校验+2位TVOC数据+1位TVOC的CRC校验。模块上电需要15s左右初始化,在初始化阶段读取的CO2浓度为400ppm,TVOC为0ppd且恒定不变。因此上电后一直读,直到TVOC不为0并且CO2不为400,SGP30模块才初始化完成。

初始化完成后刚开始读出数据会波动比较大,属于正常现象,一段时间后会逐渐趋于稳定。气体类传感器比较容易受环境影响,测量数据出现波动是正常的,可以添加滤波函数进行滤波。

代码如下:

/****

*******向SGP30的地址address中写入一个字节的数据

*****/

void SGP30_Write_Data(uchar address,uchar dat)

{

   SGP30_IIC_Start();

   SGP30_IIC_SendByte(SGP30_SlaveAddress);

   SGP30_IIC_SendByte(address);

   SGP30_IIC_SendByte(dat);

   SGP30_IIC_Stop();

}

/****

*******从SGP30的地址address中读取一个字节的数据

*****/

ulong SGP30_Read_Data()

{

   ulong dat;

   uint crc;

   SGP30_IIC_Start();

   SGP30_IIC_SendByte(SGP30_SlaveAddress + 1);

   dat = SGP30_IIC_RecByte(SGP30_ACK);               //CO2高位数据

   dat <<= 8;

   dat += SGP30_IIC_RecByte(SGP30_ACK);              //CO2低位数据

   crc = SGP30_IIC_RecByte(SGP30_ACK);                //CRC校验值

   dat <<= 8;

   dat += SGP30_IIC_RecByte(SGP30_ACK);              //TVOC高位数据

   dat <<= 8;

   dat += SGP30_IIC_RecByte(SGP30_ACK);              //TVOC低位数据

   crc = SGP30_IIC_RecByte(SGP30_NACK);               //CRC校验值

   SGP30_IIC_Stop();

   return(dat);

}

/****

*******SGP30初始化函数

*****/

void SGP30_Init(void)

{

   SGP30_Write_Data(0x20,0x03);

}

/****

*******SGP30获取CO2和TVOC值函数

*****/

void SGP30_Get_Co2_Tvoc_Value(uint *co2_value, uint *tvoc_value)

{

   ulong sgp30_value;

   SGP30_Write_Data(0x20,0x08);

   sgp30_value = SGP30_Read_Data();

   *co2_value = (sgp30_value & 0xffff0000) >> 16;

   *tvoc_value = sgp30_value & 0x0000ffff;

}

六、流程设计

首先初始化引脚,然后发送初始化指令0x2003。接着发送读取数据指令0x2008,然后开始获取数据,先获取CO2高8位数据,再获取CO2低8位数据,再获取一次CRC校验值;然后再获取TVOC高8位数据,再获取TVOC低8位数据,再获取一次CRC校验值。数据获取好后,将CO2的高8位数据和低8位数据整合为一个数据即为CO2值,将TVOC的高8位数据和低8位数据整合为一个数据即为TVOC值。

有关【mcuclub】CO2及TVOC检测-SGP30的更多相关文章

  1. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  2. 牛客网专项练习30天Pytnon篇第02天 - 2

    1.在Python3中,下列关于数学运算结果正确的是:(B)a=10b=3print(a//b)print(a%b)print(a/b)A.3,3,3.3333...B.3,1,3.3333...C.3.3333...,3.3333...,3D.3.3333...,1,3.3333...解析:    在Python中,//表示地板除(向下取整),%表示取余,/表示除(Python2向下取整返回3)2.如下程序Python2会打印多少个数:(D)k=1000whilek>1:    print(k)k=k/2A.1000 B.10C.11D.9解析:    按照题意每次循环K/2,直到K值小于等

  3. ruby - 检测由 RSpec、Ruby 运行的代码 - 2

    我想知道我的代码是否在rspec下运行。这可能吗?原因是我正在加载一些错误记录器,这些记录器在测试期间会被故意错误(expect{x}.toraise_error)弄得乱七八糟。我查看了我的ENV变量,没有(明显的)测试环境变量的迹象。 最佳答案 在spec_helper.rb的开头添加:ENV['RACK_ENV']='test'现在您可以在代码中检查RACK_ENV是否经过测试。 关于ruby-检测由RSpec、Ruby运行的代码,我们在StackOverflow上找到一个类似的问题

  4. ruby - 使用 Ruby Daemons gem 检测停止 - 2

    我正在使用rubydaemongem。想知道如何向停止操作添加一些额外的步骤?希望我能检测到停止被调用,并向其添加一些额外的代码。任何人都知道我如何才能做到这一点? 最佳答案 查看守护程序gem代码,它似乎没有用于此目的的明显扩展点。但是,我想知道(在守护进程中)您是否可以捕获守护进程在发生“停止”时发送的KILL/TERM信号...?trap("TERM")do#executeyourextracodehereend或者你可以安装一个at_exit钩子(Hook):-at_exitdo#executeyourextracodehe

  5. ruby - Ruby 脚本如何检测到它正在 irb 中运行? - 2

    我有一个定义类的Ruby脚本。我希望脚本执行语句BoolParser.generate:file_base=>'bool_parser'仅当脚本作为可执行文件被调用时,而不是当它被irbrequire(或通过-r在命令行上传递)时。我可以用什么来包装上面的语句,以防止它在我的Ruby文件加载时执行? 最佳答案 条件$0==__FILE__...!/usr/bin/ruby1.8classBoolParserdefself.generate(args)p['BoolParser.generate',args]endendif$0==_

  6. Ruby 无法检测字符串中的换行符 - 2

    我有以下字符串,我想检测那里的换行符。但是Ruby的字符串方法include?检测不到它。我正在运行Ruby1.9.2p290。我哪里出错了?"/'ædres/\nYour".include?('\n')=>false 最佳答案 \n需要在双引号内,否则无法转义。>>"\n".include?'\n'=>false>>"\n".include?"\n"=>true 关于Ruby无法检测字符串中的换行符,我们在StackOverflow上找到一个类似的问题: h

  7. 【自动驾驶环境感知项目】——基于Paddle3D的点云障碍物检测 - 2

    文章目录1.自动驾驶实战:基于Paddle3D的点云障碍物检测1.1环境信息1.2准备点云数据1.3安装Paddle3D1.4模型训练1.5模型评估1.6模型导出1.7模型部署效果附录show_lidar_pred_on_image.py1.自动驾驶实战:基于Paddle3D的点云障碍物检测项目地址——自动驾驶实战:基于Paddle3D的点云障碍物检测课程地址——自动驾驶感知系统揭秘1.1环境信息硬件信息CPU:2核AI加速卡:v100总显存:16GB总内存:16GB总硬盘:100GB环境配置Python:3.7.4框架信息框架版本:PaddlePaddle2.4.0(项目默认框架版本为2.3

  8. ruby - 重新连接 tcpsocket(或如何检测已关闭的套接字) - 2

    我有一个连接到服务器的ruby​​tcpsocket客户端。在发送数据之前如何检查套接字是否已连接?我是否尝试“拯救”断开连接的tcpsocket,重新连接然后重新发送?如果是这样,有没有人有一个简单的代码示例,因为我不知道从哪里开始:(我很自豪我设法在rails中获得了一个持久连接的客户端tcpsocket。然后服务器决定杀死客户端,一切都崩溃了;)编辑我已经使用此代码解决了一些问题-如果未连接,它将尝试重新连接,但如果服务器已关闭则不会处理这种情况(它将继续重试)。这是正确方法的开始吗?谢谢defself.write(data)begin@@my_connection.write(

  9. css - 检测到 Sass 更改但 style.css 仅在我保存时每 5 到 7 次被覆盖 - 2

    我在一台Windows764位机器上使用Sass和Ruby(最新版本),我正在我的家庭服务器上处理一个共享文件夹。(但是,我不得不承认问题本身也出现在服务器上,因为我试图安装Ruby并直接-watch服务器上的文件)。问题如下:如果我第一次保存,检测到变化,我的style.css被直接覆盖。之后,我总是需要保存多达7次才能覆盖style.css。每次都会检测到更改,但不会编译任何内容。这是一个屏幕:>>>Sassiswatchingforchanges.PressCtrl-Ctostop.overwritestyle.css>>>Changedetectedto:E:/Websites

  10. ruby-on-rails - 检测 Rails 是否正在运行站点 - 2

    我所在的团队负责管理公司面向公众的云平台。我们拥有大量运行面向互联网的VM的用户群。我想对我们的地址空间进行自动扫描,看看是否有人在运行Rails应用程序,这样我就可以通知他们升级他们的Rails版本,以避免本周出现的严重安全漏洞。我注意到在某些Apache部署中,有一个有用的PassengerHeader:X-Powered-By:PhusionPassenger(mod_rails/mod_rack)2.0.3然而,这并不可靠。我想知道是否有一种可靠的方法来检测在Web服务器后面运行的Rails,无论是使用响应header还是某种可以确定的GET/POST。谢谢!

随机推荐