Komponen · 13 mnt baca

Tutorial MQ135 Arduino: Sensor Kualitas Udara, Kalibrasi, dan PPM

Panduan MQ135 Arduino: gas yang dideteksinya, pemanasan awal 24–48 jam, kalibrasi R0 dan rumus ppm, apakah bisa mengukur CO2, kendali kipas, pencatatan dengan ESP32, dan bedanya dengan CCS811.

Proyek MQ135 Arduino adalah persinggahan pertama bagi siapa pun yang ingin cara murah dan sederhana untuk memantau seberapa bersih udara di sebuah ruangan. MQ-135 adalah sensor gas oksida logam berpemanas yang bereaksi terhadap gas seperti amonia, nitrogen oksida, benzena, alkohol, dan asap. Di kit hobi, sensor ini biasanya datang sebagai modul kecil dengan chip komparator dan potensiometer pengatur; modul disambung ke Arduino lewat output analognya dan dibaca dengan satu analogRead(). Tapi mengubah angka dari sensor ini menjadi pengukuran yang bermakna butuh pengetahuan sedikit lebih banyak daripada yang dijelaskan kebanyakan tutorial.

Di panduan ini kamu akan belajar apa yang terjadi di dalam sensor, seberapa peka sensor terhadap gas yang mana, dan kenapa sensor perlu dipanaskan 24–48 jam sebelum benar-benar dipakai pertama kali. Setelah itu kita menyusun perhitungan ppm langkah demi langkah dengan resistor beban (RL), hambatan sensor (Rs), dan hambatan referensi (R0), melakukan kalibrasi R0 di udara bersih, dan memberi jawaban jujur untuk pertanyaan yang paling sering muncul: apakah MQ-135 benar-benar mengukur CO2? Terakhir, kita menjalankan kipas ventilasi secara otomatis, mencatat hasil pembacaan dengan ESP32 ke file dengan cap waktu, menulis kode MicroPython untuk Raspberry Pi Pico, dan membandingkan MQ-135 dengan CCS811 serta sensor CO2 NDIR.

Modul sensor kualitas udara MQ-135
Modul MQ-135: sensor oksida logam berpemanas, komparator LM393, potensiometer sensitivitas, dan pin VCC, GND, DO, AO.

Apa itu MQ-135 dan bagaimana cara kerjanya?

Di balik jaring baja tahan karat, permukaan tabung keramik kecil dilapisi timah dioksida (SnO2), dan kawat pemanas yang melewati tabung itu memanaskan lapisan ini sampai beberapa ratus derajat Celsius. Di udara bersih, molekul oksigen menempel di permukaan SnO2, menangkap elektron bebas di material, dan hambatan lapisan tetap tinggi. Ketika gas pereduksi seperti amonia, alkohol, atau benzena masuk ke udara, gas itu bereaksi dengan oksigen di permukaan, elektron terlepas, dan hambatannya turun. Makin pekat gasnya, makin rendah hambatannya. Modul memasang hambatan ini dalam pembagi tegangan bersama resistor beban, sehingga tegangan di pin AO naik ketika gas bertambah.

SpesifikasiNilai
Material penginderaanTimah dioksida (SnO2), tabung keramik berpemanas
Tegangan pemanas5 V ± 0,1 V
Hambatan dan arus pemanas33 Ω ± 5%, sekitar 150 mA
Daya pemanasMaksimal 800 mW
Rentang deteksiNH3 10–300 ppm, benzena 10–1000 ppm, alkohol 10–300 ppm
Pemanasan awal pertamaLebih dari 24 jam
Kondisi kerja−10 sampai 45 °C, kelembapan relatif di bawah 95%
Output modulAO (analog) dan DO (ambang digital lewat LM393)

Gas apa saja yang dideteksi MQ-135?

MQ-135 bukan sensor selektif yang mengukur satu gas; sensor ini bereaksi sekaligus terhadap banyak gas yang bereaksi dengan permukaan SnO2 yang panas, dan tidak bisa membedakannya. Produsen menyebutnya sangat peka terhadap amonia, senyawa belerang, dan uap sejenis benzena; sensor ini juga merespons jelas terhadap alkohol, asap, dan nitrogen oksida. Karena itu MQ-135 paling tepat dianggap sebagai “indikator polusi udara”: ketika nilainya naik, sensor memberi tahu bahwa ada yang berubah di udara, tapi tidak memberi tahu apa. Untuk kebocoran gas alam dan LPG (elpiji), sensor gas MQ-2 yang dirancang untuk tugas itu jauh lebih cocok.

GasDari mana asalnya di rumah?Respons MQ-135
Amonia (NH3)Produk pembersih, pasir kucing, pupukTinggi
Benzena, toluena, dan pelarutCat, tiner, lem, asap rokokTinggi
Uap alkoholHand sanitizer, kolonye, parfumTinggi
AsapMemasak, rokok, lilinSedang
Nitrogen oksida (NOx)Kompor gas, asap knalpotSedang
Karbon dioksida (CO2)Napas manusia, ruangan tertutup dan ramaiLemah, tidak langsung

Apakah MQ-135 mengukur CO2?

Jawaban singkatnya: tidak benar-benar mengukur; sensor ini memperkirakannya. Datasheet MQ-135 memuat kurva CO2, dan kebanyakan library di internet menghitung nilai “CO2 ppm” dari kurva itu. Tapi CO2 adalah gas yang stabil secara kimia dan hanya bereaksi sangat lemah dengan permukaan SnO2. Di ruangan tertutup, ketika orang bernapas, kelembapan dan senyawa organik volatil yang dilepaskan tubuh ikut naik bersama CO2, dan itulah yang sebenarnya direspons MQ-135. Jadi “CO2” yang ditampilkan sensor sebenarnya adalah perkiraan berdasarkan polusi udara ruangan secara keseluruhan. Bukti paling mudah: buka sebotol kolonye di dekatnya dan lihat nilai “CO2” melonjak sampai 5000 ppm.

Bukan berarti MQ-135 tidak berguna. Sensor ini bekerja sangat baik untuk keputusan relatif seperti “ruangan mulai pengap, buka jendela” atau “ada asap di dapur, nyalakan penyedot asap”. Tapi kalau kamu butuh nilai CO2 yang sebenarnya di ruang kelas, kantor, atau kamar tidur, sebaiknya kamu memakai salah satu sensor CO2 NDIR dari perbandingan di akhir panduan ini. Tabel di bawah merangkum arti angka dari alat ukur CO2 sungguhan; perkiraan MQ-135 bisa kamu tafsirkan dengan rentang yang sama.

CO2 (ppm)Apa artinya?
400–450Udara luar yang bersih
450–800Ruang dalam dengan ventilasi baik
800–1000Masih bisa diterima, pertimbangkan ventilasi
1000–1500Udara pengap, konsentrasi bisa menurun; buka ventilasi
1500–2000Sakit kepala dan kantuk bisa muncul
5000Batas paparan 8 jam di tempat kerja

Pengkabelan MQ-135 ke Arduino

Pin modulArduino UnoESP32Raspberry Pi Pico
VCC (termasuk pemanas)5VVIN (5 V dari USB)VBUS (5 V dari USB)
GNDGNDGNDGND
AO (output analog)A0GPIO 34, lewat pembagi 10 kΩ / 20 kΩGP26 (ADC0), lewat pembagi 10 kΩ / 20 kΩ
DO (ambang digital, opsional)D2GPIO mana saja lewat pembagiPin GP mana saja lewat pembagi
Pemanas MQ-135 sendiri sudah menarik sekitar 150 mA dan wajib mendapat 5 V; kalau diberi daya dari pin 3V3 ESP32 atau Pico, sensor tidak cukup panas dan hasil bacaannya tidak bermakna. Ketika modul bekerja di 5 V, output AO bisa naik sampai 5 V, dan itu merusak input ADC 3,3 V pada ESP32 dan Pico. Buat pembagi tegangan 10 kΩ + 20 kΩ antara AO dan GND, lalu sambungkan titik tengahnya ke pin ADC: 5 V × 20 / 30 = 3,33 V. Pasangan resistor lain bisa kamu coba dengan kalkulator pembagi tegangan. Sensor yang sedang bekerja menjadi terlalu panas untuk dipegang; jangan sentuh jaringnya.

Pemanasan: burn-in 24–48 jam dan pemanasan harian

Sensor seri MQ punya dua pemanasan yang berbeda, dan orang sering mencampuradukkannya. Yang pertama adalah pemanasan awal (burn-in): kelembapan dan kontaminasi menumpuk di permukaan sensor yang baru keluar dari kotak atau yang lama tersimpan tanpa dipakai. Produsen meminta sensor diberi daya lebih dari 24 jam sebelum pengukuran standar; dalam praktiknya, menjalankannya terus-menerus selama 24–48 jam membuatmu bisa melihat nilainya bergeser pelan dan akhirnya stabil. Kalau kalibrasi R0 kamu lakukan sebelum periode ini selesai, semua hasil bacaanmu akan bergeser dalam beberapa hari. Yang kedua adalah pemanasan harian: sensor yang sudah menyelesaikan burn-in tetap butuh beberapa menit setiap kali dinyalakan supaya pemanasnya mencapai keseimbangan; nilai di menit pertama jelas terlalu tinggi atau terlalu rendah. Karena itu kodenya memuat penantian minimal 2–3 menit; untuk pengukuran presisi, menunggu 10–20 menit lebih baik.

Rs, RL, dan R0: bagaimana menghitung ppm dengan MQ-135?

Di dalam modul, hambatan sensor Rs dan resistor beban RL di board terpasang seri dan berbagi 5 V. Tegangan di pin AO adalah Vout = 5 × RL / (Rs + RL). Balik rumus ini dan kamu mendapat hambatan sensor pada momen itu dari tegangan yang kamu ukur: Rs = RL × (5 − Vout) / Vout. Di Arduino Uno, ADC memakai 5 V yang sama sebagai referensi, jadi kamu bahkan tidak perlu mengubahnya ke volt: Rs = RL × (1023 − raw) / raw (raw = nilai mentah dari ADC). Rs saja tidak bermakna, karena hambatannya sangat berbeda dari satu sensor ke sensor lain. Yang penting adalah perbandingan Rs dengan nilainya di udara yang sudah diketahui, yang disebut R0.

Kurva di datasheet menghubungkan rasio Rs/R0 dengan konsentrasi gas dan hampir berupa garis lurus pada sumbu log-log. Artinya kurva itu bisa dinyatakan dengan fungsi pangkat: ppm = A × (Rs/R0)^−B. Koefisien yang dipakai library MQ-135 populer untuk kurva CO2 adalah A = 116,602 dan B = 2,769. Untuk mencari R0, sensor ditaruh di udara luar yang bersih; karena CO2 di udara luar sekarang sekitar 420 ppm, rumusnya dibalik dan kamu menghitung R0 = Rs × (420 / A)^(1/B) ≈ Rs × 1,59. Ingat bahwa koefisien ini berbeda untuk gas lain dan hasilnya hanya perkiraan.

Salah satu resistor SMD kecil di bagian belakang modul adalah RL, dan kode yang tercetak di atasnya menunjukkan nilainya: 102 = 1 kΩ, 103 = 10 kΩ, 203 = 20 kΩ. Kode-kode ini kami jelaskan di kode resistor SMD. Memasukkan RL yang salah tidak mengubah hasil ppm, karena R0 dihitung dengan RL yang sama dan rasionya tetap; hanya angka Rs dan R0 yang kamu lihat di layar yang berubah skalanya. Tapi kalau RL sangat kecil (1 kΩ), tegangan AO tetap sangat rendah di udara bersih dan resolusi ADC jadi buruk; kalau nilainya terlihat bergoyang, merata-ratakan pembacaan adalah solusi yang bagus.

Kalibrasi R0 MQ-135 langkah demi langkah

  1. Sambungkan VCC modul ke 5V, GND ke GND, dan AO ke A0, lalu selesaikan pemanasan awal dengan menjalankan sensor tanpa henti selama 24–48 jam.
  2. Baca kode pada resistor beban di bagian belakang board dan atur RL_KOHM di kode di bawah agar sesuai.
  3. Bawa rangkaian ke udara luar yang bersih, misalnya balkon atau depan jendela yang terbuka, jauh dari lalu lintas, rokok, dan dapur.
  4. Upload kode kalibrasi, buka Serial Monitor di 9600 baud, dan tunggu minimal 10 menit.
  5. Begitu rata-rata R0 di layar hampir tidak berubah selama beberapa menit, catat nilainya; itulah R0 sensormu.
C++ (Arduino IDE)
1const byte MQ_PIN = A0;                 // MQ-135 AO
2const float RL_KOHM = 1.0;              // karttaki yük direnci: 102 = 1, 103 = 10 / load resistor on the board
3const float PARA = 116.6020682;         // CO2 eğrisi katsayıları / CO2 curve coefficients
4const float PARB = 2.769034857;
5const float CLEAN_AIR_PPM = 420.0;      // dış havadaki CO2 / CO2 in outdoor air
6
7float r0Average = 0;
8
9float readRs() {
10  long sum = 0;
11  for (int i = 0; i < 50; i++) {        // 50 ölçüm, yaklaşık 1 saniye / 50 readings, about 1 second
12    sum += analogRead(MQ_PIN);
13    delay(20);
14  }
15  float raw = sum / 50.0;
16  if (raw < 1) raw = 1;                 // sıfıra bölmeyi önle / avoid dividing by zero
17  return RL_KOHM * (1023.0 - raw) / raw;   // Rs = RL × (Vc − Vout) / Vout
18}
19
20void setup() {
21  Serial.begin(9600);
22  Serial.println(F("Temiz havada en az 10 dk bekle / wait at least 10 min in clean air"));
23}
24
25void loop() {
26  float rs = readRs();
27  float r0 = rs * pow(CLEAN_AIR_PPM / PARA, 1.0 / PARB);    // R0 = Rs × (420 / A)^(1/B)
28  if (r0Average == 0) r0Average = r0;
29  r0Average = r0Average * 0.95 + r0 * 0.05;                // yavaş ortalama / slow running average
30
31  Serial.print(F("Rs = "));
32  Serial.print(rs, 2);
33  Serial.print(F(" kOhm   R0 = "));
34  Serial.print(r0, 2);
35  Serial.print(F("   ortalama / average R0 = "));
36  Serial.println(r0Average, 2);
37}

Setiap detik kode merata-ratakan 50 pembacaan, menghitung Rs dan R0 terkini darinya, lalu memasukkan nilai ini ke rata-rata bergerak yang lambat. Rata-rata bergerak ini mencegah embusan singkat asap knalpot yang terbawa angin merusak hasilnya. R0 yang kamu temukan hanya berlaku untuk sensor itu dan nilai RL itu; kalau sensornya diganti, kalibrasi lagi. Dalam hitungan bulan, seiring sensor menua, R0 bergeser perlahan, jadi untuk proyek yang berjalan lama, mengulang kalibrasi setiap beberapa bulan adalah kebiasaan yang baik.

Kode pengukuran: perkiraan ppm dan tingkat kualitas udara

Setelah menemukan R0, masukkan nilainya ke kode pengukuran. Kode pertama-tama menunggu 3 menit untuk pemanasan, lalu setiap 2 detik mencetak rasio Rs/R0, perkiraan ppm, dan label kualitas udara berdasarkan tabel di atas ke Serial Monitor. Di udara bersih rasionya sekitar 0,6; makin kecil nilainya, makin banyak gas di udara. Untuk mengujinya, teteskan sedikit kolonye ke kapas di dekat sensor: dalam beberapa detik rasionya turun dan ppm naik, dan ketika kapasnya dijauhkan, nilainya kembali normal dalam beberapa menit.

