CO2-Ampel

Varianten

Arduino mit Z19B-Sensor und

  • LEDs
  • LEDs und Buzzer
  • LEDs, Buzzer und OLED-Anzeige
  • LEDs, BUZZER, OLED-Anzeige und SD-Speicher (und UHR)
  • LEDs, BUZZER, OLED-Anzeige und WLAN-Anbindung an einen Raspi mit Datenbank und Apache

fertige Ampel - LED mit Buzzer und OLED-Anzeige (ohne UHR und SD-Karte)

  • Nano 5 €
  • CO2-Sensor 20 €
  • OLED 5 €
  • Kleinteile 4 €
  • POWERBANK 6 €
  • 40 € pro Ampel

Sensorbeschaltung

  • PWM - Pin 6
  • GND - Masse
  • Vin - +5V
  • HD über einen Taster oder ein Steckkabel an Masse zur Kalibrierung

Messbeispiel

Breadboardvariante

Programmcode

  • Zusammenkopierter Sketch
    • ACHTUNG: der dieser Sketch ist für die kleinste (billigste) NANO-Variente zur groß.
    • mit UHR und SD-Kartenschreiber
    • Aufgabe: Reduziere den Programmcode auf ein Minimum
/**
 * CO2-Messung mit Sensor Typ MHZ19B
 * Messwerterfassung durch PWM-Signal
 */

/**************************************
 *  für den Betrieb der OLED-Anzeige  *
 **************************************/
#include "SSD1306AsciiAvrI2c.h"                            // OLED-Bibliothek
#define I2C_ADDRESS_OLED 0x3C                              // 0X3C+SA0 - 0x3C or 0x3D OLED
#define RST_PIN -1                                         // Define proper RST_PIN if required. OLED
#include <SD.h>                                            // In diesem Sketch verwenden wir die <SD.h> library
#include "RTClib.h"
SSD1306AsciiAvrI2c oled;
RTC_DS3231 rtc;
File Messdaten;                                            // An dieser Stelle wird die Variable "Messdaten" als File (dts. Datei) deklariert.

int z = 0;                                                 // globale Zaehlvariable für die SD-Kartennutzung in der loop

/************************************************
 *  für den Betrieb der LED-Anzeige und Summer  *
 ************************************************/

  const int summer  = 4;
  const int gruen   = 7;
  const int gelb    = 8;
  const int rot     = 9;
  const int blau    = 10;

/************************************************
 *  Alarmstufen
 *  *********************************************/

 const int guteLuft          =  800;
 const int mittlereQualitaet =  950;
 const int schlechteLuft     = 1200;
 const int vielzuvielCO2     = 2000;
 const int luftAlarm         = 2500;
  
/**************************************
*  für den Betrieb des MH-Z19B        *
**************************************/

  const int pwmpin = 6;                                     // Der Sensor hängt an Pin 6
  const int range = 5000;                                   // Der eingestellte Messbereich (0-5000ppm)
  int  ppm_pwm = 0;
  
/**************************************
*  Festlegung Messintervall           *
**************************************/

 const int schreibPause = 12000;                            // nächste Messung erst nach 12 Sekunden     

void setup() {   

/**************************************
 *  für den Betrieb der OLED-Anzeige  *
 **************************************/

    #if RST_PIN >= 0
    oled.begin(&Adafruit128x64, I2C_ADDRESS_OLED, RST_PIN);
    #else // RST_PIN >= 0
    oled.begin(&Adafruit128x64, I2C_ADDRESS_OLED);
    #endif // RST_PIN >= 0
    oled.setFont(System5x7);                               // Call oled.setI2cClock(frequency) to change from the default frequency.
    oled.clear();
    oled.println(" CO2 - Ampel ");
    oled.println(" ------------");
    oled.println(" SAS-Projekt 2020");
    tone(summer,444);
    // delay(20);
    noTone;
       

/**************************************
 *  für den Betrieb der LED-Anzeige   *
 **************************************/

   pinMode(gruen, OUTPUT);
   pinMode(gelb, OUTPUT);
   pinMode(rot, OUTPUT);
   pinMode(blau, OUTPUT);
   noTone;
   ledTest();
   Serial.begin(9600);   

/**********************************************************************************************************
 * 
 *              UHR
 *              
 **********************************************************************************************************/

  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
    }
  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
    }
    
