Jetson传感器数据读取——二氧化碳传感器SGP30

366 阅读4分钟

手里正好有个Jetson项目用到二氧化碳传感器SGP30,本着“独乐乐不如众乐乐”的心态,拿出来与大家分享。

初识二氧化碳传感器

如下图所示,这片SGP30是气体传感器,用于检测二氧化碳浓度。

image.png

很显然,这是一片Adafruit的产品。那么好消息就是:一方面产品质量有保证,另一方面是可以使用Adafruit相关的Python库来简化实现了。

通讯协议

这片SGP30使用的是I2C总线通讯,SCL与SDA需要与Jetson对应的引脚相连,可参考下图。

image.png

一般使用Jetson 40pin的3、5这一对I2C物理引脚(SDA、SCL)。

硬件连接

Jetson与SGP30物理连接参考下图。

image.png

依赖库准备

在正式编码前,记得装一下Adafruit的相应的库。

pip install adafruit-circuitpython-sgp30

adafruit的库会自动侦测0x58地址,即SGP30的I2C总线上的地址。

代码实现

由于使用I2C设备时,可能有异常导致I2C设备访问异常,记得使用软复位的方式解锁I2C总线。

def reset_i2c(): 
    try: 
        # 创建 I2C 对象 
        i2c = busio.I2C(board.SCL, board.SDA) 
        # 尝试锁定 I2C 总线 
        i2c.try_lock() 
        # 向地址为 0x58 的设备发送软复位命令 
        i2c.writeto(0x58, bytes([0x30, 0xA2])) 
        # 解锁 I2C 总线 
        i2c.unlock() 
    except Exception as e: 
        # 若复位过程中出现异常,打印错误信息 
        print("Reset error:", e) 
    finally: 
        # 等待 0.5 秒,确保复位操作完成 
        time.sleep(0.5)

否则,第二次使用I2C设备时,很可能就找不到相应的地址了。

完整实现如下:

import time 
import board 
import busio 
import adafruit_sgp30 
# 该函数用于对 I2C 总线进行软复位操作 
def reset_i2c(): 
    try: 
        # 创建 I2C 对象 
        i2c = busio.I2C(board.SCL, board.SDA) 
        # 尝试锁定 I2C 总线 
        i2c.try_lock() 
        # 向地址为 0x58 的设备发送软复位命令 
        i2c.writeto(0x58, bytes([0x30, 0xA2])) 
        # 解锁 I2C 总线 
        i2c.unlock() 
    except Exception as e: 
        # 若复位过程中出现异常,打印错误信息 
        print("Reset error:", e) 
    finally: 
        # 等待 0.5 秒,确保复位操作完成 
        time.sleep(0.5) 
    
# 该函数用于初始化 SGP30 传感器 
def initialize_sgp30(): 
    # 创建 I2C 对象,并设置频率为 100000 
    i2c = busio.I2C(board.SCL, board.SDA, frequency=100000) 
    try: 
        # 创建 Adafruit_SGP30 传感器实例 
        sgp30 = adafruit_sgp30.Adafruit_SGP30(i2c) 
        return sgp30 
    except Exception as e: 
        # 若初始化传感器时出现异常,打印错误信息并退出程序 
        print(f"初始化 SGP30 传感器时出错: {e}") 
        exit(1) # 该函数用于初始化传感器的基线 

def initialize_baseline(sgp30): 
    try: 
        # 初始化传感器的空气质量指数 
        sgp30.iaq_init() 
        # 设置传感器的空气质量基线 
        sgp30.set_iaq_baseline(0x8973, 0x8AAE) 
    except Exception as e: 
        # 若初始化基线时出现异常,打印错误信息 
        print(f"初始化传感器基线时出错: {e}") 
        
# 该函数用于对传感器进行预热操作 
    def preheat_sensor(): 
        # 打印提示信息,告知用户传感器正在预热 
        print("SGP30 传感器正在预热,请等待...") 
        # 循环 15 次,模拟 15 秒的预热时间 
        for i in range(15): 
            # 每次循环等待 1 秒 
            time.sleep(1) 
            # 显示预热进度 
            print(".", end="", flush=True) 
            # 预热完成后,打印完成信息 
            print(" 预热完成!") 
            
# 该函数用于从传感器读取二氧化碳和 TVOC 数据 
def read_data(sgp30): 
    try: 
        # 调用传感器的 iaq_measure 方法读取数据 
        eCO2, TVOC = sgp30.iaq_measure() 
        # 打印读取到的二氧化碳和 TVOC 数据 
        print(f"eCO₂: {eCO2} ppm, TVOC: {TVOC} ppb") 
        # 等待 1 秒后进行下一次读取 
        time.sleep(1) 
    except Exception as e: 
        # 打印错误信息 
        print(f"发生错误: {e}") 
        
# 主函数,程序的入口点 
def main(): 
    # 调用 reset_i2c 函数对 I2C 总线进行软复位 
    reset_i2c() 
    # 调用 initialize_sgp30 函数初始化 SGP30 传感器 
    sgp30 = initialize_sgp30() 
    # 调用 initialize_baseline 函数初始化传感器的基线
    initialize_baseline(sgp30) 
    # 调用 preheat_sensor 函数对传感器进行预热 
    preheat_sensor() 
    try: 
        # 进入无限循环,持续读取传感器数据 
        while True: 
            # 调用 read_data 函数读取并打印数据 
            read_data(sgp30) 
        except KeyboardInterrupt: 
            # 若用户按下 Ctrl+C 中断程序,打印提示信息 
            print("程序异常") 
        finally: 
            # 无论程序是否正常结束,都释放 I2C 资源 
            sgp30._i2c.deinit() 
            
if __name__ == "__main__": 
    # 调用主函数启动程序 
    main()

效果展示

程序执行效果如下:

image.png

这个效果,我还是相当满意的。