Cirkit Designer Logo
Cirkit Designer
Your all-in-one circuit design IDE
Home / 
Project Documentation

Arduino Nano-Based Air Quality Monitoring System with OLED Display and Alerts

Image of Arduino Nano-Based Air Quality Monitoring System with OLED Display and Alerts

Circuit Documentation

Summary

This circuit is designed to monitor air quality using an MQ-7 gas sensor and provide visual and auditory alerts based on the detected gas levels. The system uses an Arduino Nano microcontroller to process sensor data and control various output devices, including a traffic light, a passive buzzer, a vibration motor, and an OLED display for real-time data visualization.

Component List

  1. Arduino Nano

    • Description: A compact microcontroller board based on the ATmega328P.
    • Pins: D1/TX, D0/RX, RESET, GND, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11/MOSI, D12/MISO, VIN, 5V, A7, A6, A5, A4, A3, A2, A1, A0, AREF, 3V3, D13/SCK
  2. Traffic Light

    • Description: A module with three LEDs (Green, Yellow, Red) to indicate different levels of gas concentration.
    • Pins: Green, Yellow, Red, GND
  3. MQ-7 Breakout

    • Description: A gas sensor module for detecting carbon monoxide (CO) levels.
    • Pins: VCC, GND, DO, AO
  4. Passive Buzzer

    • Description: A simple buzzer for generating sound alerts.
    • Pins: S output signal, +VCC, GND
  5. PWM Vibration Motor Sensor Module Switch

    • Description: A module with a vibration motor for tactile feedback.
    • Pins: Signal, Vcc, Ground
  6. 128x64 OLED Display (I2C IIC SPI Serial)

    • Description: A small OLED display for showing sensor data and status messages.
    • Pins: GND, SDA, SCL, VCC

Wiring Details

Arduino Nano

  • D11/MOSI connected to Traffic Light Green
  • D10 connected to Traffic Light Yellow
  • D9 connected to Traffic Light Red
  • D8 connected to Passive Buzzer S output signal
  • D7 connected to PWM Vibration Motor Sensor Module Switch Signal
  • A0 connected to MQ-7 Breakout AO
  • A4 connected to 128x64 OLED Display SCL
  • A5 connected to 128x64 OLED Display SDA
  • 5V connected to PWM Vibration Motor Sensor Module Switch Vcc, MQ-7 Breakout VCC, 128x64 OLED Display VCC
  • GND connected to Passive Buzzer GND, Traffic Light GND, PWM Vibration Motor Sensor Module Switch Ground, 128x64 OLED Display GND, MQ-7 Breakout GND

Traffic Light

  • Green connected to Arduino Nano D11/MOSI
  • Yellow connected to Arduino Nano D10
  • Red connected to Arduino Nano D9
  • GND connected to Arduino Nano GND

MQ-7 Breakout

  • VCC connected to Arduino Nano 5V
  • GND connected to Arduino Nano GND
  • AO connected to Arduino Nano A0

Passive Buzzer

  • S output signal connected to Arduino Nano D8
  • GND connected to Arduino Nano GND

PWM Vibration Motor Sensor Module Switch

  • Signal connected to Arduino Nano D7
  • Vcc connected to Arduino Nano 5V
  • Ground connected to Arduino Nano GND

128x64 OLED Display (I2C IIC SPI Serial)

  • GND connected to Arduino Nano GND
  • SDA connected to Arduino Nano A5
  • SCL connected to Arduino Nano A4
  • VCC connected to Arduino Nano 5V

Documented Code

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

// Define OLED display size
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

// OLED I2C Address and Reset Pin
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Define pins
int LEDRed = 9;       // Red LED (Very Dangerous Level)
int LEDYellow = 10;   // Yellow LED (Dangerous Level)
int LEDGreen = 11;    // Green LED (Normal Level)
int buzzer = 8;       // Buzzer
int motor = 7;        // Vibration Motor
int smokeA0 = A0;     // MQ-7 output connected to A0

