Kohlendioxid Warngerät Teil 2

Hier der zweite Teil des Kohlendioxid Warngerät, an dem jetzt noch ein LCD Display und ein Piezo Speaker angeschlossen wird. Somit können nun die Werte an dieser Co2-Ampel selbst abgelesen werden und kann jetzt auch ein akustisches Alarmsignal abgeben, selbst wenn es in einer nicht beobachteten Ecke seinen Dienst verrichtet. Weiter unten gibt es auch alternativ eine ESP8266er Version mit OLED-Display.

Hinzugekommene Hardware:
LCD Display 2004 mit I2C Modul
Buzzer (Piezo-Speaker)
stärkeres Netzteil

Datenblatt:
I2C-Modul

Quellcode:

// CO2-Ampel mit Alarm
// Automatische Selbstkalibrierung eingeschaltet
// prilchen.de

#include <Adafruit_SCD30.h>
#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

Adafruit_SCD30  scd30; //CO2 Sensor
LiquidCrystal_I2C lcd(0x27, 20, 4);  //Display  (I2C-Adresse/Zeichen pro Zeile/Anzahl Zeilen)
#define PIN 9 // Pin des WS2812b LED Ring
Adafruit_NeoPixel strip = Adafruit_NeoPixel(8, PIN, NEO_GRB + NEO_KHZ800);
int NUM_LEDS = strip.numPixels();
float sinVal; //Alarmgeber
int toneVal; //fuer Alarmgeber

void setup(void) {
  pinMode(8, OUTPUT); //Piezo Speaker
  lcd.init(); //Im Setup wird das LCD gestartet
  lcd.backlight(); //Hintergrundbeleuchtung von LCD einschalten (0 schaltet die Beleuchtung aus).
  strip.begin();
  strip.setBrightness(60);
  strip.show();

  Serial.begin(115200);
  while (!Serial) delay(10);     // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("Adafruit SCD30 Sensor adjustment test!");

  // Try to initialize!
  if (!scd30.begin()) {
    Serial.println("Failed to find SCD30 chip");
    while (1) {
      delay(10);
    }
  }
  Serial.println("SCD30 Found!");
  Serial.println("\n\n");
  // entweder Automatische Selbstkalibrierung oder Erzwungene Neukalibrierung aktivieren (nie beide!!!)
  scd30.selfCalibrationEnabled(true);           //Automatische Selbstkalibrierung eingeschaltet
  //oder
  //scd30.forceRecalibrationWithReference(400);   //Erzwungene Neukalibrierung beginnt bei Neustart bei Wert 400
}

void loop() {
  if (scd30.dataReady()) {

    if (!scd30.read()) {
      Serial.println("Error reading sensor data");
      return;
    }

    Serial.print("Temperature: ");
    Serial.print(scd30.temperature);
    Serial.println(" degrees C");

    Serial.print("Relative Humidity: ");
    Serial.print(scd30.relative_humidity);
    Serial.println(" %");

    Serial.print("CO2: ");
    Serial.print(scd30.CO2, 3);
    Serial.println(" ppm");
    Serial.println("");
    //Beginn LCD Ausgabe:
    lcd.setCursor(0, 0); //Der folgende Text soll beim LCD beim ersten Zeichen in der ersten Zeile beginnen.
    lcd.print("Temperatur:"); //Ausgabe in der ersten Zeile
    lcd.setCursor(13, 0);
    lcd.print(scd30.temperature);
    lcd.setCursor(19, 0); //Der folgende Text soll beim LCD beim 19ten Zeichen in der ersten Zeile beginnen.
    lcd.print("C");
    lcd.setCursor(0, 1); //Der folgende Text soll beim LCD beim ersten Zeichen in der zweiten Zeile beginnen.
    lcd.print("Luftfeucht:");
    lcd.setCursor(13, 1);
    lcd.print(scd30.relative_humidity);
    lcd.setCursor(19, 1);
    lcd.print("%");
    lcd.setCursor(0, 3); //Der folgende Text soll beim LCD beim ersten Zeichen in der dritten Zeile beginnen.
    lcd.print("CO2 Wert:");
    lcd.setCursor(10, 3);
    lcd.print(scd30.CO2, 2);
    lcd.setCursor(17, 3);
    lcd.print("ppm");
    delay(1000);
  }
  if (scd30.CO2 < 800) {
    setNeoPixel(0, 255, 0);
    noTone(8); //kein alarm
  }
  else
  {
    if (scd30.CO2 < 1200) {
      setNeoPixel(255, 255, 0);
      noTone(8); //kein alarm
    }
    else
    {
      setNeoPixel(255, 0, 0);
      //alarmton start
      for (int x = 0; x < 180; x++) {
        // convert degrees to radians then obtain sin value
        sinVal = (sin(x * (3.1412 / 180)));
        // generate a frequency from the sin value
        toneVal = 2000 + (int(sinVal * 1000));
        tone(8, toneVal);
        delay(2);
      }
    }
  }

  delay(100);
}

