Überwachung von CO2, Temperatur und Luftfeuchtigkeit mit MQ-135 und DHT11 - AZ-Delivery

Der folgende Beitrag wurde uns von dem Leser Miguel Torres Gordo zugesandt. Nachdem Bernd Albrecht die Blogreihe zu einem ähnlichen Thema mit MQ-2 und DHT22 am ESP8266 gestartet hat, gibt es hier eine Alternative für ATmega328 Mikrocontroller und MQ-135 / DHT11 Sensoren. Viel Spaß beim Lesen und nachbasteln!

Da es sehr wichtig ist, den Sättigungsgrad der Umgebung zu kennen, zum Beispiel am Arbeitsplatz, habe ich im Internet nach einem Sensor gesucht, der mit Arduino verwendet werden kann, um den CO2-Gehalt zu messen. Glücklicherweise habe ich einen Sensor gefunden, der die Luftqualität misst. Es handelt sich um den MQ-135, der, wie man im Datenblatt sehen kann, bestimmte Stoffe messen kann, wie NH3, Alkohol, Benzol, Rauch, CO2 usw. So bin ich auf diesen Sensor gestoßen.

Da ich wusste, dass es die Möglichkeit gab, ihn zusammen mit unserem ATmega328 Mikrocontroller zu verwenden, suchte ich als erstes nach den Sicherheitsgrenzwerten für CO2 in Teilen pro Million (ppm) für Wohnungen, Räume und Gebäude, die laut verschiedenen Studien zwischen 400 und 800 ppm liegen können. Jetzt, da ich den richtigen Sensor und die Sicherheitsgrenzwerte kannte, war es an der Zeit, ein nützliches Projekt zu entwerfen, das uns diese Informationen anzeigt und uns auch über Temperatur und Luftfeuchtigkeit informiert.

Ziel dieses Projekts ist es daher, die CO2-Konzentration in Teilen pro Million zu messen, sie auf einem Bildschirm anzuzeigen und uns eine akustische Warnung zu geben, wenn sie eine gefährliche Konzentration erreicht, sowie uns über die Temperatur und Luftfeuchtigkeit zu informieren. Um die Lebensdauer des Bildschirms zu verlängern, hielt ich es für eine gute Option, drei verschiedenfarbige LEDs anzubringen, die uns eine schnelle visuelle Information über die Höhe der CO2-Konzentration geben, ohne dass wir die Daten sehen müssen. Nachdem das alles installiert ist, können wir uns an die Arbeit machen.

Benötigte Hardware

Anzahl Bauteil
1 ATmega328p Mikrocontroller
1 MQ-135 Luftqualitätssensor
1 DHT-11 Temperatur- und Feuchtigkeitssensor
1 MT3608 DC-DC-Adapter
1 LED 1x rot, 1x gelb, 1x grün
1 Zweifarbiges OLED I2C 128x64 Pixel Display 1,3 Zoll (hier in SW)
2 1K-Widerstände
1 Widerstand 220 Ohm
1 Buzzer

    Die erforderliche Software

    Beschreibung der Funktionsweise der Schaltung

    Die Funktionsweise dieser Schaltung ist sehr einfach. Der MQ-135-Sensor misst die CO2-Konzentration in Teilen pro Million, der DHT-11-Sensor misst die Temperatur und die Luftfeuchtigkeit. Diese drei Daten werden an einen zweifarbigen OLED-Bildschirm mit 0,96 Zoll gesendet, um jeden Wert für 3 Sekunden in Intervallen von 1 Minute anzuzeigen. Der Bildschirm bleibt während dieser Zeit ausgeschaltet. Diese Zeitwerte können konfiguriert werden. Während der Bildschirm ausgeschaltet bleibt, informieren uns die drei LEDs visuell über die vorhandenen CO2-Werte. Die grüne LED leuchtet, wenn die Konzentration gleich oder kleiner als 550 ist. Die gelbe LED leuchtet, wenn die Konzentration zwischen 551 und 799 Teilen pro Million CO2 liegt und die rote LED leuchtet zusammen mit einem Summerton, wenn die Konzentration 799 Teile pro Million übersteigt. Diese drei Werte können auch konfiguriert werden.

    Vorbereitung und Einstellung der RZERO-Widerstandsreferenz für den atmosphärischen CO2-Gehalt

    Als erstes muss der MQ-135-Sensor vorbereitet werden, damit er die richtigen Werte misst, die wir im nächsten Schritt verwenden werden. Dazu muss der Sensor im Neuzustand etwa 2 Stunden lang mit 5 Volt betrieben werden, damit die bei der Herstellung entstandenen Verunreinigungen beseitigt werden. Danach ist es am besten, den Referenzabgleich des RZERO-Widerstands in der endgültigen Schaltung vorzunehmen, da dies mit den normalerweise verwendeten Versorgungs- und Betriebsspannungen geschieht und die Messung optimal ist.

    Schaltungsaufbau

    Schaltungsaufbau

    Ziel dieser Kalibrierung ist es, den Widerstand des atmosphärischen CO2-Niveaus so einzustellen, dass der MQ-135-Sensor eine Konzentration zwischen 300 und 450 ppm misst, was der normalen Konzentration dieses Gases in der Umwelt entspricht. Es ist sehr wichtig, den Sensor unabhängig mit 5 VDC zu versorgen, da er 850 mW verbraucht.

    Wenn alles angeschlossen ist, starten wir die Arduino-IDE, laden und starten den Sketch "MQ135_calibration.ino". Zuvor muss die MQ135-Bibliothek installiert werden. Wir öffnen den seriellen Monitor und sehen den ppm-Messwert; wir müssen den RZERO-Wert in der Datei MQ135.h im Bibliotheksordner der Arduino IDE ändern und speichern, bis der ppm-Messwert derjenige ist, den wir als Arbeitsreferenz der Schaltung belassen wollen. Der zu ändernde Wert ist der grün gefärbte Wert.

     /// Kalibrierungswiderstand bei atmosphärischem CO2-Niveau
     /// Ändern Sie diesen Wert, bis der ppm-Wert 450 beträgt.
     #define RZERO 22500

    Um die Einstellung vorzunehmen, müssen wir den Wert von RZERO ändern, die Änderungen der Datei MQ135.h der Bibliothek in ihrem Ordner der Arduino IDE speichern und den Kalibrierungs-Sketch neu laden, den neuen Wert der CO2-Konzentration im seriellen Monitor überprüfen und den Vorgang wiederholen, um RZERO mit dem Wert einzustellen, den wir als Referenz für die CO2-Konzentration in der Luft für die Warngrenzen im Sketch unseres Projekts lassen wollen.

    Sketch MQ135_Kalibrierung für RZERO-Abgleich (download):

     #include "MQ135.h"
     #define RZERO 1
     
     MQ135 gasSensor = MQ135(A0);
     int val;
     int sensorPin = A0;
     int sensorValue = 0;
     
     void setup() {
       Serial.begin(115200);
       pinMode(sensorPin, INPUT);
     }
     
     void loop() {
       val = analogRead(A0);
       Serial.print ("raw = ");
       Serial.println (val);
       float zero = gasSensor.getRZero();
       Serial.print ("rzero: ");
       Serial.println (zero);
       float ppm = gasSensor.getPPM();
       Serial.print ("ppm: ");
       Serial.println (ppm);
       delay(2000);
     }

    Wenn wir die CO2-Konzentration in Teilen pro Million richtig abgelesen haben, ist es an der Zeit, den Sketch CO2_monitor.ino zu laden, der uns die Informationen über diese Konzentration, die Luftfeuchtigkeit und die Temperatur an dem Ort liefert, an dem wir die Werte Messen wollen.

    Sketch CO2_monitor (Download):

     /*************   Necessary libraries for the project    **************************/
     #include <Wire.h>
     #include <Adafruit_GFX.h>
     #include <Adafruit_SSD1306.h>
     #include <DHT.h>
     #include "pitches.h"
     
     /*************   Screen parameters   ********************************************/
     #define SCREEN_WIDTH 128
     #define SCREEN_HEIGHT 64
     Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
     
     /******   Humidity and temperature sensor DHT-11 paramters and variables   *****/
     #define DHTPIN 2
     #define DHTTYPE DHT11
     DHT dht(DHTPIN, DHTTYPE);
     float t, h;
     
     /******************   MQ-135 sensor parameteres and variables   ****************/
     #define RZERO 1
     #include "MQ135.h"
     MQ135 gasSensor = MQ135(A0);
     int val;
     int sensorPin = A0;
     int sensorValue = 0;
     float ppm, zero;
     
     /*****************   LEDs   ****************************************************/
     #define led_verde 3
     #define led_amarillo 4
     #define led_rojo 5
     
     unsigned long tiempo_anterior;  // Time counter
     
     /***********************   SETUP BLOCK   ***************************************/
     void setup( )
     {
       Serial.begin(115200);
       dht.begin();              // DHT-11 initialization
       
       if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Checking display present
         Serial.println(F("SSD1306 allocation failed"));
         for(;;);
      }
       delay(2000);
       display.clearDisplay();        // Initialization screen and
       display.setTextColor(WHITE);  // config text color
       
       pinMode(sensorPin, INPUT);    // MQ-135 pin data
     
       pinMode(led_verde, OUTPUT);
       pinMode(led_amarillo, OUTPUT);
       pinMode(led_rojo, OUTPUT);
       digitalWrite(led_verde, LOW);
       digitalWrite(led_amarillo, LOW);
       digitalWrite(led_rojo, LOW);
     
     }
     
     /***********************   LOOP BLOCK   *************************************/
     void loop( ) {
     
       t = dht.readTemperature();    // Read temperature
       h = dht.readHumidity();        // Read Humidity
     
       if (isnan(h) || isnan(t)) {    // If there aren't temperature and
         Serial.println("Fallo de lectura del sensor DHT !!!"); // humidity read, show message to inform
      }
     
       val = analogRead(A0);        // CO2 read
       zero = gasSensor.getRZero();  // Calibration value for the MQ-135 sensor
       ppm = gasSensor.getPPM();      // Formula in the library for obtaín the ppm of CO2
     
       chequeo_led ();              // Go and run to LEDs check method
       
       Serial.print( "T = " );        // Show values by the Serial Port
       Serial.print(t);
       Serial.print(" ºC, H = ");
       Serial.print(h);
       Serial.print( "%, " );
       Serial.print ("raw = ");
       Serial.print (val);
       Serial.print (", rzero: ");
       Serial.print (zero);
       Serial.print (", ppm: ");
       Serial.println (ppm);
       delay (1000);
     
       if ( millis()-tiempo_anterior >= 60000) { // If the time past is most or equal than 60 sg
             encendido_pantalla();    // Execute the turn on screen method.
             tiempo_anterior = millis(); // Save the actual time.
      }
     }
     
     void chequeo_led() {
       if (ppm >= 800) {              // If the CO2 concentration is equal o most than 800
         digitalWrite(led_rojo, HIGH);        // Turn on de red LED
         tone(8, NOTE_C5, 5000);            // Buzzer sound
         display.clearDisplay();            // Set the screen parameters to show the PPM value
         display.setTextSize(2);
         display.setCursor(7,0);
         display.print("CO2 (PPM):");
         display.setTextSize(3);
         display.setCursor(40,35);
         display.print(ppm,0);
         display.display();
         delay(10000);
      } else {
         digitalWrite(led_rojo, LOW);
         display.clearDisplay();
         display.display(); }
       
       if (ppm >= 551 && ppm <= 799) {
         digitalWrite(led_amarillo, HIGH); // The yellow LED turno on if the CO2 concentration
      } else {
         digitalWrite(led_amarillo, LOW); }    // is between 551 and 799
       
       if (ppm <= 550) {
         digitalWrite(led_verde, HIGH); // The green LED turn on only when the CO2
      } else {
         digitalWrite(led_verde, LOW); }      // concentration is most low than 551
     }
     
     void encendido_pantalla() {    // Turn on screen method
       display.clearDisplay();              // Set the screen parameters and show the PPM value
       display.setTextSize(2);
       display.setCursor(7,0);
       display.print("CO2 (PPM):");
       display.setTextSize(3);
       display.setCursor(40,35);
       display.print(ppm,0);
       display.display();
       delay(3000);
       
       display.clearDisplay();              // Set the display parameters and show the Humidity value
       display.setTextSize(2);
       display.setCursor(20,0);
       display.print("HUMEDAD:");
       display.setTextSize(3);
       display.setCursor(20,35);
       display.print(h,1);
       display.setCursor(90,35);
       display.print("%");
       display.display();
       delay(3000);
       
       display.clearDisplay();              // Set the display parameters and show the Temperature value
       display.setTextSize(2);
       display.setCursor(40,0);
       display.print("TEMP:");
       display.setTextSize(3);
       display.setCursor(5,35);
       display.print(t,1);
       display.setCursor(85,35);
       display.cp437(true);
       display.write(167);
       display.setCursor(107,35);
       display.print("C");
       display.display();
       delay(3000);
       
       display.clearDisplay();
       display.display();
     }

    Schaltungsaufbau
    Schaltungsaufbau

    Danke an Miguel Torres Gordo für seinen Beitrag.

    DisplaysFür arduinoProjekte für anfängerSensoren

    12 Kommentare

    Georg Franke

    Georg Franke

    Fazit vorweg: Der MQ135 kann kein CO2 (Kohlenstoffdioxid, Kohlendioxid) messen.
    Ich habe zunächst auch gehofft und geglaubt, dass der MQ135 dies könnte. Ich hatte aus Laubabfällen im Garten Biogas hergestellt, das mitunter brennbar ist oder nicht. Biogas kann u.a. Methan(brennbar) und CO2 enthalten. Um das Gasgemisch zu analysieren, habe ich einen Gaschromatographen(GC) von CMA gekauft und wollte den MQ135 als Gasdetektor verwenden. Der GC trennt die einzelnen Gaskomponenten und führt sie nacheinander zum Detektor. Das hat bei mir bei allen brennbaren Gasen (z.B. Wasserstoff, Propan, Butan, Alkoholdampf, Azetondampf) funktioniert nur eben nicht mit CO2. Im Nachhinein ist mir auch klar geworden, warum es auch theoretisch gar nicht geht: Der MQ135 besitzt eine SnO2-Schicht zur Detektion reduzierender Substanzen. Dieses SnO2 wird dabei teilweise reduziert und dadurch elektrisch leitfähiger, d.h. der Widerstand sinkt. Leider ist CO2 keine reduzierende Verbindung und kann daher nicht mit dem SnO2 reagieren. In einigen früheren Kommentaren wurde bereits darauf hingewiesen, worauf Miguel Torres auf das Datenblatt verwies. Ich habe das Datenblatt gesehen. In einem Diagramm wird der Zusammenhang zwischen Gaskonzentration verschiedener Gase in ppm und dem Widerstand des MQ135 dargestellt. Meine Lehrer hätten mir wahrscheinlich eine glatte 6 gegeben, In der Legende rechts oben stehen einige Gase: Al R oder AI R soll vermutlich Luft (Air) bedeuten, dann kann man mit etwas Fantasie CO2 und CO erkennen, sowie NH4 (soll vielleicht Ammoniak sein, also NH3), den Rest kann ich mir gar nicht zusammenreimen. Es wurden 3 Messpunkte pro Gas eingezeichnet. Über die Messunsicherheit (Toleranzen), sowie Quelle und Reinheit der verwendeten Gase wurden keine Angaben gemacht. Wie gesagt, wir messen im ppm-Bereich, da wirken sich geringste Verunreinigungen stark auf das Messergebnis aus und gaukeln z. B. beim CO2 etwas vor, was gar nicht vorhanden ist.
    Übrigens: Anbieter des MQ135, wie AZ-Delivery oder Reichelt verzichten auf die Nennung von CO2 als detektierbares Gas

    Mario Bluhm

    Mario Bluhm

    Hallo,

    Ich habe den MQ-135 am Pico-w.
    Habe die PI Daten herunter geladen, angeglichen und er liefert werte. Habe zusätzlich einen DHT-11 angeschlossen.

    Jetzt komme ich mit den gelieferten Werten nicht klar. was wird mir angezeigt. Temperatur und Luftfeuchte ist mir klar.

    DHT11 Temperature: 22 Humidity: 48
    MQ135 RZero: 90.50353 Corrected RZero: 92.92871 Resistance: 56.37128 PPM: 261.504 Corrected PPM: 236.589ppm

    Was soll da CO2 sein? Das sollte ein Wert um die 412ppm sein.

    Andreas Wolter

    Andreas Wolter

    @Sirko: könnten Sie bitte so nett sein und dazu schreiben, was aus Ihrer Sicht nicht korrekt ist und was Sie geändert haben?
    Ich kann das an den Autoren weiterleiten und wir korrigieren das dann im Beitrag.
    Vielen Dank.

    Grüße,
    Andreas Wolter
    AZ-Delivery Blog

    Sirko

    Sirko

    Das ganze mal etwas Richtiger (achte auf die auswahl dhd 11 oder dht 22)

    #include
    #include

    /* MQ135 + DHT Temp Sensor

    Combination of the MQ135 air quality sensor and a DHT11/22 temperature sensor to accurately measure ppm values through the library correction. Uses the Adafruit DHT Sensor Library: https://github.com/adafruit/DHT-sensor-library Written by: https://github.com/Phoenix1747/MQ135

    */

    #define PIN_MQ135 A2 // MQ135 Analog Input Pin
    #define DHTPIN 2 // DHT Digital Input Pin
    #define DHTTYPE DHT22 // DHT11 or DHT22, depends on your sensor

    MQ135 mq135_sensor(PIN_MQ135);
    DHT dht(DHTPIN, DHTTYPE);

    float temperature, humidity; // Temp and Humid floats, will be measured by the DHT

    void setup() {
    Serial.begin(9600);

    dht.begin();

    }

    void loop() {
    humidity = dht.readHumidity();
    temperature = dht.readTemperature();

    // Check if any reads failed and exit early (to try again). if (isnan(humidity) || isnan(temperature)) { Serial.println(F(“Failed to read from DHT sensor!”)); return; } float rzero = mq135_sensor.getRZero(); float correctedRZero = mq135_sensor.getCorrectedRZero(temperature, humidity); float resistance = mq135_sensor.getResistance(); float ppm = mq135_sensor.getPPM(); float correctedPPM = mq135_sensor.getCorrectedPPM(temperature, humidity); Serial.print("MQ135 RZero: "); Serial.print(rzero); Serial.print("\t Corrected RZero: "); Serial.print(correctedRZero); Serial.print("\t Resistance: "); Serial.print(resistance); Serial.print("\t PPM: "); Serial.print(ppm); Serial.print(“ppm”); Serial.print("\t Corrected PPM: "); Serial.print(correctedPPM); Serial.print(“ppm”); Serial.print( "\t T = " ); Serial.print(temperature); Serial.print("\t ºC, H = "); Serial.print(humidity); Serial.println( "%, " ); delay(10000);

    }

    Andreas Wolter

    Andreas Wolter

    @Erik Huber: Danke für den Hinweis. Ich habe das an den Autoren weitergegeben. Wir checken das und ändern das dann.

    Grüße,
    Andreas Wolter
    AZ-Delivery Blog

    Erik Huber

    Erik Huber

    Hi, Im Code ist ein Fehler.
    #define RZERO 1
    Es ist zwar definiert, aber nirgends wird es angewendet. Der Korrekte Befehl lautet daher nicht: MQ135 gasSensor = MQ135;
    Sondern: MQ135 gasSensor(A0, RZERO);

    Erst dann kann man den RZERO Wert nutzen.
    Also, den Wert von RZERO auf 1 lassen, dann 12 Stunden den Sensor an der guten Luft lassen mit Stormversorgung. Danach den RZERO Wert ablesen und den Wert im Code bei "#define RZERO " eintragen. Also nur die “1” mit dem Wert austauschen.

    iberotecno

    iberotecno

    Good work, but the problem is the library. The library author Georg Krocker’s says “The library also provides functions to apply the temperature/humidity correction that is shown in Fig 4 of the datasheet, but I do not trust the datasheet there, so this should not be used for the moment.” Source: https://hackaday.io/project/3475-sniffing-trinket/log/12363-mq135-arduino-library I also tryed with this method and the measures are inaccurate. More inaccurate than measures without temperature and humidity correction. We need another solution.

    Miguel Torres

    Miguel Torres

    Hello Philipp,

    The difference in price of the MQ-135 sensor versus the MHZ-19 is very significant for Arduino projects.

    Miguel Torres

    Miguel Torres

    According to the data sheet for this sensor, this also measures CO2. I leave a link where it shows the sensitivity for different gases.
    https://www.olimex.com/Products/Components/Sensors/Gas/SNS-MQ135/resources/SNS-MQ135.pdf

    mi

    mi

    hmmmm – kann es sein, dass der MQ-135 kein CO2 sondern nur CO misst ?

    Philipp Landhäußer

    Philipp Landhäußer

    Hallo,
    ein sehr guter Bericht aber das Problem ist, dass der MG-135 nur CO misst und kein CO2. Dafür wäre eher der MHZ-19 geeignet.

    Mfg

    Andreas Waldbrenner

    Andreas Waldbrenner

    Wäre super, wenn man mit einem Knopfdruck alle Teile im Warenkorb hätte. Oder habe ich diese Funktion übersehen? Andi

    Kommentar hinterlassen

    Alle Kommentare werden von einem Moderator vor der Veröffentlichung überprüft

    Empfohlene Blogbeiträge

    1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
    2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
    3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
    4. ESP32 - das Multitalent - AZ-Delivery