// Calibration constants
float V_ref = 5.0;    // Reference voltage
float RL = 10.0;      // Load resistance in kOhms
float R0 = 10.0;      // Sensor baseline resistance in clean air

// Thresholds
float normalThreshold = 100.0;
float dangerousThreshold = 150.0;
float veryDangerousThreshold = 200.0;

// Variables
int analogSensor;     // Analog sensor reading
float VRL, Rs, ppm;   // Voltage across load, sensor resistance, and ppm value

void setup() {
  // Initialize pins
  pinMode(LEDRed, OUTPUT);
  pinMode(LEDYellow, OUTPUT);
  pinMode(LEDGreen, OUTPUT);
  pinMode(buzzer, OUTPUT);
  pinMode(motor, OUTPUT);
  pinMode(smokeA0, INPUT);

  // Start Serial Monitor
  Serial.begin(9600);

  // Initialize OLED
  if (!display.begin(0x3C, OLED_RESET)) {  // I2C address set to 0x3C
    Serial.println(F("OLED initialization failed! Check connections."));
    for (;;);  // Halt execution if OLED fails
  }
  
  // Clear and prepare OLED
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 0);
  display.println("Initializing...");
  display.display();
  delay(2000);  // Show initializing message
}

void loop() {
  // Read sensor data
  analogSensor = analogRead(smokeA0);
  VRL = (analogSensor / 1023.0) * V_ref;       // Convert analog value to voltage

  // Check for invalid sensor readings
  if (analogSensor < 10) { // Threshold for detecting disconnected or invalid sensor
    ppm = 0; // Set ppm to 0 for invalid readings
  } else {
    Rs = RL * ((V_ref - VRL) / VRL);            // Calculate sensor resistance
    ppm = calculatePPM(Rs / R0);                // Calculate ppm from Rs/R0 ratio
  }

  // Clear OLED and display data
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("PPM: ");
  display.println(ppm);

  // LED, Buzzer, and Motor Control Based on Thresholds
  if (ppm >= veryDangerousThreshold) {
    display.println("Level: VERY DANGEROUS");
    activateAlert(LEDRed, 2000, motor, true); // Red LED, continuous buzzer, motor on
  } else if (ppm > normalThreshold && ppm <= dangerousThreshold) {
    display.println("Level: DANGEROUS");
    activateAlert(LEDYellow, 1500, motor, false); // Yellow LED, intermittent buzzer, motor on/off
  } else if (ppm <= normalThreshold && ppm > 0) {
    display.println("Level: NORMAL");
    activateNormal(LEDGreen); // Green LED, no buzzer, motor off
  } else {
    // No valid readings
    display.println("No Sensor Data");
    activateNormal(-1); // Turn off all outputs
  }

  // Display updates
  display.display();

  // Serial output for debugging
  Serial.print("Analog Value: ");
  Serial.print(analogSensor);
  Serial.print(" | PPM: ");
  Serial.println(ppm);

  delay(500); // Adjust reading interval
}

// Function to calculate ppm
float calculatePPM(float ratio) {
  return pow(10, (log10(ratio) - log10(1.0)) * 0.3 + 2.0); // Replace constants with calibration values if needed
}

// Function to handle dangerous and very dangerous alerts
void activateAlert(int ledPin, int buzzerFrequency, int motorPin, bool continuous) {
  digitalWrite(LEDRed, LOW);
  digitalWrite(LEDYellow, LOW);
  digitalWrite(LEDGreen, LOW);
  if (ledPin != -1) digitalWrite(ledPin, HIGH);        // Activate corresponding LED
  tone(buzzer, buzzerFrequency);                      // Activate buzzer
  if (continuous) {
    digitalWrite(motorPin, HIGH);                     // Keep motor on continuously
  } else {
    digitalWrite(motorPin, HIGH);
    delay(500);                                       // Intermittent motor activation
    digitalWrite(motorPin, LOW);
  }
}

// Function to handle normal or invalid level
void activateNormal(int ledPin)