void setNeoPixel(int r, int g, int b) {
  // Walk through each Neopixel
  for (int i = 0; i < NUM_LEDS; i++) { // For each pixel...
    // pixels.Color() takes RGB values, from 0,0,0 up to 255,255,255
    strip.setPixelColor(i, strip.Color(r, g, b));
    strip.show();   // sendet geaenderte pixel Farben an LED Ring.
  }
}

Der Teil 1 und der Teil 3 dieser Reihe sind hier zu finden:
Kohlendioxid CO2 Warngerät – Teil 1
Kohlendiocid CO2 Warngerät – Teil 3


Hier die ESP8266 Lösung:
hier jetzt alternativ eine Version mit einem ESP8266 und anstatt ein LCD Display nun ein OLED-Display

Hardware:
NodeMCU ESP8266
Sensirion SCD30
NeoPixel Ring
Buzzer (Piezo-Speaker)
OLED Display SSD1306 
Power Supply USB 3A

Verdrahtung:

Quellcode:

#include <Adafruit_SCD30.h>
#include <Adafruit_NeoPixel.h>
#include <U8g2lib.h>
#include <U8X8lib.h>

Adafruit_SCD30  scd30;
#define PIN 2 // Pin des WS2812b (Bei ESP8266 an pin D4)
 Adafruit_NeoPixel strip = Adafruit_NeoPixel(12, PIN, NEO_GRB + NEO_KHZ800);
 int NUM_LEDS = strip.numPixels();
  U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(/* rotation=*/U8G2_R0, /* reset=*/ U8X8_PIN_NONE); //oled display

void setup(void) {
  strip.begin();
  strip.setBrightness(60);
  strip.show(); 
  u8g2.begin();  
  pinMode(14, OUTPUT); //Piezo Speaker
  Serial.begin(115200);
  while (!Serial) delay(10);     // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("Adafruit SCD30 Sensor adjustment test!");

  // Try to initialize!
  if (!scd30.begin()) {
    Serial.println("Failed to find SCD30 chip");
    while (1) { delay(10); }
  }
  Serial.println("SCD30 Found!");

  /***
   * Der folgende Code zeigt die aktuellen Einstellungen für jede der
   * Einstellungen, die geändert werden können. Um zu sehen, wie sie funktionieren, deaktivieren Sie die Einstellung
   * Code über einer Statusmeldung und Anpassen des Werts
   *
   * **Note:** Da die automatische Selbstkalibrierung oder die erzwungene Neukalibrierung immer wieder
   * den Referenzwert überschreibt, sollten Sie nur das eine oder das andere setzen
  ***/


  /*** Passen Sie die Geschwindigkeit, mit der Messungen durchgeführt werden, von 2-1800 Sekunden an */
  // if (!scd30.setMeasurementInterval(5)) {
  //   Serial.println("Failed to set measurement interval");
  //   while(1){ delay(10);}
  // }
  Serial.print("Measurement interval: ");
  Serial.print(scd30.getMeasurementInterval());
  Serial.println(" seconds");


  /*** Starten Sie die kontinuierliche Messung mit einem Druckversatz von 700 bis 1400 Millibar neu.
   * Wenn Sie kein Argument anführen oder den Offset auf 0 setzen, wird die Offsetkorrektur deaktiviert
   */
  // if (!scd30.startContinuousMeasurement(15)){
  //   Serial.println("Failed to set ambient pressure offset");
  //   while(1){ delay(10);}
  // }
  Serial.print("Ambient pressure offset: ");
  Serial.print(scd30.getAmbientPressureOffset());
  Serial.println(" mBar");


  /*** Legen Sie einen Höhenversatz in Metern über dem Meeresspiegel fest
   * Offset-Wert, der im nichtflüchtigen Speicher von SCD30 gespeichert ist.
   * Wenn Sie einen Höhenversatz festlegen, wird jeder Druckversatz überschrieben.
   */
  // if (!scd30.setAltitudeOffset(110)){
  //   Serial.println("Failed to set altitude offset");
  //   while(1){ delay(10);}
  // }
  Serial.print("Altitude offset: ");
  Serial.print(scd30.getAltitudeOffset());
  Serial.println(" meters");


  /*** Stellen Sie einen Temperaturversatz in Hundertste Grad Celsius ein.
   * Offset-Wert, der im nichtflüchtigen Speicher von SCD30 gespeichert ist.
   */
  // if (!scd30.setTemperatureOffset(1984)){ // 19.84 degrees celcius
  //   Serial.println("Failed to set temperature offset");
  //   while(1){ delay(10);}
  // }
  Serial.print("Temperature offset: ");
  Serial.print((float)scd30.getTemperatureOffset()/100.0);
  Serial.println(" degrees C");


  /*** Zwingen Sie den Sensor, mit dem angegebenen Referenzwert von 400-2000 ppm neu zu kalibrieren. Durch das Schreiben einer Neukalibrierungsreferenz werden alle vorherigen Selbstkalibrierungswerte überschrieben.
   * Reference value stored in non-volatile memory of SCD30.
   */
  // if (!scd30.forceRecalibrationWithReference(400)){
  //   Serial.println("Failed to force recalibration with reference");
  //   while(1) { delay(10); }
  // }
  Serial.print("Forced Recalibration reference: ");
  Serial.print(scd30.getForcedCalibrationReference());
  Serial.println(" ppm");


  /*** Aktivieren oder deaktivieren Sie die automatische Selbstkalibrierung (ASC).    
   *  Parameter, der im nichtflüchtigen Speicher von SCD30 gespeichert ist.   
   *  Durch aktivierende Selbstkalibrierung werden alle zuvor festgelegten erzwungenen Kalibrierungswerte überschrieben
   *  ASC benötigt Dauerbetrieb mit mindestens 1 Stunde 400ppm CO2-Konzentration täglich.
   */
  // if (!scd30.selfCalibrationEnabled(true)){
  //   Serial.println("Failed to enable or disable self calibration");
  //   while(1) { delay(10); }
  // }
  if (scd30.selfCalibrationEnabled()) {
    Serial.print("Self calibration enabled");
  } else {
    Serial.print("Self calibration disabled");
  }

  Serial.println("\n\n");
}

void loop() {
  if (scd30.dataReady()) {
    
    if (!scd30.read()){ 
      Serial.println("Error reading sensor data"); 
      return; 
    }

    Serial.print("Temperature: ");
    Serial.print(scd30.temperature);
    Serial.println(" degrees C");
    
    Serial.print("Relative Humidity: ");
    Serial.print(scd30.relative_humidity);
    Serial.println(" %");
    
    Serial.print("CO2: ");
    Serial.print(scd30.CO2, 3);
    Serial.println(" ppm");
    Serial.println("");

    u8g2.setFont(u8g2_font_profont17_tf);
  
        u8g2.drawStr(35,15,"CO2 Wert");
        u8g2.setCursor(50,35);
        u8g2.println(scd30.CO2);
        u8g2.sendBuffer();  
        u8g2.clearBuffer();
  }
if (scd30.CO2<800){ 
setNeoPixel(0, 255, 0);
digitalWrite(14, LOW); 
}
else
{
  if (scd30.CO2<1200){ 
setNeoPixel(255, 255, 0);
digitalWrite(14, LOW); 
}
else
{ 
setNeoPixel(255, 0, 0);
digitalWrite(14, HIGH); 
}
}

  delay(1000);
}
void setNeoPixel(int r, int g, int b){
    // Walk through each Neopixel
    for(int i=0; i<NUM_LEDS; i++) { // For each pixel...
      // pixels.Color() takes RGB values, from 0,0,0 up to 255,255,255
      strip.setPixelColor(i, strip.Color(r, g, b));
      strip.show();   // Send the updated pixel colors to the hardware.
    } 
  }
, ,