arduino开发SGP30模块测二氧化碳浓度-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 12505|回复: 4

arduino开发SGP30模块测二氧化碳浓度

[复制链接]
发表于 2019-4-16 17:28 | 显示全部楼层 |阅读模式
  • SGP30模块是目前位置接触的比较麻烦的模块,首先芯片手册就比较烦人,没有中文翻译,(文末附加了芯片手册),而且SGP30使用的是I2C通信,所以这就需要了解I2C的通信原理,(文末附加了I2C手册),再者,SGP30模块有较多的模式,需要通过I2C将执行的指令传给模块,才可以选择对应的模式,得到自己想要的结果。每个传输的指令都是由两个字节构成,每个数据的返回也是由两个字节的数据构成,而且还要加一个字节的CRC校验码,(CRC校验来验证数据是否传输正确,芯片生成一个校验码传输给主机,所以必须写一个CRC校验算法,来对两个CRC码进程对比,以此来证明数据传输的正确性)。
  • I2C的通信过程,不用自己写,arduino库集成了<Wire.h>来实现,这也省了一部分工作,但是这样也就感觉没有了开发这个模块的乐趣,不过可以看看<Wire>的源码来膜拜一下大神们维护的库。附上源码路径方便查看:/arduino/hardware/arduino/avr/libraries/Wire


  • 最重要的一点是SGP30的电气特性,工作电压是1.62v-1.92v(如果没记错的),这个工作电压跟板子上的电压完全不匹配啊,不过问题不大,可以自己链接5v-1.8v的稳压芯片,(但是,焊好稳压芯片,接好电路,烧好代码之后,却发现模块不工作,索性把稳压芯片去掉,将模块接到3.3v的电压上,竟然神奇般的工作正常了)。

  • 完成之后,发现一个道理,贵的模块果然工作稳定。




[mw_shl_code=arduino,true]#include "Adafruit_SGP30.h"

//#ifdef I2C_DEBUG

Adafruit_SGP30::Adafruit_SGP30() {
}

boolean Adafruit_SGP30::sgp_begin(TwoWire *theWire) {
    _i2caddr = SGP30_I2CADDR_DEFAULT;
    if (theWire == NULL) {
        _i2c = &Wire;
    } else {
        _i2c = theWire;
    }

    // 初始化wire库,并且加入到i2c网络,主机只能调用一次
    _i2c->begin();


    // 0x3682 指令:  获取序列号
    uint8_t command[2];
    command[0] = 0x36;
    command[1] = 0x82;
    if (! readWordFromCommand(command, 2, 10, serialnumber, 3))
        return false;

    //  0x202f 指令: 获取版本号
    uint16_t featureset;
    command[0] = 0x20;
    command[1] = 0x2F;
    if (! readWordFromCommand(command, 2, 10, &featureset, 1))
        return false;
    //Serial.print("Featureset 0x"); Serial.println(featureset, HEX);
    // 0x0020 版本号
    if (featureset != SGP30_FEATURESET)
        return false;
    if (! IAQinit())
        return false;

    return true;
}


//  0x2003 指令: 初始化空气质量
//
boolean Adafruit_SGP30::IAQinit(void) {
    uint8_t command[2];
    command[0] = 0x20;
    command[1] = 0x03;
    return readWordFromCommand(command, 2, 10);
}

// 返回 6 字节,包括CRC 2字节
boolean Adafruit_SGP30::IAQmeasure(void) {
    uint8_t command[2];
    command[0] = 0x20;
    command[1] = 0x08;
    uint16_t reply[2];
    if (! readWordFromCommand(command, 2, 12, reply, 2))
        return false;
    TVOC = reply[1];
    eCO2 = reply[0];
    return true;
}

// 0x2015 指令: 获取基准线
// 返回 6 字节,包括CRC 2字节
boolean Adafruit_SGP30::getIAQBaseline(uint16_t *eco2_base, uint16_t *tvoc_base) {
    uint8_t command[2];
    command[0] = 0x20;
    command[1] = 0x15;
    uint16_t reply[2];
    if (! readWordFromCommand(command, 2, 10, reply, 2))
        return false;
    *eco2_base = reply[0];
    *tvoc_base = reply[1];
    return true;
}

// 0x201e 指令:  设置基准线
// 参数 6 字节,包括CRC两字节
//
boolean Adafruit_SGP30::setIAQBaseline(uint16_t eco2_base, uint16_t tvoc_base) {
    uint8_t command[8];
    command[0] = 0x20;
    command[1] = 0x1e;
    command[2] = tvoc_base >> 8;
    command[3] = tvoc_base & 0xFF;
    command[4] = generateCRC(command+2, 2);
    command[5] = eco2_base >> 8;
    command[6] = eco2_base & 0xFF;
    command[7] = generateCRC(command+5, 2);

    return readWordFromCommand(command, 8, 10);
}

//  0x2061 指令: 设置温度补偿
//  参数 3 字节 包括 CRC
boolean Adafruit_SGP30::setHumidity(uint32_t absolute_humidity) {
    if (absolute_humidity > 256000) {
        return false;
    }

    uint16_t ah_scaled = (uint16_t)(((uint64_t)absolute_humidity * 256 * 16777) >> 24);
    uint8_t command[5];
    command[0] = 0x20;
    command[1] = 0x61;
    command[2] = ah_scaled >> 8;
    command[3] = ah_scaled & 0xFF;
    command[4] = generateCRC(command+2, 2);

    return readWordFromCommand(command, 5, 10);
}