C++ (Arduino IDE)
1const byte MQ_PIN = A0;
2const float RL_KOHM = 1.0;              // kalibrasyondaki RL ile aynı / same RL as in calibration
3const float R0_KOHM = 3.6;              // kendi kalibrasyon sonucunla değiştir / replace with your calibration result
4const float PARA = 116.6020682;
5const float PARB = 2.769034857;
6const unsigned long WARMUP_MS = 180000; // 3 dk ısınma / 3 min warm-up
7
8float readRs() {
9  long sum = 0;
10  for (int i = 0; i < 20; i++) {
11    sum += analogRead(MQ_PIN);
12    delay(10);
13  }
14  float raw = sum / 20.0;
15  if (raw < 1) raw = 1;
16  return RL_KOHM * (1023.0 - raw) / raw;
17}
18
19const __FlashStringHelper* airLabel(float ppm) {
20  if (ppm < 800)  return F("Iyi / good");
21  if (ppm < 1000) return F("Orta / moderate");
22  if (ppm < 1500) return F("Havalandir / ventilate");
23  return F("Kotu / poor");
24}
25
26void setup() {
27  Serial.begin(9600);
28  Serial.println(F("Isiniyor / warming up..."));
29  while (millis() < WARMUP_MS) delay(100);
30}
31
32void loop() {
33  float ratio = readRs() / R0_KOHM;           // gaz arttıkça küçülür / falls as gas rises
34  float ppm = PARA * pow(ratio, -PARB);       // tahmini CO2 eşdeğeri / estimated CO2 equivalent
35
36  Serial.print(F("Rs/R0 = "));
37  Serial.print(ratio, 2);
38  Serial.print(F("   ~"));
39  Serial.print(ppm, 0);
40  Serial.print(F(" ppm   "));
41  Serial.println(airLabel(ppm));
42  delay(2000);
43}

Bagaimana suhu dan kelembapan memengaruhi MQ-135?

Hambatan sensor oksida logam tidak hanya bergantung pada gas, tapi juga pada suhu dan kelembapan ruangan. Menurut kurva datasheet, di udara yang sama rasio Rs/R0 turun cukup jelas ketika suhu naik dari 20 °C ke 40 °C, dan juga turun ketika kelembapan bertambah; sensor membaca ini sebagai “lebih banyak gas”. Hasilnya, nilai ppm naik sendiri di ruangan yang terkena sinar matahari sore atau di kamar mandi setelah mandi. Ada dua cara untuk mengurangi efek ini: kalibrasi pada suhu dan kelembapan yang mendekati tempat sensor akan dipakai, atau ukur suhu dan kelembapan dengan DHT22 atau DHT11 lalu terapkan rumus koreksi dari library. Fungsi seperti getCorrectedPPM(temperature, humidity) di library MQ135 siap pakai melakukan hal itu. Kalau kamu ingin mengukur suhu dan kelembapan lebih akurat daripada DHT11, kamu bisa memakai sensor BME280.

Otomatisasi kipas ventilasi

Tugas MQ-135 yang paling berguna adalah menyalakan kipas angin atau kipas pembuangan (exhaust) secara otomatis ketika udara mulai pengap. Ada dua detail penting di sini. Yang pertama adalah histeresis: kipas menyala di atas 1000 ppm tapi baru mati ketika nilainya turun di bawah 800 ppm; dengan satu ambang saja, relay akan berbunyi klik setiap detik selama nilainya naik-turun di sekitar ambang. Yang kedua adalah waktu nyala minimum: begitu kipas menyala, kipas berjalan minimal 2 menit supaya udara di ruangan benar-benar berganti. Kode juga menghaluskan pembacaan supaya lonjakan sekejap tidak memicu kipas.

C++ (Arduino IDE)
1const byte MQ_PIN = A0;
2const byte FAN_PIN = 7;                    // röle modülü IN / relay module IN
3const bool RELAY_ACTIVE_LOW = true;        // çoğu modül LOW ile çeker / most modules switch on with LOW
4const float RL_KOHM = 1.0;
5const float R0_KOHM = 3.6;                 // kendi kalibrasyon sonucun / your calibration result
6const float PARA = 116.6020682;
7const float PARB = 2.769034857;
8const float FAN_ON_PPM = 1000;             // bunun üstünde fanı aç / fan on above this
9const float FAN_OFF_PPM = 800;             // bunun altında fanı kapat / fan off below this
10const unsigned long MIN_RUN_MS = 120000;   // fan en az 2 dk çalışır / fan runs at least 2 min
11const unsigned long WARMUP_MS = 180000;    // 3 dk ısınma / 3 min warm-up
12
13bool fanOn = false;
14unsigned long fanStart = 0;
15float smoothPpm = 0;
16
17void setFan(bool on) {
18  fanOn = on;
19  if (on) fanStart = millis();
20  bool level = RELAY_ACTIVE_LOW ? !on : on;
21  digitalWrite(FAN_PIN, level ? HIGH : LOW);
22}
23
24float readPpm() {
25  long sum = 0;
26  for (int i = 0; i < 20; i++) {
27    sum += analogRead(MQ_PIN);
28    delay(10);
29  }
30  float raw = sum / 20.0;
31  if (raw < 1) raw = 1;
32  float rs = RL_KOHM * (1023.0 - raw) / raw;
33  return PARA * pow(rs / R0_KOHM, -PARB);
34}
35
36void setup() {
37  digitalWrite(FAN_PIN, RELAY_ACTIVE_LOW ? HIGH : LOW);   // önce kapalı seviye, sonra çıkış / off level first, then output
38  pinMode(FAN_PIN, OUTPUT);
39  Serial.begin(9600);
40  while (millis() < WARMUP_MS) delay(100);
41  smoothPpm = readPpm();
42}
43
44void loop() {
45  smoothPpm = smoothPpm * 0.8 + readPpm() * 0.2;          // ani sıçramaları yumuşat / smooth out spikes
46
47  if (!fanOn && smoothPpm > FAN_ON_PPM) {
48    setFan(true);
49  } else if (fanOn && smoothPpm < FAN_OFF_PPM && millis() - fanStart > MIN_RUN_MS) {
50    setFan(false);
51  }
52
53  Serial.print(F("~"));
54  Serial.print(smoothPpm, 0);
55  Serial.print(F(" ppm   fan: "));
56  Serial.println(fanOn ? F("ACIK / ON") : F("KAPALI / OFF"));
57  delay(1000);
58}

Pin IN modul relay ke D7, VCC dan GND-nya ke Arduino; kipas tersambung ke catu dayanya sendiri lewat terminal COM dan NO relay. Kalau kamu memakai kipas komputer 12 V, MOSFET lebih senyap dan lebih awet daripada relay; pengkabelannya sama dengan rangkaian pompa air mini. Kalau kamu menghidupmatikan perangkat 230 V (220 V di Indonesia) seperti kipas exhaust kamar mandi, ikuti aturan keselamatan di panduan modul relay dengan ketat: masukkan sisi tegangan listrik PLN ke dalam kotak tertutup dan jangan pernah menyentuh rangkaian ketika masih bertegangan. Mengatur pin ke level mati dulu dan baru kemudian menjadikannya output di setup() mencegah relay aktif LOW sempat menyala sekejap ketika daya masuk.

Mencatat kualitas udara dengan ESP32

Melihat bagaimana kualitas udara berubah sepanjang hari jauh lebih banyak mengajarkan daripada satu kali pembacaan: hanya catatan data yang bisa memperlihatkan udara pengap yang menumpuk di kamar tidur menjelang pagi, lonjakan di dapur ketika memasak, atau efek membuka jendela. Kode ESP32 di bawah mengambil satu pembacaan setiap menit, mengambil waktu dari internet (NTP) untuk menaruh tanggal dan jam di setiap baris, lalu menyimpan hasilnya sebagai CSV ke sistem file LittleFS di memori flash ESP32 sendiri. Ketika kamu membuka alamat IP ESP32 di browser, kamu melihat pembacaan terakhir dan bisa mengunduh seluruh catatan dengan sekali klik sebagai file CSV yang bisa dibuka di Excel. Tidak perlu library tambahan.

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <WebServer.h>
3#include <LittleFS.h>
4#include <time.h>
5
6const char* WIFI_SSID = "AgAdi";              // Wi-Fi adın / your Wi-Fi name
7const char* WIFI_PASS = "Sifre123";           // Wi-Fi şifren / your Wi-Fi password
8const int MQ_PIN = 34;                        // AO, 10k/20k bölücü üzerinden (ADC1) / through a 10k/20k divider (ADC1)
9const float DIVIDER = 1.5;                    // (10k + 20k) / 20k
10const float RL_KOHM = 1.0;
11const float R0_KOHM = 3.6;                    // ESP32 ile yeniden kalibre et / recalibrate with the ESP32
12const float PARA = 116.6020682;
13const float PARB = 2.769034857;
14const unsigned long LOG_INTERVAL = 60000;     // dakikada bir kayıt / one entry per minute
15
16WebServer server(80);
17unsigned long lastLog = 0;
18float lastPpm = 0;
19
20float readPpm() {
21  uint32_t mv = 0;
22  for (int i = 0; i < 20; i++) {
23    mv += analogReadMilliVolts(MQ_PIN);       // kalibre edilmiş mV / calibrated mV
24    delay(5);
25  }
26  float vout = (mv / 20.0) / 1000.0 * DIVIDER;   // sensör çıkışı (V) / sensor output (V)
27  if (vout < 0.05) vout = 0.05;
28  float rs = RL_KOHM * (5.0 - vout) / vout;
29  return PARA * pow(rs / R0_KOHM, -PARB);
30}
31
32void handleRoot() {
33  String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>"
34                "<meta name='viewport' content='width=device-width,initial-scale=1'></head>"
35                "<body style='font-family:sans-serif'><h2>MQ-135</h2><p>Son ölçüm / last reading: ~";
36  html += String(lastPpm, 0);
37  html += " ppm</p><p><a href='/log.csv'>CSV indir / download</a> | "
38          "<a href='/clear'>Kaydı sil / clear log</a></p></body></html>";
39  server.send(200, "text/html", html);
40}
41
42void handleCsv() {
43  File f = LittleFS.open("/log.csv", "r");
44  if (!f) {
45    server.send(404, "text/plain", "Kayit yok / no log yet");
46    return;
47  }
48  server.streamFile(f, "text/csv");
49  f.close();
50}
51
52void handleClear() {
53  LittleFS.remove("/log.csv");
54  server.sendHeader("Location", "/");
55  server.send(303);
56}
57
58void setup() {
59  Serial.begin(115200);
60  analogSetPinAttenuation(MQ_PIN, ADC_11db);  // yaklaşık 0-3,1 V ölçüm aralığı / about 0-3.1 V range
61  if (!LittleFS.begin(true)) {                // true: ilk açılışta biçimlendir / format on first use
62    Serial.println("LittleFS hatasi / error");
63  }
64  WiFi.mode(WIFI_STA);
65  WiFi.begin(WIFI_SSID, WIFI_PASS);
66  while (WiFi.status() != WL_CONNECTED) {
67    delay(500);
68    Serial.print(".");
69  }
70  Serial.println();
71  Serial.println(WiFi.localIP());
72  configTime(3 * 3600, 0, "pool.ntp.org");    // UTC+3; kendi saat dilimine göre değiştir / change to your time zone
73
74  server.on("/", handleRoot);
75  server.on("/log.csv", handleCsv);
76  server.on("/clear", handleClear);
77  server.begin();
78  lastLog = millis();                         // ilk kayıt 1 dk sonra, sensör ısınırken / first entry after 1 min
79}
80
81void loop() {
82  server.handleClient();
83  if (millis() - lastLog >= LOG_INTERVAL) {
84    lastLog = millis();
85    lastPpm = readPpm();
86    char stamp[20] = "saat-yok";
87    struct tm now;
88    if (getLocalTime(&now, 100)) {
89      strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M", &now);
90    }
91    File f = LittleFS.open("/log.csv", "a");  // dosyanın sonuna ekle / append to the file
92    if (f) {
93      f.printf("%s,%.0f\n", stamp, lastPpm);
94      f.close();
95    }
96    Serial.printf("%s  ~%.0f ppm\n", stamp, lastPpm);
97  }
98}

Karena ADC ESP32 mengukur dengan cara yang berbeda dari ADC Uno, sebaiknya kalibrasi R0 diulang dengan rangkaian ini; cukup sesuaikan fungsi readRs() di kode kalibrasi dengan logika readPpm() di sini. Sambungkan sensor ke salah satu pin ADC1 antara GPIO 32 dan 39: pin ADC2 tidak bisa dipakai ketika Wi-Fi menyala. Tiap baris sekitar 22 byte; dengan satu entri per menit, terkumpul sekitar 32 KB data per hari, dan area 1,5 MB di Partition Scheme bawaan cukup untuk kira-kira satu setengah bulan. Untuk catatan yang lebih panjang, kamu bisa memakai modul kartu SD, dan kalau ingin mengirim data langsung ke spreadsheet, lihat cara mencatat data ESP32 ke Google Sheets.

MQ-135 dengan Raspberry Pi Pico (MicroPython)

Di Pico, modul diberi daya 5 V dari pin VBUS dan output AO disambung ke GP26, lagi-lagi lewat pembagi 10 kΩ / 20 kΩ. ADC Pico mengembalikan nilai 16-bit (0–65535) dengan referensi 3,3 V; kode mengubahnya dulu menjadi tegangan, lalu dengan rasio pembagi menjadi output sensor. Rumusnya sama dengan di Arduino. Karena VBUS bisa bervariasi antara 4,8 dan 5,1 V tergantung sumber USB-nya, untuk hasil yang presisi ukur VBUS dengan multimeter lalu koreksi nilai 5.0 di kode.

MicroPython
1from machine import ADC
2import time
3
4adc = ADC(26)                          # GP26 = ADC0, AO bölücü üzerinden / AO through a divider
5DIVIDER = 1.5                          # (10k + 20k) / 20k
6RL = 1.0                               # kΩ, karttaki yük direnci / load resistor on the board
7R0 = 3.6                               # kΩ, kendi kalibrasyon sonucun / your calibration result
8PARA, PARB = 116.6020682, 2.769034857
9VCC = 5.0                              # VBUS gerilimi / VBUS voltage
10
11def read_rs():
12    total = 0
13    for _ in range(20):
14        total += adc.read_u16()
15        time.sleep_ms(5)
16    v = total / 20 / 65535 * 3.3 * DIVIDER    # sensör çıkışı (V) / sensor output (V)
17    v = max(v, 0.05)                          # sıfıra bölmeyi önle / avoid dividing by zero
18    return RL * (VCC - v) / v
19
20print("Isiniyor / warming up...")
21time.sleep(180)                        # 3 dk ısınma / 3 min warm-up
22while True:
23    ratio = read_rs() / R0
24    ppm = PARA * ratio ** -PARB        # tahmini CO2 eşdeğeri / estimated CO2 equivalent
25    print("Rs/R0 = %.2f   ~%d ppm" % (ratio, ppm))
26    time.sleep(2)

MQ-135 vs CCS811 vs sensor CO2 NDIR

Ada tiga kelas sensor kualitas udara, dan masing-masing menjawab pertanyaan yang berbeda. MQ-135 murah, analog, dan sederhana; sensor ini menunjukkan perubahan umum di udara. CCS811 juga sensor oksida logam, tapi punya mikrokontroler sendiri di dalamnya, mengatur pemanasnya sendiri, dan langsung mengeluarkan TVOC (total senyawa organik volatil) dan eCO2 (CO2 ekuivalen) lewat I2C; kami membahasnya di panduan sensor kualitas udara CCS811. Satu-satunya kelompok yang mengukur CO2 sungguhan adalah sensor NDIR (inframerah non-dispersif): modul seperti MH-Z19B atau SenseAir S8 mengukur seberapa banyak cahaya inframerah pada 4,26 µm yang diserap molekul CO2, dan hampir tidak terpengaruh gas lain.

SpesifikasiMQ-135CCS811NDIR (MH-Z19B, SenseAir S8)
Prinsip pengukuranHambatan SnO2 yang dipanaskanOksida logam + mikrokontroler internalPenyerapan cahaya inframerah
Mengukur CO2 sungguhan?Tidak, hanya memperkirakanTidak, menghitung eCO2 dari VOCYa
OutputAnalog (plus ambang digital)I2CUART atau PWM
Catu daya5 V, sekitar 150 mA3,3 V, rata-rata sekitar 30 mA5 V, rata-rata di bawah 60 mA
Pemanasan24–48 jam ketika baru, lalu beberapa menit48 jam ketika baru, lalu 20 menitSekitar 3 menit
AkurasiRendah, untuk perubahan relatifSedang, untuk memantau VOC secara relatifSekitar ±50 ppm + 3–5% dari pembacaan
HargaPaling murahSedangPaling mahal

Singkatnya: untuk belajar, memicu alarm atau kipas, dan memantau perubahan udara, MQ-135 sudah cukup. Kalau kamu ingin memantau uap cat, lem, atau produk pembersih, CCS811 memberi data yang lebih halus dan stabil. Kalau kamu butuh angka yang bisa diandalkan untuk menjawab “sudah waktunya buka jendela?” di ruang kelas, kantor, atau kamar tidur, kamu perlu berinvestasi di sensor CO2 NDIR. Banyak orang memakai keduanya: sensor NDIR memantau CO2, sementara MQ-135 menangkap kejadian mendadak seperti asap atau bau pelarut di dapur.

Ide proyek dengan MQ-135

  • Indikator udara ruangan: LED RGB yang menyala hijau, kuning, atau merah sesuai kualitas udara, atau grafik langsung di layar OLED.
  • Penyedot asap dapur pintar: Sistem yang menyalakan penyedot asap ketika asap dan uap naik selama memasak dan mematikannya begitu udara bersih.
  • Peringatan garasi dan bengkel cat: Rangkaian yang membunyikan buzzer dan menyalakan ventilasi ketika uap pelarut meningkat.
  • Pemantau pasir kucing: Proyek ESP32 yang memberi notifikasi ke ponselmu ketika amonia naik dan sudah waktunya mengganti pasir.
  • Papan udara kelas: Grafik yang mencatat pembacaan dengan ESP32 dan membandingkannya dengan jadwal pelajaran untuk menunjukkan kebiasaan ventilasi.
  • Otomatisasi rumah: Kirim nilainya ke Home Assistant lewat MQTT dan nyalakan pembersih udara dengan stopkontak pintar ketika udara memburuk.

Kesalahan umum dan cara memperbaikinya

GejalaKemungkinan penyebabSolusi
Nilai terus bergeser selama berjam-jamPemanasan awal belum selesaiJalankan sensor tanpa henti selama 24–48 jam, lalu kalibrasi
Nilai terlalu tinggi atau terlalu rendah ketika baru dinyalakanTidak menunggu pemanasan harianTunggu minimal 3 menit, idealnya 10–20, sebelum mengukur
Ribuan ppm bahkan di udara bersihR0 salah, atau kalibrasi dilakukan di dalam ruanganUlangi kalibrasi di udara luar yang bersih
Di ESP32 nilainya selalu mentok di maksimumAO mencapai 5 V, atau sensor bekerja di 3,3 VBeri daya sensor dari 5 V dan tambahkan pembagi 10k/20k di AO
Arduino jadi hangat atau USB terputusPemanas 150 mA ditambah beban lain membebani USBPakai catu eksternal 5 V dan satukan ground-nya
ppm naik ketika kena sinar matahari atau setelah mandiEfek suhu dan kelembapanKalibrasi di kondisi yang mirip atau terapkan koreksi dengan DHT22
Tafsirkan nilai MQ-135 bukan sebagai pengukuran absolut, melainkan sebagai perubahan dari nilai dasar. Setelah sensor panas, jadikan nilai yang kamu ukur pada momen udara bersih sebagai nilai dasar dan ambil keputusan dengan ambang relatif seperti “30% di atas nilai dasar”; pendekatan ini jauh lebih tahan terhadap kesalahan kalibrasi, penuaan sensor, dan perubahan musim. Filter rata-rata bergerak dan median yang bisa kamu pakai untuk menghaluskan pembacaan kami bahas di menyaring data sensor.

Asalkan kamu tahu batasannya, MQ-135 adalah sensor pemula yang sangat bagus untuk belajar tentang kualitas udara dan mengotomatiskan ventilasi: beri daya 5 V, beri pemanasan awal 24–48 jam, cari R0 di udara bersih, baca hasilnya secara relatif, dan beralih ke sensor NDIR ketika kamu butuh CO2 sungguhan. Di aplikasi BlueGrays kamu akan menemukan proyek Menggunakan Sensor Gas, Alarm Sensor Api dan Gas, dan Alarm Detektor Gas/Asap MQ-2 ESP32, beserta proyek suhu dan kelembapan dengan DHT11 dan DHT22 serta Pencatat Data Suhu ESP32, lengkap dengan skema rangkaian dan kode langkah demi langkah.

Pertanyaan umum

Bisakah MQ135 mengukur CO2?

MQ-135 tidak benar-benar mengukur CO2; sensor ini memperkirakannya. Respons sensor terhadap CO2 hanya lemah; respons sebenarnya adalah terhadap gas seperti alkohol, amonia, dan benzena serta senyawa volatil yang dilepaskan manusia. Nilai CO2 ppm yang ditampilkan library dihitung dari polusi umum ini; untuk CO2 sungguhan kamu butuh sensor NDIR seperti MH-Z19B.

Berapa lama MQ135 perlu dipanaskan?

MQ-135 yang baru butuh pemanasan awal 24–48 jam, dan ini harus selesai sebelum kalibrasi. Setelah itu, sensor bisa dipakai dalam sekitar 2–3 menit setiap kali dinyalakan; untuk nilai yang paling stabil, menunggu 10–20 menit lebih baik.

Bagaimana cara mencari nilai R0 MQ135?

Bawa sensor yang sudah selesai pemanasan awal ke udara luar yang bersih, hitung hambatannya dengan Rs = RL × (1023 − raw) / raw, lalu dengan asumsi CO2 di udara luar sekitar 420 ppm, hitung R0 = Rs × (420 / 116,6)^(1 / 2,769). Rata-ratakan pembacaan selama beberapa menit. R0 yang kamu temukan hanya berlaku untuk sensor itu dan resistor beban itu.

Apa bedanya MQ135 dan MQ2?

Keduanya sensor oksida logam berpemanas, tapi disetel untuk gas yang berbeda. MQ-2 cocok untuk LPG, propana, metana, hidrogen, dan asap, jadi sensor inilah yang dipakai untuk alarm kebocoran gas. MQ-135 peka terhadap polutan udara seperti amonia, benzena, alkohol, NOx, dan asap, dan dipakai untuk memantau kualitas udara.

Bisakah MQ135 dipakai dengan ESP32?

Bisa, tapi perhatikan dua hal. Pemanas sensor butuh 5 V, jadi beri daya modul dari pin VIN ESP32. Output AO juga bisa mencapai 5 V, jadi turunkan ke 3,3 V dengan pembagi tegangan 10 kΩ dan 20 kΩ, lalu sambungkan ke pin ADC1 antara GPIO 32 dan 39.

Gas apa saja yang dideteksi MQ135?

MQ-135 paling peka terhadap amonia, senyawa belerang, dan uap aromatik seperti benzena. Sensor ini juga merespons jelas terhadap alkohol, asap, dan nitrogen oksida, serta lemah terhadap CO2 dan karbon monoksida. Sensor ini tidak bisa membedakan gas-gas tersebut; yang ditunjukkan hanya perubahan keseluruhan di udara.

Lihat semua proyek
Suhu dan Kelembapan dengan DHT11
#55Menengah

Suhu dan Kelembapan dengan DHT11

Seberapa hangat kamarmu, dan apakah udaranya lembap atau kering? Sensor DHT11 mengukur suhu dan kelembapan, dan Arduino menulis nilainya di layar LCD dua baris, diperbarui setiap beberapa detik. Jika

4.7(47)
73
Menggunakan Sensor Gas
#51Pemula
Premium

Menggunakan Sensor Gas

Penjaga kecil yang menyadari kebocoran gas di dapur lebih dulu darimu. Sensor gas terus mengendus udara; selama semuanya aman LED hijau tetap menyala, dan ketika gas di udara melewati tingkat tertentu

4.6(37)
50
Alarm Sensor Api dan Gas
#52Mahir
Premium

Alarm Sensor Api dan Gas

Penjaga kecil yang langsung memperingatkanmu ketika ada gas bocor atau nyala api di suatu tempat. Sensor gas mengawasi gas di udara dan sensor api mengawasi cahaya api; selama semuanya aman LED hijau

4.8(52)
67
Alarm Detektor Gas/Asap MQ-2 ESP32
#122Menengah

Alarm Detektor Gas/Asap MQ-2 ESP32

Di proyek ini, gas mudah terbakar (LPG, metana, propana) dan asap dideteksi memakai modul sensor gas MQ-2, dan alarm mirip sirene diputar lewat buzzer pasif ketika terdeteksi. Output ambang digital (DO) sensor disambung ke GPIO 4 ESP32; ketika gas atau asap melewati ambang, DO menjadi LOW dan alarm terpicu. Kepekaan diatur lewat potensiometer modul. Buzzer pasif digerakkan dengan tone() untuk menghasilkan efek sirene dua frekuensi.

4.7(28)
43
Suhu dan Kelembapan DHT22 ESP32 (dengan Layar LCD)
#117Menengah

Suhu dan Kelembapan DHT22 ESP32 (dengan Layar LCD)

Proyek ini mengukur suhu dan kelembapan sekitar dengan sensor DHT22 dan menampilkan datanya secara real-time di LCD I2C 16x2. Data dibaca dari sensor dengan protokol satu kabel lewat library Adafruit DHT. Proyek ini menjadi dasar untuk stasiun cuaca IoT, otomasi rumah pintar, atau sistem pemantauan lingkungan di rumah kaca. Komunikasi dengan DHT22 dilakukan lewat pin GPIO 4 ESP32.

4.8(38)
56
Pencatat Data Suhu ESP32 (DHT22 + RTC DS1307 + microSD + OLED)
#144Mahir
Premium

Pencatat Data Suhu ESP32 (DHT22 + RTC DS1307 + microSD + OLED)

Buat pencatat suhu bercap waktu dengan ESP32! Baca suhu/kelembapan DHT22 setiap menit, ambil waktu sebenarnya dari RTC DS1307, dan catat ke kartu microSD sebagai CSV. OLED menampilkan suhu langsung (font besar), kelembapan, cap waktu, dan penghitung catatan. File /temp_log.csv bisa dibuka di Excel, Google Sheets, atau Python pandas; cocok untuk rumah kaca, suhu kamar, data laboratorium, penyimpanan makanan, atau sarang lebah.

4.7(7)
12
Layar LCD I2C ESP32 (16x2)
#119Menengah
Premium

Layar LCD I2C ESP32 (16x2)

Di proyek ini, kita menampilkan teks dengan menyambungkan layar LCD karakter 16x2 ke ESP32 lewat protokol I2C. Berkat I2C, kita bisa mengendalikan layar hanya dengan dua pin data (SDA dan SCL), sehingga tidak perlu memboroskan 6+ pin seperti pada sambungan paralel klasik. Kode mencetak pesan tetap di baris pertama dan penghitung yang naik setiap detik di baris kedua. Selain itu, kita menjalankan pemindai I2C di awal untuk mencetak alamat layar ke Serial Monitor (biasanya 0x27).

4.9(23)
40
Menyalakan Bohlam 220V dengan Tombol Tekan
#19Mahir
Premium

Menyalakan Bohlam 220V dengan Tombol Tekan

Selama kamu menahan tombol, bohlam 220 volt sungguhan tetap menyala, dan mati begitu kamu melepasnya. Sinyal kecil Arduino tidak bisa langsung menyalakan bohlam, jadi relay, sakelar yang dikendalikan

4.4(30)
38