Lập trình ESP32 – Bài 18: Đọc cảm biến khí gas MQ-2 và hiển thị lên màn hình OLED

Hướng dẫn kết nối cảm biến khí gas MQ-2 với ESP32, đọc giá trị analog (khói, LPG, butane…) và hiển thị lên màn hình OLED SSD1306 (I2C).

Mục lục

  1. Giới thiệu
  2. Cảnh báo & nguyên tắc đo MQ-2
  3. Phần cứng cần chuẩn bị
  4. Sơ đồ kết nối
  5. Ví dụ 1 – Đọc cảm biến MQ-2 (analog)
  6. Ví dụ 2 – Đọc cảm biến & hiển thị OLED
  7. Hiệu chuẩn & mẹo thực tế
  8. Lỗi thường gặp & cách khắc phục
  9. Gợi ý mở rộng

1) Giới thiệu

MQ-2 là cảm biến phát hiện khí gas/khói giá rẻ. Module thường có AO (analog)DO (digital ngưỡng). ESP32 có ADC tích hợp, phù hợp đọc AO để theo dõi mức tương đối của nồng độ khí.

2) Cảnh báo & nguyên tắc đo MQ-2

  • Heater & AO của MQ-2 thường là 5V. Ngõ AO trên nhiều module có biên độ 0–5Vkhông đưa trực tiếp vào ADC ESP32 (giới hạn 0–3.3V).
  • Dùng mạch chia áp (ví dụ 100kΩ / 100kΩ), lấy tín hiệu giữa đưa vào chân ADC để hạ biên độ còn ~0–2.5V.
  • MQ-2 cần làm nóng (burn-in) vài phút đến vài chục phút để ổn định.
  • Giá trị ADC là tương đối; muốn suy ra ppm cần đường cong Rs/R0 theo datasheet và hiệu chuẩn môi trường.

3) Phần cứng cần chuẩn bị

Linh kiệnSố lượngGhi chú
ESP32 DevKit V11
Cảm biến MQ-2 (module AO/DO)1Nguồn 5V cho heater
2 điện trở 100kΩ2Tạo mạch chia áp AO → ADC
OLED SSD1306 I2C 0.96″ (128×64)1Địa chỉ thường 0x3C
Dây nối, breadboardVài sợi

4) Sơ đồ kết nối (Connection Diagram)

  • Nguồn
    • ESP32 cấp USB 5V.
    • MQ-2 VCC → 5V, GND → GND.
  • Tín hiệu analog
    • AO (MQ-2)mạch chia áp 100k/100kESP32 ADC GPIO34.
    • (Tuỳ chọn) DO (MQ-2)GPIO26 để đọc mức ngưỡng.
  • OLED (I2C)
    • SDA → GPIO21, SCL → GPIO22, VCC → 3V3, GND → GND.

5) Ví dụ 1 – Đọc cảm biến MQ-2 (analog)

Mục tiêu

  • Đọc ADC từ MQ-2 tại GPIO34 qua chia áp.
  • In giá trị thô (0–4095) và điện áp xấp xỉ.

Code (Arduino IDE)

// ESP32 + MQ-2 (AO) -> Voltage Divider (100k/100k) -> GPIO34

#define MQ2_ADC_PIN 34
const float VREF = 3.3;  // tham chiếu ADC ESP32

void setup() {
  Serial.begin(115200);
  delay(300);
  Serial.println("ESP32 - MQ2 analog read (divider 100k/100k -> ADC34)");
  analogReadResolution(12); // 0..4095
  // analogSetAttenuation(ADC_11db); // tùy nhu cầu
}

void loop() {
  int raw = analogRead(MQ2_ADC_PIN);     // 0..4095
  float vadc = raw * VREF / 4095.0;      // điện áp tại CHÂN ADC (sau chia 1/2)
  float vao  = vadc * 2.0;               // ước lượng điện áp tại AO của MQ-2

  Serial.print("ADC="); Serial.print(raw);
  Serial.print(" | Vadc="); Serial.print(vadc, 3);
  Serial.print(" V | VAO~"); Serial.print(vao, 3);
  Serial.println(" V");

  delay(500);
}