/**********************************************************************************************************
 * 
 *        SD-Kartenleser - Schreibtest
 *        
 *********************************************************************************************************/

  Serial.println("Initialisiere SD-Karte");   
  if (!SD.begin(5)) {                                          // Wenn die SD-Karte nicht (!SD.begin) gefunden werden kann, ...
    Serial.println("Initialisierung fehlgeschlagen!");         // ... soll eine Fehlermeldung ausgegeben werden. ....
    return;
  }
  Serial.println("Initialisierung abgeschlossen");             // ... Ansonsten soll die Meldung "Initialisierung abgeschlossen." ausgegeben werden.
  
 /**********************************************************************************************************
 * 
 *        SD-Kartenleser - Lesetest NUN WIRD der bisherige Text AUSGELESEN 
 *        
 *********************************************************************************************************/                                                              
                                                               
  Messdaten = SD.open("co2.txt");                              // Die Textdatei auf der SD-Karte wird wieder geoeffnet...
  if (Messdaten)  {                                            
     Serial.println("alte Werte: ");                           // ... und der Name der Datei wird ausgegeben. 
     while (Messdaten.available())                             // Anschließend wird die Datei so lange ausgelesen (while)...
       {                          
        Serial.write(Messdaten.read());                        // ... bis keine Daten mehr gefunden werden können.
        digitalWrite(blau, HIGH);
        digitalWrite(blau, LOW);
        
       }
     Messdaten.close();                                        // Im Anschluss wird die Textdatei wieder geschlossen.
    } 
   else                                                        // Sollte keine Textdatei (also test.txt) gefunden werden können...
    {
    Serial.println("Textdatei konnte nicht geoeffnet werden"); // ... erscheint eine Fehlermeldung im seriellen Monitor.
    }
    digitalWrite(blau, LOW);

/**************************************
 *  für den Betrieb des MH-Z19B        *
 **************************************/
    
    pinMode(pwmpin, INPUT);                                    // PWM-Pin auf Eingang setzen

}                                                              // ENDE Setup

/***********************************************************************************************************************
*
* LOOP
*
***********************************************************************************************************************/

void loop() {
  z = z+1;                                                  
  ppm_pwm = readCO2PWM();                                      // Messung der PWM-Länge mittels einer eigenen Funktion
  if (z > 4) {                                                 // erst die 5. Messung wird gesichert, dann ca. pro Minute eine
    messWertSchreibenSD();                                     // jeden 5. Messwert auf die SD-Karte schreiben (blaue LED)
    z = 0;                                                     // Zaehler zurueck setzen
  }
  oledAnzeige();                                               // Messwerte auf dem OLED ausgeben
  delay(schreibPause);                                         // PAUSE: nächste Messungen in 12 Sekunden (ca. 5 Messungen pro Minute)
}

/************************************************************************************************************************
*
* LOOP ENDE
*
************************************************************************************************************************/

/*********************************
*                                *
* Funktionen und Prozeduren      *
*                                *
*********************************/

/**********************************************************************************************************
 * 
 *                 Funktionen zum PWM-Auslese des CO2-Wertes
 *                 
 ***********************************************************************************************************/

  int readCO2PWM() {
  unsigned long th;
  int ppm_pwm = 0;
  float pulsepercent;
  do {
    th = pulseIn(pwmpin, HIGH, 1004000) / 1000;
    float pulsepercent = th / 1004.0;                                    // Pulslänge in Prozent (%)
    ppm_pwm = range * pulsepercent;                                      // PPM-Werte bei gegebenem Range
  } while (th == 0);                                                     // Der gemessene Wert wird an die loop()-Funktion zurückgegeben,                                                                        
  return ppm_pwm;                                                        // wo er dann ausgegeben wird.  
}

/**********************************************************************************************************
 * 
 *        SD-Schreibprocedur
 *        
 *********************************************************************************************************/

void messWertSchreibenSD() {
  Messdaten = SD.open("co2.txt", FILE_WRITE);                     // An dieser Stelle wird die Messdaten erstellt.   
  if (Messdaten)                                                  // Wenn die Messdaten ("co2.txt") gefunden wurde....
    {                                        
      ledSD();                                                    // Schreibanzeige - KEINE SD entfernen
      Serial.println("Schreibe in Messdaten...");                 // Meldung im seriellen Monitor für den Schreibvorgang
      DateTime now = rtc.now();                                   // altuelle Zeit auslesen
      Messdaten.print(now.year(), DEC);
      Messdaten.print('-');
      Messdaten.print(now.month(), DEC);
      Messdaten.print('-');
      Messdaten.print(now.day(), DEC);                            // im Format 2020-10-13 schreiben
      Messdaten.print(' ');
      Messdaten.print(now.hour(), DEC);
      Messdaten.print(':');
      Messdaten.print(now.minute(), DEC);
      Messdaten.print(':');
      Messdaten.print(now.second(), DEC);                         // im Format 10:35:22 schreiben
      Messdaten.print(' ' );    
      Messdaten.print(ppm_pwm);
      Messdaten.println(" ppm CO2");
      Messdaten.close();                                          // Anschließend wird die Messdaten wieder geschlossen...
      Serial.println("Abgeschlossen.");                             // ... und eine erneute Meldung im seriellen Monitor ausgegeben.
      Serial.println();
    } 
  else 
   {                                                              // Wenn !keine! Messdaten gefunden werden kann ...
    Serial.println("Messdaten konnte nicht ausgelesen werden");   // ... erscheint eine Fehlermeldung im seriellen Monitor.
   }
}

/**********************************************************************************************************
 * 
 *        OLED-Anzeigeprocedur
 *        
 *********************************************************************************************************/
 
void oledAnzeige() {
  DateTime now = rtc.now();                                   // altuelle Zeit auslesen
  oled.clear();
  oled.println("   CO2 - Ampel ");
  oled.println("-------------------");
  oled.println("    GYPT-HH   ");
  oled.println("-------------------");
  oled.println(" ");
  oled.print(" CO2 Wert: ");
  oled.print(ppm_pwm); 
  oled.println(" ppm");
  oled.println("-------------------");
  oled.print("      ");
  oled.print(now.hour(), DEC);
  oled.print(':');
  oled.println(now.minute(), DEC);
  ledRot();
  ledGruen();
  if (ppm_pwm > mittlereQualitaet) { ledGelb(); }
  if (ppm_pwm > schlechteLuft)     { ledRot();  } 
  if (ppm_pwm > vielzuvielCO2)     { ledblau();  } 
  if (ppm_pwm > luftAlarm)         { alarm();   }
  Serial.print("PWM-Messung: ");                         // Ausgabe der Werte über die serielle USB-Verbindung
  Serial.print(ppm_pwm);
  Serial.println(" ppm CO2");
}

/************************************************************************************************************
 * 
 *          LED-Anzeige mit Summer
 *          
 ***************************************************************************************************************/
void ledTest() {
           digitalWrite(gruen, HIGH);
           digitalWrite(gelb, HIGH);
           digitalWrite(rot, HIGH);
           digitalWrite(blau, LOW); 
           delay(600);
           digitalWrite(blau, HIGH); 
           delay(100);       
           digitalWrite(gruen, LOW);
           digitalWrite(gelb, LOW);
           digitalWrite(rot, LOW);
           digitalWrite(blau, LOW);            
           noTone(summer);
}
void ledGruen(){
          digitalWrite(gruen, HIGH);
          digitalWrite(gelb, LOW);
          digitalWrite(rot, LOW);
          digitalWrite(blau, LOW);
          noTone(summer);
}

void ledGelb(){
          digitalWrite(gruen, LOW);
          digitalWrite(gelb, HIGH);
          digitalWrite(rot, LOW);
          digitalWrite(blau, LOW);
          noTone(summer);
}
void ledRot(){
          digitalWrite(gruen, LOW);
          digitalWrite(gelb, LOW);
          digitalWrite(rot, HIGH);
          digitalWrite(blau, LOW);
          noTone(summer);
}
void ledblau(){
          digitalWrite(gruen, LOW);
          digitalWrite(gelb, LOW);
          digitalWrite(rot, HIGH);
          digitalWrite(blau, HIGH);
          delay(100);
          digitalWrite(blau, LOW);
          delay(200);
          digitalWrite(blau, HIGH);
          delay(200);
          digitalWrite(blau, LOW);
          delay(200);
          noTone(summer);
}
void alarm(){
          digitalWrite(gruen, HIGH);
          digitalWrite(gelb, HIGH);
          digitalWrite(rot, HIGH);
          digitalWrite(blau, HIGH);
          tone(summer,600);
}

void ledSD(){
          digitalWrite(gruen, LOW);
          digitalWrite(gelb, HIGH);
          digitalWrite(rot, LOW);
          digitalWrite(blau, HIGH);
          noTone(summer);
}

void ledAus() {
          digitalWrite(gruen, LOW);
          digitalWrite(gelb, LOW);
          digitalWrite(rot, LOW);
          digitalWrite(blau, LOW);
          noTone(summer);
}
QR-Code
QR-Code www-fuer-alle:co2-ampel (erstellt für aktuelle Seite)