boolean Adafruit_SGP30::readWordFromCommand(uint8_t command[], uint8_t commandLength, uint16_t delayms, uint16_t *readdata, uint8_t readlen)
{
    uint8_t data;

    // 开始传输数据,发送一个i2c开始字符
    _i2c->beginTransmission(_i2caddr);

#ifdef I2C_DEBUG
    Serial.print("\t\t-> ");
#endif

    for (uint8_t i=0; i<commandLength; i++) {
        // 向从机发送数据
        _i2c->write(command);
#ifdef I2C_DEBUG
        Serial.print("0x"); Serial.print(command, HEX); Serial.print(", ");
#endif
    }
#ifdef I2C_DEBUG
    Serial.println();
#endif
    // 结束发送
    _i2c->endTransmission();

    delay(delayms);

    if (readlen == 0)
        return true;

    //  replylen : 从从机请求到的数据的字节数
    //  sgp30 芯片手册得知: 每个数据由两个字节组成,并且附加一个字节的CRC校验
    uint8_t replylen = readlen * (SGP30_WORD_LEN +1);

    // requestFrom : 主设备请求从设备一个字节,这个字节可以被主设备用 read() 和 available() 接受
    // 参数        : 从设备地址 请求得到的数量
    // 返回值      : 从从机接受到的字节数目

    if (_i2c->requestFrom(_i2caddr, replylen) != replylen)
        return false;
    uint8_t replybuffer[replylen];
#ifdef I2C_DEBUG
    Serial.print("\t\t<- ");
#endif  
    for (uint8_t i=0; i<replylen; i++) {
        //  read() : 用于接受 requestFrom 请求的数据
        replybuffer = _i2c->read();
#ifdef I2C_DEBUG
        Serial.print("0x"); Serial.print(replybuffer, HEX); Serial.print(", ");
#endif
    }

#ifdef I2C_DEBUG
    Serial.println();
#endif

    for (uint8_t i=0; i<readlen; i++) {
        uint8_t crc = generateCRC(replybuffer+i*3, 2);
#ifdef I2C_DEBUG
        Serial.print("\t\tCRC calced: 0x"); Serial.print(crc, HEX);
        Serial.print(" vs. 0x"); Serial.println(replybuffer[i * 3 + 2], HEX);
#endif
        if (crc != replybuffer[i * 3 + 2])
            return false;
        // success! store it
        readdata = replybuffer[i*3];
        readdata <<= 8;
        readdata |= replybuffer[i*3 + 1];
#ifdef I2C_DEBUG
        Serial.print("\t\tRead: 0x"); Serial.println(readdata, HEX);
#endif
    }
    return true;
}

//  generateCRC 进行数据的校验  
//  data  : 数据
//  datalen : 数据字长
uint8_t Adafruit_SGP30::generateCRC(uint8_t *data, uint8_t datalen) {
    // calculates 8-Bit checksum with given polynomial
    uint8_t crc = SGP30_CRC8_INIT;

    for (uint8_t i=0; i<datalen; i++) {
        crc ^= data;
        for (uint8_t b=0; b<8; b++) {
            if (crc & 0x80)
                crc = (crc << 1) ^ SGP30_CRC8_POLYNOMIAL;
            else
                crc <<= 1;
        }
    }
    return crc;
}
[/mw_shl_code]



Sensors_SGP30_Datasheet_EN.zip

988.44 KB, 下载次数: 261

SGP30芯片手册

STM32-I2C.pdf

553 KB, 下载次数: 164

I2C手册

SGP30.tar

1.02 KB, 下载次数: 252

SGP30代码(不包含main函数的调用)

发表于 2019-5-6 09:13 | 显示全部楼层
学习了,正在为sgp30这个芯片资料少而发愁,非常感谢楼主指导,马上准备买个芯片试试看!
发表于 2019-5-6 09:34 | 显示全部楼层
请教您sgp30连接arduino的问题,我准备买的是sgp30升级版即供电电压1.8-5v的,连接到5varduino,都是用5v供电,请问两个板子之间数据线连接还需要电平转换吗?
发表于 2022-8-21 16:44 | 显示全部楼层
本帖最后由 yidongzhao 于 2022-8-21 16:45 编辑

你好,我在使用这个模块的时候,相同环境下两次数据差别很大,呼气后的值变化也很大。请问会是什么方面的原因呢?大神能帮忙分析一下吗?第一次是C:\Users\Lenovo\Desktop\数据\2\shot.png;第二次是C:\Users\Lenovo\Desktop\数据\2\shot2.png

第一次测量

第一次测量

第二次测量

第二次测量
发表于 2022-8-22 13:58 | 显示全部楼层
yidongzhao 发表于 2022-8-21 16:44
你好,我在使用这个模块的时候,相同环境下两次数据差别很大,呼气后的值变化也很大。请问会是什么方面的原 ...

传感器是有响应时间的
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-12-1 07:05 , Processed in 0.077529 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表