基于MQ-135与Arduino的空气质量监测系统:从硬件连接到数据校准全解析 📅 发布时间:2026/8/19 10:05:27 👁 浏览次数: 1. 项目概述从传感器到数据一次完整的空气质量监测实践最近在工作室捣鼓一个环境监测的小项目核心就是这块MQ-135气体传感器。这玩意儿在创客圈和电子爱好者里挺常见的常被用来“感知”空气中的一些“不速之客”比如二氧化碳CO2、苯C6H6、氨气NH3、酒精、烟雾等等。它本质上是一个半导体气敏元件对多种可燃和有毒气体都有响应虽然选择性不算顶级但胜在成本低、电路简单、灵敏度高非常适合用来做定性或半定量的环境感知比如判断“室内空气是否浑浊”、“有没有可疑的酒精或烟雾泄漏”。我这次的目标就是把它和Arduino Uno板子结合起来搭建一个能实时读取、并在串口监视器上显示“气体浓度”变化的简易系统。整个过程涉及硬件连接、分压电路理解、代码编写以及最重要的——数据校准思路。别看原理简单真想让它输出一个相对靠谱、能反映趋势的数值而不是胡乱跳动的数字里头有不少细节和“坑”需要留意。这篇文章我就把从开箱到看到稳定数据的全过程连同我踩过的坑和总结的经验毫无保留地分享出来。2. 核心硬件解析与电路搭建2.1 MQ-135传感器深度拆解MQ-135传感器模块通常有两种形态一种是只有传感器本体的“裸板”需要自己搭建外围电路另一种是集成了必要电路主要是负载电阻和LM393比较器的“模块板”。我们最常见、也最推荐新手使用的是后者它通常有4个引脚VCC接5V、GND接地、DO数字输出、AO模拟输出。核心原理传感器内部有一个由二氧化锡SnO2等材料制成的气敏层。在清洁空气中其导电率较低。当存在目标气体时气敏层表面发生吸附反应导致其导电率增加。整个模块的工作就是通过测量这个导电率的变化来间接反映气体浓度。模拟输出AO这是我们将主要使用的引脚。它输出一个模拟电压值0-5V这个电压值与传感器敏感层的电阻亦即气体浓度成反比关系。气体浓度越高传感器电阻越低分压后AO引脚电压就越高。我们需要用Arduino的模拟输入引脚A0-A5来读取这个电压值。数字输出DO模块上通常有一个可调电位器蓝色的小方块。它连接到一个电压比较器如LM393我们可以通过旋转电位器设定一个阈值电压。当AO引脚电压代表浓度超过这个阈值时DO引脚会从高电平跳变为低电平反之亦然从而提供一个简单的“超标报警”开关信号。对于需要定量分析的场景我们主要使用AO。注意MQ-135需要预热这是很多新手会忽略的关键一点。传感器内部的敏感材料需要在一定温度下通过内部的加热丝提供才能进入稳定工作状态。通常需要通电预热5-20分钟其读数才会趋于稳定。冷启动时的数据是毫无参考价值的。2.2 硬件连接图与要点连接非常简单采用“模块板”可以极大简化操作MQ-135模块 VCC-Arduino 5V引脚MQ-135模块 GND-Arduino GND引脚MQ-135模块 AO-Arduino A0引脚或其他任意模拟输入引脚可选MQ-135模块 DO-Arduino D2引脚或其他任意数字输入引脚这里有一个非常重要的实操心得务必使用Arduino板载的5V和GND为传感器供电。虽然有些教程说可以接3.3V但MQ-135内部加热丝需要5V才能达到最佳工作温度接3.3V可能导致灵敏度下降、预热时间延长甚至工作不稳定。同时确保你的电源比如USB线或外部电源适配器能提供足够的电流Arduino Uno的板载稳压器能为整个系统提供约500mA的电流驱动一个MQ-135工作电流约150mA绰绰有余。3. 基础代码实现与串口可视化3.1 初始代码与原始数据读取连接好硬件后我们上传第一段代码目的是读取原始的模拟值并在串口绘图器中观察它的变化。// MQ-135 基础读取代码 const int sensorPin A0; // 定义传感器连接的模拟引脚 void setup() { Serial.begin(9600); // 启动串口通信波特率9600 // 可以在此处添加一些初始化提示信息 Serial.println(MQ-135 Sensor Initializing... Please wait for pre-heating.); } void loop() { int sensorValue analogRead(sensorPin); // 读取模拟值范围0-1023 Serial.println(sensorValue); // 将原始值打印到串口监视器 // 如果使用串口绘图器则使用 Serial.println(sensorValue); delay(100); // 延时100毫秒控制数据输出频率 }上传代码后打开Arduino IDE的串口绘图器Tools - Serial Plotter。你会看到一条曲线在跳动。刚通电时曲线可能会有一个明显的上升然后逐渐下降的过程这就是传感器在预热。让它运行至少5分钟曲线会逐渐平稳下来。这个0-1023的sensorValue就是我们的原始数据它对应A0引脚上0-5V的电压。3.2 将原始值转换为电压与电阻原始模拟值对我们来说不够直观。为了后续校准我们首先需要将其转换为传感器敏感层的电阻值。这需要理解模块的基本电路。模块上的AO引脚电压实际上是传感器电阻Rs和模块上一个固定负载电阻RL组成的分压电路的输出。通常模块上的RL是10kΩ。计算公式如下模拟电压值voltage sensorValue * (5.0 / 1023.0);传感器电阻Rs根据分压公式Vout Vcc * (RL / (Rs RL))可以推导出Rs RL * (Vcc - voltage) / voltage。其中Vcc5VRL10kΩ。我们在代码中加入这部分计算const int sensorPin A0; const float RL 10.0; // 负载电阻单位千欧(kΩ) const float Vcc 5.0; // 供电电压 void setup() { Serial.begin(9600); } void loop() { int sensorValue analogRead(sensorPin); float voltage sensorValue * (Vcc / 1023.0); float Rs RL * (Vcc - voltage) / voltage; // 计算传感器电阻单位kΩ Serial.print(Raw: ); Serial.print(sensorValue); Serial.print( | Voltage: ); Serial.print(voltage, 2); // 保留两位小数 Serial.print(V | Rs: ); Serial.print(Rs, 2); // 保留两位小数 Serial.println(kΩ); delay(1000); // 每秒输出一次 }现在串口监视器输出的信息就丰富多了。Rs值是我们校准的基石。在清洁空气中Rs会稳定在一个相对较高的值例如20-50kΩ具体因传感器个体和环境而异。当有目标气体如你呼出的二氧化碳靠近时Rs值会显著下降。4. 校准与气体浓度估算的核心方法论这是整个项目最核心、也最容易让人困惑的部分。MQ-135的数据手册会提供一种“灵敏度特性曲线”但直接使用它非常复杂。社区里更流行一种基于传感器电阻比Rs/R0的经验公式法。4.1 关键参数 R0 的获取R0指的是传感器在特定浓度洁净空气中的电阻值。对于MQ-135通常是指在100ppm氨气NH3或某种标准条件下的电阻。但对我们而言更实用的方法是测量传感器在当前环境中比如你认为空气良好的室内长时间预热稳定后的电阻将此值近似视为R0。操作步骤将传感器置于目标监测环境如通风良好的房间。运行上一节的代码让传感器预热至少30分钟以上确保读数完全稳定。记录下稳定后的Rs值例如测得Rs 35.6 kΩ。我们就把这个值定义为当前环境下的R0 35.6。重要注意事项R0不是一个绝对常数它会随着传感器老化、环境温湿度变化而缓慢漂移。因此对于要求不高的项目可以一次性测定后长期使用对于需要较高准确性的项目可能需要设计定期自动校准如每天在凌晨空气最好时自动记录R0的程序。4.2 利用 Rs/R0 比值与经验公式得到R0后我们就可以计算实时的电阻比ratio Rs / R0。气体浓度与这个ratio存在近似幂律关系。对于不同的气体有不同的经验公式系数。这些系数通常来源于社区实验或数据手册的曲线拟合。例如一个常用于估算**二氧化碳CO2浓度单位ppm**的公式如下ppm 116.602068 * (pow((Rs/R0), -2.769034857))这个公式是怎么来的它是对数坐标系下通过特定数据点拟合出的幂函数y a * x^b。其中a和b就是拟合系数。对于苯C6H6、氨气NH3等系数完全不同。在代码中实现const int sensorPin A0; const float RL 10.0; const float Vcc 5.0; const float R0 35.6; // 替换为你自己测得的R0值 void setup() { Serial.begin(9600); } void loop() { int sensorValue analogRead(sensorPin); float voltage sensorValue * (Vcc / 1023.0); float Rs RL * (Vcc - voltage) / voltage; float ratio Rs / R0; // 使用CO2的经验公式 float ppm_co2 116.602068 * pow(ratio, -2.769034857); Serial.print(Rs: ); Serial.print(Rs, 2); Serial.print(kΩ | Ratio: ); Serial.print(ratio, 4); Serial.print( | CO2 (approx): ); Serial.print(ppm_co2, 0); // 取整 Serial.println( ppm); // 可以添加其他气体的公式例如苯系数需另行查找 // float ppm_benzyne xxx * pow(ratio, yyy); delay(2000); // 每2秒读一次 }运行这段代码你就能看到一个估算的CO2浓度值。在通风环境下它可能读数在400-600ppm接近大气背景值。对着传感器轻轻吹气呼出的气体CO2含量高数值会急剧上升。4.3 校准的局限性与务实理解必须清醒认识到通过这种简单公式计算出的ppm值绝对精度是有限的尤其是对于MQ-135这种广谱传感器。它更容易受到其他干扰气体如酒精、香烟烟雾的影响。因此我们更应将其视为一个**“空气质量相对指数”或“特定气体浓度趋势指示器”**。它的核心价值在于趋势监测长时间观察浓度变化趋势判断通风效率。阈值报警设定一个安全阈值如CO2超过1000ppm报警虽然绝对值可能不准但用于触发提醒是有效的。比较性测量比较不同房间、不同时间段的空气“污染”程度。如果你需要实验室级别的精确CO2测量应该选择NDIR非分散红外传感器如MH-Z19B。MQ-135的优势在于低成本、多功能和快速响应适合定性或半定量应用。5. 项目优化与高级应用拓展5.1 软件滤波与数据平滑原始传感器读数会有噪声和抖动。直接使用单次读数会导致显示值频繁跳跃体验很差。我们可以采用简单的软件滤波来平滑数据。移动平均滤波法是一种简单有效的方法const int sensorPin A0; const int numReadings 10; // 平均采样次数 int readings[numReadings]; // 存储采样值的数组 int readIndex 0; // 当前读取索引 int total 0; // 总和 int average 0; // 平均值 void setup() { Serial.begin(9600); // 初始化数组所有值为0 for (int thisReading 0; thisReading numReadings; thisReading) { readings[thisReading] 0; } } void loop() { // 减去最早的读数加上最新的读数 total total - readings[readIndex]; readings[readIndex] analogRead(sensorPin); total total readings[readIndex]; readIndex readIndex 1; if (readIndex numReadings) { readIndex 0; // 到达数组末尾后归零 } average total / numReadings; // 计算移动平均值 // 使用这个平滑后的 average 值进行后续电压、电阻和浓度计算 float voltage average * (5.0 / 1023.0); // ... 后续计算与之前相同 delay(100); // 采样间隔可以更短因为输出已经是平滑后的值 }5.2 构建本地空气质量监测节点单一的串口输出实用性有限。我们可以将其升级为一个真正的监测节点添加显示连接一个OLED屏幕如SSD1306实时显示浓度数值和简单的状态图标笑脸/哭脸。添加声光报警连接一个LED和一个蜂鸣器。当浓度超过设定阈值时LED闪烁蜂鸣器鸣叫。数据记录添加一个SD卡模块定期将时间戳和浓度值写入CSV文件用于长期趋势分析。物联网IoT集成连接ESP8266或ESP32模块将数据通过Wi-Fi发送到云端平台如ThingsBoard、Blynk或自建的MQTT服务器实现远程手机监控和历史数据图表查看。5.3 多传感器融合与交叉验证由于MQ-135的选择性问题单独使用它来判断具体是哪种气体超标是困难的。一个更可靠的方案是进行多传感器融合搭配温湿度传感器如DHT22因为许多气体的灵敏度受温湿度影响补偿后数据更准。搭配特定气体传感器如果主要关心CO2可以增加一个MH-Z19B作为基准用MQ-135作为辅助和冗余。如果关心TVOC总挥发性有机物可以搭配SGP30传感器。逻辑判断例如当MQ-135读数升高而温湿度变化不大时可能是CO2如果同时有酒精传感器如MQ-3也升高则可能是酒精泄露。通过简单的逻辑规则可以提高判断准确性。6. 常见问题、故障排查与维护心得在实际操作中你几乎一定会遇到下面这些问题。这里是我的排查清单和解决建议问题现象可能原因排查步骤与解决方案读数始终为0或1023接线错误或接触不良传感器模块损坏。1. 用万用表检查VCC和GND之间是否有5V电压。2. 检查AO引脚与Arduino A0引脚的连接。3. 尝试更换一个模拟输入引脚和代码中的引脚定义。4. 在空气中测量AO对GND电压正常应在0.8V-4V之间波动否则模块可能已损坏。数值乱跳极不稳定电源噪声接线过长或松动未预热。1.确保充分预热至少10-20分钟。2. 在Arduino的5V和GND之间靠近传感器模块处并联一个100μF的电解电容可有效平滑电源。3. 检查所有杜邦线连接确保插紧。尽量使用短线。4. 在代码中实施移动平均滤波见上一节。对目标气体无反应或反应迟钝传感器老化寿命通常1-3年预热不充分气体不在敏感范围内。1. 确认已充分预热。2. 尝试用明确的干扰源测试如打火机释放少量丁烷注意安全远离明火或高度白酒靠近看读数是否有剧烈变化。如果有说明传感器基本正常。3. MQ-135对某些气体如低浓度CO2灵敏度本身就不高反应慢是正常的。计算出的浓度值明显不合理如CO2始终好几千R0值设定错误经验公式系数不匹配环境本底值高。1.重新校准R0在清晨通风良好的室外或你认为空气最好的地方长时间预热后测量Rs作为新的R0。2. 确认使用的经验公式系数是否适用于你的目标气体。不同来源的系数可能有差异。3. 理解这是估算值关注其相对变化而非绝对数值。传感器发热严重这是正常现象。内部加热丝在工作。确保模块没有接触易燃物并留出一定的散热空间即可。工作温度较高是这类半导体气敏传感器的共同特点。长期使用与维护建议避免长期暴露于高浓度气体虽然传感器能恢复但长期处于极端环境会加速老化。定期校准对于重要应用建议每月或每季度在已知的清洁空气中重新测定一次R0值。注意中毒硅基化合物、硫化物等可能导致传感器永久性中毒失效应避免接触。存储长期不使用时最好放在干燥密封的袋子里。折腾完这一整套从硬件连接到软件滤波再到校准逻辑的思考你会发现一个简单的传感器项目背后贯穿了模拟电路、数据采集、信号处理和系统设计的基本思想。MQ-135就像一个窗口让你能以极低的成本窥探周围不可见的气体世界。它的数据或许不够“精确”但足够“有用”。关键在于你如何理解它的输出如何设计系统来扬长避短。最后别忘了所有基于电阻变化的气敏传感器都受温湿度影响巨大如果你的项目对稳定性要求高下一步就是考虑如何集成温湿度传感器进行补偿那又是另一个有趣的故事了。