Kết quả

  • Serial hiển thị ADC, Vadc (sau chia), VAO (ước lượng).
  • Đưa nguồn lửa/gas lại gần → giá trị tăng rõ rệt.

6) Ví dụ 2 – Đọc cảm biến & hiển thị OLED

Mục tiêu

  • Đọc MQ-2 (AO) như Ví dụ 1.
  • Hiển thị bar/giá trị trên OLED SSD1306 (I2C 0x3C).

Thư viện cần cài

  • Adafruit SSD1306
  • Adafruit GFX Library

Code (Arduino IDE)

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define MQ2_ADC_PIN 34
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET   -1
#define OLED_ADDR    0x3C

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const float VREF = 3.3;

void setup() {
  Serial.begin(115200);
  analogReadResolution(12);

  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
    Serial.println(F("OLED init failed! Check I2C and address 0x3C/0x3D."));
    for(;;);
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0,0);
  display.println(F("ESP32 + MQ-2 + OLED"));
  display.println(F("AO via divider -> ADC34"));
  display.display();
  delay(800);
}

void drawBar(int value, int maxv) {
  int w = map(value, 0, maxv, 0, 120);
  display.drawRect(4, 38, 120, 18, SSD1306_WHITE);
  display.fillRect(4, 38, w, 18, SSD1306_WHITE);
}

void loop() {
  int raw = analogRead(MQ2_ADC_PIN);
  float vadc = raw * VREF / 4095.0;
  float vao  = vadc * 2.0; // ước lượng trước chia áp

  display.clearDisplay();

  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print(F("ADC: ")); display.println(raw);
  display.print(F("Vadc: ")); display.print(vadc, 3); display.println(F("V"));
  display.print(F("VAO~: ")); display.print(vao, 3); display.println(F("V"));

  display.setCursor(0, 28);
  display.print(F("Level:"));
  drawBar(raw, 4095);

  display.display();

  // Log Serial
  Serial.printf("ADC=%d, Vadc=%.3f V, VAO~%.3f V\n", raw, vadc, vao);

  delay(300);
}

Kết quả

  • OLED hiển thị ADC, Vadc (sau chia), VAO ước lượngthanh mức.
  • Khi có khói/khí gas, Level tăng nhanh.

7) Hiệu chuẩn & mẹo thực tế

  • Burn-in vài chục phút lần đầu; chờ ổn định trước khi đo.
  • Lấy giá trị nền (baseline) không khí sạch để so sánh tương đối.
  • Nếu cần ppm, đọc datasheet để dùng đường cong Rs/R0 vs ppmhiệu chuẩn R0 ở môi trường chuẩn.
  • Giảm nhiễu: lấy trung bình trượt, thêm tụ 100nF gần AO, chắc GND chung.

8) Lỗi thường gặp & cách khắc phục

  • ADC luôn cao/thấp: kiểm tra dây AO, mạch chia áp 100k/100k.
  • OLED không hiển thị: sai địa chỉ (thử 0x3D), sai dây SDA/SCL.
  • Giá trị dao động mạnh: nguồn/ground yếu; cần lọc trung bình; để cảm biến ổn định sau burn-in.
  • ESP32 nóng/treo: tuyệt đối không đưa 5V trực tiếp vào ADC!

9) Gợi ý mở rộng

  • Cảnh báo buzzer/relay khi vượt ngưỡng; gửi dữ liệu MQTT/Web.
  • Ghi log ra SPIFFS/SD Card; biểu đồ thời gian thực WebSocket.
  • Kết hợp DHT22/BME280 để bù theo nhiệt độ/độ ẩm.

Comments

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *