把附带的四针排针焊上之后,GY-SGP30 空气质量传感器只要四根杜邦线就能接到 Arduino Uno 或 ESP32:VIN、GND,再加两根 I2C 线(Uno 接 A4/A5,ESP32 接 GPIO21/22),然后用 Adafruit_SGP30 库从地址 0x58 读出 TVOC 和 eCO2。不过这些数字要会看:前 15 秒按设计固定输出 400 ppm 和 0 ppb;头 12 小时是传感器在学习“干净空气”长什么样;而 eCO2 并不是实测的 CO2。
SGP30 到底测的是什么?eCO2 是真正的 CO2 吗?
SGP30 是一颗金属氧化物(MOX)气体传感器:芯片里的微型加热板让一层很薄的金属氧化物膜保持高温。在干净空气中,氧气吸附在这层高温表面上,从膜里夺走电子,于是膜的电阻升高;而氢气、酒精和大多数 VOC 这类还原性气体会和被吸附的氧发生反应,电子回到膜里,电阻随之下降。芯片用两个通道观察这个效应——一个氢气(H2)信号和一个乙醇信号——再由片上算法换算成你通过 I2C 读到的两个数:TVOC(总挥发性有机化合物,0–60,000 ppb)和 eCO2(400–60,000 ppm),数据见 Sensirion SGP30 数据手册。也正因为有加热器,这颗传感器测量时电流约 48 mA,比绝大多数 I2C 模块都大,但由 Uno 或 ESP32 的电源脚供电完全没问题。
eCO2 里的那个“e”分量很重。这颗传感器里没有任何部件在测二氧化碳——CO2 已经完全氧化,不会和被吸附的氧反应,不释放电子,膜的电阻也就纹丝不动。SGP30 是从氢气通道估算出一个 CO2 当量:人呼出的气里带有消化过程产生的氢气,有人活动的房间也会积累 VOC,所以在日常室内环境中,这些信号通常和真实 CO2 一起升降。因此 eCO2 很适合回答“人和人的活动有没有让这间房的空气变差?”,却不适合用来核实通风量或判断 CO2 是否安全——因为在那种场合,这种相关性本身恰恰就是你需要去验证的东西。要真正数出 CO2 分子,得用光学 NDIR 传感器,比如我们 ESP32 空气质量监测仪里用的 SCD30。
所以两个输出都要当作趋势指标,而不是实验室测量值来看。在传感器旁边拔开一支油性记号笔的笔盖,TVOC 几秒内就会跳上去;打开窗户,两个数字都会慢慢降下来。
材料清单:SGP30 空气质量监测
Parts list
想做 WiFi 数据面板?ESP32 可以直接替换 Uno——它的 USB-C 口要用数据线,不能用只能充电的线。没有烙铁?5 针焊接服务会在发货前替你焊好 SGP30 的四个排针焊点。DHT22 用于下文讲的湿度补偿;OLED 让你不接电脑也能看读数。
GY-SGP30 怎么接到 Arduino Uno 或 ESP32?
GY-SGP30 模块到手时,四针排针是单独一条散装的——背面标着 VIN、GND、SCL、SDA 的金属化孔是空的,所以第一步是焊四个点。我们的排针焊接教程会配合一卷焊锡丝一步步带你做;如果不想自己焊,在可选清单里勾上焊接服务,排针就会焊好再寄出。
排针焊好后,整个接线只有四根线。把模块插到面包板上,用软的公对公杜邦线连到 Uno——关键在“软”字,因为面包板跳线套装里那种硬的 U 形线只能在面包板内部的孔之间跨接,够不到 Uno 的母排座。排针焊好后,其实连面包板都可以省掉:用公对母杜邦线直接把模块连到 Uno。ESP32 也要用这种线,因为它的引脚是公针:公头插在面包板上模块旁边,母头套到 ESP32 的引脚上。
| GY-SGP30 引脚 | Arduino Uno | ESP32(30 针 DevKit) |
|---|---|---|
| VIN | 5V | 3V3 |
| GND | GND | GND |
| SCL | A5(或 USB 那个角上的 SCL 脚) | GPIO22 |
| SDA | A4(或旁边的 SDA 脚) | GPIO21 |
两种供电电压都没错,原因是这样的:Sensirion 芯片本身工作在 1.8V 级别的电源上——1.62–1.98V,绝对最大值 2.16V——所以模块板上自带稳压器,从 VIN 接进来的电压生成这路电源,SDA 和 SCL 上还有电平转换,让只能跑 1.8V 的芯片能和 5V 或 3.3V 逻辑对话。Adafruit 和 SparkFun 的 SGP30 模块文档里写的也是同一套架构,这也是 VIN 能接 2V 到 5V 任意电压的原因。这同时意味着 VIN 决定了逻辑电平:SDA 和 SCL 的上拉电阻接在电平转换器的 VIN 一侧(这是模块上唯一高于 1.8V 的电源),所以你的开发板 I2C 引脚看到的就是 VIN 的电压。ESP32 上有一个坑:要接 3V3,不要接 DevKit 上自己那个标着 VIN 的脚——那个脚上是 USB 来的 5V,会把 5V 加到 ESP32 不耐 5V 的引脚上(Adafruit 的 SGP30 模块同样注明了 10k 上拉接在 Vin 上)。
用哪个库、哪段程序读出第一组 TVOC 和 eCO2?
SGP30 的标准 Arduino 驱动是 Adafruit_SGP30 库:在 IDE 里打开 Tools → Manage Libraries,搜索 “Adafruit SGP30” 并安装,顺便装上它提示需要的 Adafruit BusIO 辅助库。同一段程序在 ESP32 上不用改就能跑——那边的 Wire 默认就是 GPIO21/22——只要选对开发板,并用支持数据传输的 USB-C 线给 ESP32 上传即可。
#include <Wire.h>
#include "Adafruit_SGP30.h"
Adafruit_SGP30 sgp;
unsigned long lastBaselineReport = 0;
void setup() {
Serial.begin(115200);
while (!Serial) { delay(10); }
if (!sgp.begin()) {
Serial.println("SGP30 not found - check VIN, GND, SCL, SDA and the header joints");
while (1) { delay(10); }
}
Serial.print("SGP30 found, serial #");
Serial.print(sgp.serialnumber[0], HEX);
Serial.print(sgp.serialnumber[1], HEX);
Serial.println(sgp.serialnumber[2], HEX);
// 一周内保存过基准值?在这里用下面 BASELINE 行里
// 你自己的两个数字恢复它,就不用再等 12 小时:
// sgp.setIAQBaseline(0x8E68, 0x8F41);
}
void loop() {
if (!sgp.IAQmeasure()) {
Serial.println("Measurement failed");
delay(1000);
return;
}
Serial.print("eCO2: ");
Serial.print(sgp.eCO2);
Serial.print(" ppm TVOC: ");
Serial.print(sgp.TVOC);
Serial.println(" ppb");
// 每分钟打印一次基准值,方便你记下来
if (millis() - lastBaselineReport > 60000UL) {
lastBaselineReport = millis();
uint16_t eco2_base, tvoc_base;
if (sgp.getIAQBaseline(&eco2_base, &tvoc_base)) {
Serial.print("BASELINE eCO2: 0x");
Serial.print(eco2_base, HEX);
Serial.print(" TVOC: 0x");
Serial.println(tvoc_base, HEX);
}
}
delay(1000); // 基准算法要求每秒读一次
}
以 115200 波特率打开串口监视器(Serial Monitor)。序列号那一行就是接线正确的证明——只有 Uno 在 I2C 地址 0x58 上找到了应答的设备,它才会打印出来。接着是每秒一行的读数:大约前十五行都是不多不少的 400 ppm 和 0 ppb。这不是故障。收到初始化命令后,SGP30 要花 15 秒加热敏感膜、让它稳定下来,数据手册规定它在准备好之前就返回这两个固定的底值。之后数字才是实时的——对着传感器呼一口气,两个数都会跳起来。
为什么读数总在 400 和 0 附近?基准值又是什么?
SGP30 的输出从设计上就是相对值。MOX 膜的电阻会随温度、湿度和老化漂移,单看一个绝对电阻值毫无意义。所以芯片跑着一套动态基准补偿算法:它持续追踪自己遇到过的最干净的空气,把它定为参考点——eCO2 400 ppm、TVOC 0 ppb,也就是两个量程的底值——其余一切都按高出这个参考点多少来报告。
这个参考点是真实的空气,不是瞎猜的。根据 Sensirion 的气体传感器 FAQ,算法锚定的是干净的室外空气中始终存在的氢气,那是大约百万分之零点五的稳定本底,所以传感器每一到两周需要接触大约 10 分钟真正干净的空气。一间从不通风、一直关着开冷气的房间,永远给不了它这个锚点:闷浊的“日常”会被当成干净空气学进去,之后的读数就会偏低。
参考点也是故意慢慢移动的,免得臭了一小时就成了新的“正常”;所以要得到一个可信的参考点,需要大约 12 小时的通电运行。第一次运行期间开窗通风十分钟,第一天的绝对数字都只当作暂定值。传感器只在被请求时才测量,而算法期望每秒请求一次,所以程序里的 delay(1000) 是不能乱改的。
一断电,学到的参考点就没了——除非你把它保存下来。getIAQBaseline() 以两个 16 位数的形式读出算法的状态,程序每分钟打印一次这组数。串口监视器打开一次就一直开着,电脑也别让它休眠:打开串口监视器会让 Uno 重启,重启会重新执行 begin(),而这会重置 SGP30 的基准值,12 小时就得重新算起。头 12 小时过后,记下一组数;之后把 setIAQBaseline() 那一行取消注释,填上你自己的数字,传感器就能带着校准状态继续工作,不用从头学起。根据 Adafruit 的 SGP30 教程,这里有两条规矩:保存的那组数要定期更新(长期安装的设备每小时存一次到 EEPROM 或 flash);传感器断电超过大约一周——七天是官方给的上限——保存的基准值就算过期,让它重新学习。

怎样避免马来西亚的高湿度让读数失真?
水汽和其他气体一样,会参与 SGP30 高温敏感膜上的表面化学反应,所以湿度变化会像气体一样改变原始信号。芯片可以在片上做补偿,但前提是你得把湿度值发给它:数据手册写明,每次上电或软复位后,湿度补偿都处于关闭状态,直到收到一个湿度值为止。马来西亚室内 30°C、75% RH 的空气,每立方米约含 23 克水汽——几乎是数据手册自己举的 25°C、50% RH 例子中 11.8 g/m³ 的两倍——而且每下一场雨、冷气每开关一次,它都会大幅波动。不做补偿的话,这些波动就会被当成空气质量变化打印出来。顺带说一条硬性限制:数据手册规定传感器绝不能暴露在会结露的空气中(高于 90% RH),所以别把它放在浴室或其他会凝结水汽的地方。
解决办法就是把真实湿度告诉传感器。DHT22 提供温度和相对湿度;程序把它们换算成绝对湿度,交给 setHumidity(),单位是毫克每立方米。之所以用绝对湿度而不是相对湿度,是因为高温敏感膜响应的是到达表面的水分子数量,而不是房间离饱和还有多远:30°C 时的 75% RH,含水量大约比 22°C 时的 75% RH 多一半。
把 DHT22 模块的引脚插进面包板,再把开发板唯一的那路 5V(Uno)或 3V3(ESP32)电源和 GND 改接到面包板的电源轨上,让两个传感器共用。然后 DHT22 的 + 接电源轨,− 接 GND,out 接 D2,ESP32 上则接 GPIO4。ESP32 上别用 GPIO2:它是启动相关引脚,而 DHT22 的数据线空闲时是高电平,可能导致无法上传。在同一个 Library Manager 里安装 Adafruit 的 DHT sensor library(它提示需要的 Adafruit Unified Sensor 辅助库也一并装上),然后在上面的程序里加入这三段:
// 1) 放在最上面,#include "Adafruit_SGP30.h" 下一行:
#include "DHT.h"
#define DHTPIN 2 // DHT22 数据脚(ESP32 用 4,不要用 2 或只能输入的 34-39)
DHT dht(DHTPIN, DHT22);
// 由温度(C)和相对湿度(%)计算绝对湿度,单位 mg/m3
uint32_t absoluteHumidity(float t, float rh) {
float ah = 216.7f * ((rh / 100.0f) * 6.112f *
expf((17.62f * t) / (243.12f + t)) / (273.15f + t)); // g/m3
return (uint32_t)(1000.0f * ah); // mg/m3
}
// 2) 在 setup() 里,紧接在 Serial.begin(115200) 之后:
// dht.begin();
// 3) 在 loop() 的最前面,sgp.IAQmeasure() 之前:
float t = dht.readTemperature();
float rh = dht.readHumidity();
if (!isnan(t) && !isnan(rh)) {
sgp.setHumidity(absoluteHumidity(t, rh));
}
DHT11 也能做同样的事,预算更省,只是湿度分辨率更粗——两者的取舍见 DHT11 和 DHT22 怎么选。

我们常见的错误
因为读数正好是 400 和 0,就认定传感器坏了。前 15 秒,这两个值是写死的初始化输出;之后,它们就是干净空气的读数——两个量程的底值。真正的健康检查看的是有没有反应:对着传感器呼气,或在旁边拔开一支记号笔。数字跳起来,就说明什么都没坏。
VIN 对 VIN 地接。ESP32 DevKit 自己的 VIN 脚上是 USB 来的约 5V;模块接到那里,SDA 和 SCL 就会被上拉到 5V,而这些 GPIO 并不耐 5V。按表格接,别按丝印名字对:Uno 接 5V,ESP32 接 3V3。
用 eCO2 来判断通风。一间房的 eCO2 可能显示得让人放心,而真实 CO2 却在上升:SGP30 的数字是从氢气和 VOC 信号推算出来的,并不是在测 CO2;而在一间从不通风的房间里,它的基准值会把闷浊的空气学成 400。看人员活动的趋势:可以。认证一间教室的通风:那是 NDIR 传感器的活。
OLED 按位置接,而不是按标签接。0.96 寸 OLED 的第一个排针是 GND——和很多 VCC 在前的模块正好相反。凭“上次就是这样插的”去接,电源和地就会接反,可能直接烧掉屏幕。OLED(0x3C)和这颗传感器(0x58)可以和平共用一条 I2C 总线;屏幕那边的接线和代码见 DHT11 + OLED 温湿度监测教程。
ESP32 用了只能充电的 USB-C 线。板子能上电、会闪灯,却永远不会出现端口,因为这条线根本没有数据线芯。请用标明支持数据传输的线;如果端口还是不出现,按 ESP32 无法识别一文逐项排查。
常见问题
SGP30 的 eCO2 读数是真正的 CO2 吗?
不是。SGP30 是从氢气信号估算出一个 CO2 当量,依据是呼吸和室内活动释放的氢气、VOC 大致和 CO2 同步变化。它很适合追踪人员活动的趋势,但无法核实通风情况或 CO2 是否安全——那需要 NDIR 传感器,比如 SCD30,它用光学方法测量 CO2 分子。
SGP30 要多久才能给出准确读数?
分三个时间尺度:前 15 秒是固定的 400 ppm / 0 ppb 初始化输出;几分钟内趋势就能用;大约 12 小时的通电运行后,片上基准值形成,绝对数字才有意义。之后保存那组基准值,开机时恢复——有效期大约一周——传感器就能带着校准状态回来,而不是从头开始。每一到两周让它接触大约十分钟新鲜空气,参考点才能保持准确。
一块 Arduino 能接两个 SGP30 吗?
同一条总线上不行:I2C 地址固定为 0x58,没有地址跳线,两个地址相同的设备会冲突。可以把第二个传感器接到 I2C 多路复用器上,或者接到 ESP32 的第二条 I2C 总线(Wire1),或者每个传感器配一块开发板。
SGP30 能检测烟霾、烟雾或 PM2.5 吗?
它会对烟里的气体起反应,所以烟雾可能让 TVOC 读数升高,但它测不了烟霾或 PM2.5:烟霾是按细颗粒物来判断的,而气体传感器没法数颗粒。颗粒物读数需要光学 PM2.5 传感器,比如我们烟霾监测仪里用的那种;做烟雾和可燃气体报警项目,常用的是 MQ-2,但它只是学习用的作品,绝不能取代经过认证的烟雾报警器。SGP30 的专长是 VOC:溶剂、喷雾、材料释放的气体,还有人。
SGP30 能用在 5V 的 Arduino Uno 上吗?
GY-SGP30 模块可以,因为板载稳压器会把 VIN 降到 Sensirion 芯片自身 1.62–1.98V 的电源,电平转换器则负责转换 SDA 和 SCL。VIN 可以接 2V 到 5V 之间的任意电压,但要和开发板的逻辑电压一致,因为模块的 I2C 上拉电阻由 VIN 供电:Uno 接 5V 脚,ESP32 接 3V3 脚,绝不要接 ESP32 那个 5V 的 VIN 脚。只有不带模块板的裸 SGP30 芯片才严格是 1.8V 器件。
最后更新:2026 年 11 月。有问题?WhatsApp 联系我们。



GY-SGP30 AIR QUALITY SENSOR MODULE TVOC ECO2 SGP30 BREAKOUT I2C FOR ARDUINO
Arduino Uno Compatible SMD UNO R3 with Type B Cable - ATMEGA328P with CH340G-Microcontroller Project
MB102 Breadboard 170 400 830 Holes Breadboard Donut Board Arduino Prototype Multi Color - BREADBOARD (400 HOLES)
40pcs Dupont Wire 10cm 20cm 30cm for Breadboard DIY Experiment Jumper Wire Breadboard wire - DUPONT WIRE M-M 20CM
NodeMCU ESP32 Wi-Fi + Bluetooth Development Board CH340/CP2012 - For IOT Project - ESP-32 (CH340)
Data Cable Type-A Type-C MicroUSB Type-B 0.5m 1m 30cm 0.3m 100cm Data Transfer Upload Code - TYPE-A TO TYPE-C CABLE (1.0M)
Soldering Service for Circuit Boards & Electronics - 5 Pins Soldering Service
DHT 11 DHT 22 Temperature and Humidity Sensor DHT22 High Sensitivity Sensor DHT11 For Aduino IOT - DHT22 SENSOR
0.96‘ OLED Display Module Blue White Screen I2C IIC Serial 128X64 LCD Display Board - 0.96' OLED BLUE