用Arduino Nano和SGP30传感器DIY一个桌面空气质量监测仪(附完整代码)

张开发
2026/4/6 20:50:51 15 分钟阅读

分享文章

用Arduino Nano和SGP30传感器DIY一个桌面空气质量监测仪(附完整代码)
用Arduino Nano和SGP30传感器DIY一个桌面空气质量监测仪附完整代码最近几年室内空气质量越来越受到人们的关注。尤其是在办公室或居家环境中CO2和TVOC浓度过高会导致疲劳、头痛甚至影响长期健康。作为一个电子爱好者我发现用Arduino Nano和SGP30传感器可以轻松搭建一个实用的空气质量监测仪成本不到100元却能提供专业级的监测功能。这个项目特别适合想要入门智能家居开发的创客。你不需要复杂的电路知识只要会使用Arduino IDE就能完成。最终成品可以放在办公桌上实时显示CO2和TVOC数值当空气质量不佳时会发出提醒。下面我就详细介绍如何从零开始制作这个小设备。1. 硬件准备与连接1.1 所需材料清单制作这个空气质量监测仪你需要准备以下硬件主控板Arduino Nano或UNO一个传感器SGP30气体传感器模块显示屏0.96寸OLED屏幕I2C接口连接线杜邦线若干电源Micro USB线或9V电池其他面包板可选、外壳可选提示SGP30传感器价格约50-80元建议选择带稳压电路的模块版本稳定性更好。1.2 硬件连接示意图SGP30和OLED都通过I2C接口与Arduino连接接线非常简单Arduino Nano引脚SGP30/OLED引脚5VVCCGNDGNDA4SDAA5SCL实际连接时需要注意SGP30和OLED可以并联在同一个I2C总线上如果使用面包板建议给I2C线路加上4.7kΩ上拉电阻长距离连接时超过20cm建议使用屏蔽线2. 软件环境配置2.1 安装必要的库在Arduino IDE中我们需要安装两个关键库Adafruit_SGP30用于与SGP30传感器通信Adafruit_SSD1306用于驱动OLED显示屏安装步骤打开Arduino IDE点击工具-管理库...搜索并安装上述两个库同时安装依赖库Adafruit_GFX2.2 基础代码框架我们先建立一个基本的代码框架包含必要的初始化和库引用#include Wire.h #include Adafruit_SGP30.h #include Adafruit_GFX.h #include Adafruit_SSD1306.h #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 Adafruit_SGP30 sgp; Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, Wire); void setup() { Serial.begin(9600); // 初始化OLED if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println(F(SSD1306分配失败)); while(1); } // 初始化SGP30 if (!sgp.begin()){ Serial.println(SGP30传感器未找到); while (1); } Serial.println(初始化完成); }3. 传感器数据读取与处理3.1 读取CO2和TVOC数据SGP30传感器通过I2C接口提供CO2和TVOC数据。在Adafruit库的帮助下读取数据非常简单void loop() { if (!sgp.IAQmeasure()) { Serial.println(测量失败); return; } uint16_t co2 sgp.eCO2; // CO2浓度单位ppm uint16_t tvoc sgp.TVOC; // TVOC浓度单位ppb Serial.print(CO2: ); Serial.print(co2); Serial.println( ppm); Serial.print(TVOC: ); Serial.print(tvoc); Serial.println( ppb); delay(1000); }3.2 传感器预热与校准SGP30需要15-30秒的预热时间才能提供准确读数。在此期间CO2读数会固定在400ppmTVOC为0ppb。我们可以添加一个等待初始化的逻辑bool waitForSensorReady() { unsigned long startTime millis(); while (millis() - startTime 30000) { // 最多等待30秒 if (sgp.IAQmeasure()) { if (sgp.eCO2 ! 400 || sgp.TVOC ! 0) { return true; } } delay(1000); } return false; }4. 数据显示与界面设计4.1 OLED显示实现我们将使用OLED屏幕显示实时数据。下面是一个简单的显示函数void updateDisplay(uint16_t co2, uint16_t tvoc) { display.clearDisplay(); // 显示标题 display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,0); display.println(空气质量监测); // 显示CO2数据 display.setCursor(0, 20); display.print(CO2: ); display.print(co2); display.println( ppm); // 显示TVOC数据 display.setCursor(0, 40); display.print(TVOC: ); display.print(tvoc); display.println( ppb); // 根据空气质量显示提示 display.setCursor(0, 55); if (co2 1000 || tvoc 500) { display.println(空气质量差); } else { display.println(空气质量良好); } display.display(); }4.2 添加可视化元素为了让数据显示更直观我们可以添加一些简单的图形元素void drawCO2Indicator(uint16_t co2) { // 绘制背景条 display.drawRect(70, 20, 50, 10, WHITE); // 根据CO2值填充 int fillWidth map(constrain(co2, 400, 2000), 400, 2000, 0, 50); display.fillRect(70, 20, fillWidth, 10, WHITE); }5. 完整代码与优化5.1 完整项目代码将前面各部分组合起来我们得到完整的项目代码#include Wire.h #include Adafruit_SGP30.h #include Adafruit_GFX.h #include Adafruit_SSD1306.h #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 Adafruit_SGP30 sgp; Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, Wire); bool waitForSensorReady() { unsigned long startTime millis(); while (millis() - startTime 30000) { if (sgp.IAQmeasure()) { if (sgp.eCO2 ! 400 || sgp.TVOC ! 0) { return true; } } delay(1000); } return false; } void updateDisplay(uint16_t co2, uint16_t tvoc) { display.clearDisplay(); display.setTextSize(1); display.setTextColor(WHITE); display.setCursor(0,0); display.println(空气质量监测); display.setCursor(0, 20); display.print(CO2: ); display.print(co2); display.println( ppm); display.setCursor(0, 40); display.print(TVOC: ); display.print(tvoc); display.println( ppb); drawCO2Indicator(co2); display.setCursor(0, 55); if (co2 1000 || tvoc 500) { display.println(空气质量差); } else { display.println(空气质量良好); } display.display(); } void drawCO2Indicator(uint16_t co2) { display.drawRect(70, 20, 50, 10, WHITE); int fillWidth map(constrain(co2, 400, 2000), 400, 2000, 0, 50); display.fillRect(70, 20, fillWidth, 10, WHITE); } void setup() { Serial.begin(9600); if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println(F(SSD1306分配失败)); while(1); } if (!sgp.begin()){ Serial.println(SGP30传感器未找到); while (1); } Serial.println(等待传感器初始化...); if (!waitForSensorReady()) { Serial.println(传感器初始化失败); while(1); } Serial.println(传感器就绪); } void loop() { if (!sgp.IAQmeasure()) { Serial.println(测量失败); return; } uint16_t co2 sgp.eCO2; uint16_t tvoc sgp.TVOC; Serial.print(CO2: ); Serial.print(co2); Serial.println( ppm); Serial.print(TVOC: ); Serial.print(tvoc); Serial.println( ppb); updateDisplay(co2, tvoc); delay(2000); // 每2秒更新一次 }5.2 项目优化建议完成基础功能后可以考虑以下优化添加蜂鸣器报警当空气质量超过阈值时发出声音提醒数据记录功能使用SD卡模块记录历史数据WiFi上传通过ESP8266模块将数据上传到物联网平台低功耗优化使用睡眠模式延长电池供电时间6. 实际应用与问题排查6.1 典型应用场景这个空气质量监测仪可以用于办公室空气质量监测新装修房屋的甲醛检测学校教室通风情况监测实验室环境监测6.2 常见问题与解决方案在实际使用中可能会遇到以下问题传感器读数不稳定确保电源稳定建议使用线性稳压电源避免将传感器放置在通风口或阳光直射处添加软件滤波算法OLED不显示检查I2C地址是否正确通常为0x3C或0x3D确认接线正确特别是电源线尝试降低I2C时钟速度SGP30无法初始化检查I2C上拉电阻4.7kΩ确保供电电压在3.3V-5V之间尝试重新插拔传感器// 简单的软件滤波示例 #define FILTER_SAMPLES 5 uint16_t filterCO2(uint16_t newValue) { static uint16_t values[FILTER_SAMPLES] {0}; static uint8_t index 0; values[index] newValue; index (index 1) % FILTER_SAMPLES; uint32_t sum 0; for(uint8_t i0; iFILTER_SAMPLES; i) { sum values[i]; } return sum / FILTER_SAMPLES; }制作过程中我发现SGP30对温度变化比较敏感最好在室温稳定的环境下使用。另外传感器的使用寿命约6年但需要每6个月进行一次校准可以通过将设备放置在室外新鲜空气中几小时来完成。

更多文章