====== WWW CO2-Messungen BIO ======
===== Basilikum =====
* [[https://wiki.gymsas.de/doku.php?id=www-fuer-alle:arduino|Arduinos im Unterricht - Informatik, Physik, Technik, ...]]
* NW-Projekt Klassenstufe 8
* [[lehrer:nwt:co2-messgeraet|intern: LEHRER]]
* [[lehrer:arduino:p48-nano-messbox]| LEHRER: P48-Nano-Messbox]]
* {{ :www-fuer-alle:arduino:nw-8-2024-09-09-musterauswertung.ods |Auswertungshilfe}}
Fragen und Anregungen an: [[Makerspace@GymSAS.de]]
===== Messgerät =====
* ARDUINO-NANO
* 3D-Druckgehäuse
{{:www-fuer-alle:arduino:2023-10-26-nw-co2-handmessgeraet.png?400 |}}
{{:www-fuer-alle:arduino:2023-10-17-co2-sd-bmp180-oled.png?400 |}}
===== Aufbau =====
{{:www-fuer-alle:arduino:2023-11-29-co2-basikikum-aufbau.jpg?200 |}}
===== Ergebnis =====
==== Vorversuch ====
{{:www-fuer-alle:01-co2-2023-12-20-nwt8-wachstumslampe.png?800 |}}
====== 48-Stunden-Messung ======
* 2 Stunden Licht
* 6 Stunden Dunkelheit
* 2 halbe Pflanzen
* 1 LED
{{:www-fuer-alle:arduino:basilikum-Topf.jpg?200|}}{{:www-fuer-alle:arduino:basilikum-2-teile.jpg?300|}}
=== CO2-07 ===
{{:www-fuer-alle:arduino:basilikum-08.png?800|}}
=== CO2-08 ===
{{:www-fuer-alle:arduino:basilikum-09.png?800|}}
==== Analyse der Daten: ====
=== CO2-Erzeugung (ohne Licht) ===
Die Daten herausfiltern, in denen die Temperatur konstant und niedrig ist (Lampe aus). In diesen Zeiträumen wird der CO2-Anstieg pro Minute berechnet.
=== CO2-Aufnahme (mit Licht) ===
Die Daten herausfiltern, in denen die Temperatur höher ist (Lampe an). In diesen Zeiträumen wird der CO2-Abfall pro Minute berechnet.
=== Berechnung: ===
* Die Rate der CO2-Veränderung (ppm pro Minute) für beide Zustände berechnen.
* Mit dem Volumen des Gefäßes (5 Liter) wird die CO2-Menge in Mikromol umgerechnet
* unter Verwendung der idealen Gasgleichung.
=== Ergebnisse: ===
Die CO2-Produktion und -Aufnahme pro Minute in relevanten Einheiten angeben.
=== Beispiel ===
{{:www-fuer-alle:arduino:co2-berechnung-01.png?600|}}
{{:www-fuer-alle:arduino:co2-berechnung-02.png?600|}}
{{:www-fuer-alle:arduino:co2-berechnung-03.png?600|}}
{{:www-fuer-alle:arduino:co2-berechnung-04.png?800|}}
====== Nachbau ======
===== 1. Grundfunktion - UNO mit Sensoren =====
==== Material ====
* Mikrocontroler ARDUINO UNO ([[https://www.berrybase.de/kompatibler-arduino-uno-mit-atmel-mega-328p-prozessor?utm_source=google&utm_medium=cpc&gad_source=1&gad_campaignid=21582945112&gclid=Cj0KCQjwjJrCBhCXARIsAI5x66WoZonZllkIIUrHZWs-EI6MgMJrqfKx18rFMD6vKDiGpvgeduENqgwaAhVtEALw_wcB|5 bis 20 EURO]])
* Co2-Sensor [[https://www.winsen-sensor.com/d/files/MH-Z19B.pdf|MHZ 19B (10 bis 40 Euro]] - [[https://www.blikk.it/forum/blog.php?bn=neuemedien_fb&lang=de&id=1575901160|Funktionsweise MHZ-19]]
* Erweiterung: Lufttemperatur und Luftdruck
* BMP180 (1 bis 4 EURO)
* Laptop (zum Programmieren und als Anzeige)
* Steckverbindungen
* 20 bis 40 EURO (Asien/Europa)
==== Steckplan ====
{{:www-fuer-alle:arduino:uno-mhz-19-bmp180.png?direct&400|}}
{{:www-fuer-alle:arduino:nano-mhz-bmp.png?direct&400|}}
==== Code ====
* Co2-Messung mit MHZ-19B über PWM-Kommunikation
/*********************************************************************************************************
*
* MHZ-19B, BMP 180 2025-06-12
*
*********************************************************************************************************/
#define ALTITUDE 8.0 // BMP 180 Borgfelde liegt 8 m ueber dem Meer
#include // BMP 180
#include // BMP 180
SFE_BMP180 pressure; // BMP 180 - Creating an object pressure
float StartZeit, LaufZeit; // Zeitpunkt der Messung
String dataString = ""; // Ausgabestring
int LeerZeile = 0;
/**************************************
* 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;
/**************************************
* für den Betrieb des BMP 180 *
**************************************/
double T, P, p0; // Speicher fuer temp, Druck relativer Druck
/**************************************
* Festlegung Messintervall *
**************************************/
const int SchreibPause = 29998; // naechste Messung erst nach ca. 30 Sekunden
int WarteZeit;
void setup() {
StartZeit = millis();
/**************************************
* für den Betrieb der Ausgaben *
**************************************/
Serial.begin(9600); // Serieller Monitor mit 9600 bit/s
/**************************************
* für den Betrieb des MH-Z19B *
**************************************/
pinMode(pwmpin, INPUT); // PWM-Pin auf Eingang setzen
/**************************************
* für den Betrieb des BMP-180 *
**************************************/
if (!pressure.begin()) {
delay(3000);
Serial.println("BMP-180 init failed!"); // while(true); // wartet, bis der Sensor sich meldet
}
Serial.print("Provided altitude: ");
Serial.print(ALTITUDE, 0);
Serial.println(" meters");
}
/*********************************************************************************************************
*
* H A U P T P R O G R A M M - Loop
*
*********************************************************************************************************/
void loop() {
DatenAuslesen();
SerialAusgabe();
}
/********************************************************************************************************
*
* Prozedur Datenauslesen
*
*********************************************************************************************************/
void DatenAuslesen(){
LaufZeit = millis() - StartZeit;
ppm_pwm = readCO2PWM(); // Messung der PWM-Länge mittels einer eigenen Funktion
DruckUndTemperaturMessung();
}
/********************************************************************************************************
*
* Ausgabe am seriellen Monitor
*
*********************************************************************************************************/
void SerialAusgabe(){
Serial.print(LaufZeit/1000,0);
Serial.print(" s | ");
Serial.print(ppm_pwm);
Serial.print(" ppm | ");
Serial.print(T,1);
Serial.print(" C | ");
Serial.print(p0);
Serial.print(" hPa | ");
Serial.print(P);
Serial.print(" hPa Luftdruck gemessen in Borgfelde 6 m ueber NN");
Serial.println();
}
/********************************************************************************************************
*
* 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.
}
/********************************************************************************************************
*
* Prozedur zum Auslese des BMP-180 (Druck- und Temperatursensor)
*
********************************************************************************************************/
void DruckUndTemperaturMessung(){
char status;
status = pressure.startTemperature();
if (status != 0) {
delay(status);
status = pressure.getTemperature(T);
if (status != 0) {
status = pressure.startPressure(3);
if (status != 0) {
delay(status);
status = pressure.getPressure(P, T);
if (status != 0) {
p0 = pressure.sealevel(P, ALTITUDE);
}
}
}
}
}
===== 2. Nano mit Sensoren und OLED-Display =====
==== Material ====
* Mikrocontroler ARDUINO NANO (oder UNO) ([[https://www.berrybase.de/kompatibler-arduino-uno-mit-atmel-mega-328p-prozessor?utm_source=google&utm_medium=cpc&gad_source=1&gad_campaignid=21582945112&gclid=Cj0KCQjwjJrCBhCXARIsAI5x66WoZonZllkIIUrHZWs-EI6MgMJrqfKx18rFMD6vKDiGpvgeduENqgwaAhVtEALw_wcB|5 bis 20 EURO]])
* Co2-Sensor [[https://www.winsen-sensor.com/d/files/MH-Z19B.pdf|MHZ 19B (10 bis 40 Euro]] - [[https://www.blikk.it/forum/blog.php?bn=neuemedien_fb&lang=de&id=1575901160|Funktionsweise MHZ-19]]
* Breadbord 400
* Lufttemperatur und Luftdruck
* BMP180 (1 bis 4 EURO)
* OLED zur Datenanzeige
* Laptop (zum Programmieren)
* Steckverbindungen
* 21 bis 45 EURO (Asien/Europa)
==== Schltplan ====
{{ :www-fuer-alle:arduino:co2-bmp180-oled-2025-06-11.png?direct&600 |}}
==== Steckplan ====
{{:www-fuer-alle:arduino:nano-mhz-bmp-oled-1.jpg?direct&200|}}
{{:www-fuer-alle:arduino:nano-mhz-bmp-oled-2.jpg?direct&200|}}
{{:www-fuer-alle:arduino:nano-mhz-bmp-oled-3.jpg?direct&200|}}
{{:www-fuer-alle:arduino:nano-mhz-bmp-oled-4.jpg?direct&200|}}
{{:www-fuer-alle:arduino:nano-mhz-bmp-oled-5.jpg?direct&200|}}
==== Code ====
* Co2-Messung über PWM-Kommunikation mit dem Sensor
/*********************************************************************************************************
*
* MHZ-19B, BMP 180 und OLED 2025-06-13
*
*********************************************************************************************************/
#include // OLED
#include "SSD1306Ascii.h" // OLED
#include "SSD1306AsciiWire.h" // OLED
#define I2C_ADDRESS 0x3C // OLED
SSD1306AsciiWire oled; // OLED
#define ALTITUDE 8.0 // BMP 180 Borgfelde liegt 8 m ueber dem Meer
#include // BMP 180
#include // BMP 180
SFE_BMP180 pressure; // BMP 180 - Creating an object pressure
float StartZeit, LaufZeit; // Zeitpunkt der Messung
String dataString = ""; // Ausgabestring
int LeerZeile = 0;
/**************************************
* 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;
/**************************************
* für den Betrieb des BMP 180 *
**************************************/
double T, P, p0; // Speicher fuer temp, Druck relativer Druck
/**************************************
* Festlegung Messintervall *
**************************************/
const int SchreibPause = 29998; // naechste Messung erst nach ca. 30 Sekunden
int WarteZeit;
void setup() {
StartZeit = millis();
/**************************************
* für den Betrieb des OLEDs *
**************************************/
Wire.begin();
Wire.setClock(400000L);
oled.begin(&Adafruit128x64, I2C_ADDRESS);
oled.setFont(System5x7); // Auswahl der Schriftart
oled.clear(); // Loeschen der aktuellen Displayanzeige
oled.println("+ Klimakoffer LMU +");
delay(1000);
/**************************************
* für den Betrieb der Ausgaben *
**************************************/
Serial.begin(9600); // Serieller Monitor mit 9600 bit/s
/**************************************
* für den Betrieb des MH-Z19B *
**************************************/
pinMode(pwmpin, INPUT); // PWM-Pin auf Eingang setzen
/**************************************
* für den Betrieb des BMP-180 *
**************************************/
if (!pressure.begin()) {
delay(3000);
Serial.println("BMP-180 init failed!"); // while(true); // wartet, bis der Sensor sich meldet
}
Serial.print("Provided altitude: ");
Serial.print(ALTITUDE, 0);
Serial.println(" meters");
}
/*********************************************************************************************************
*
* H A U P T P R O G R A M M - Loop
*
*********************************************************************************************************/
void loop() {
DatenAuslesen();
DatenAnzeigen();
SerialAusgabe();
delay(5000);
}
/********************************************************************************************************
*
* Prozedur Datenauslesen
*
*********************************************************************************************************/
void DatenAuslesen(){
LaufZeit = millis() - StartZeit;
ppm_pwm = readCO2PWM(); // Messung der PWM-Länge mittels einer eigenen Funktion
DruckUndTemperaturMessung();
}
/********************************************************************************************************
*
* Prozedur Daten auf dem OLED anzeigen
*
*********************************************************************************************************/
void DatenAnzeigen(){
oled.setFont(System5x7); // Auswahl der Schriftart
oled.clear(); // Loeschen der aktuellen Displayanzeige
oled.print("CO2: ");
oled.print(ppm_pwm);
oled.println(" ppm");
oled.println("-------------------");
oled.print("Temp. ");
oled.print(T,1);
oled.println(" C");
oled.println("-------------------");
oled.print("Druck ");
oled.print(p0,0);
oled.println(" hPa");
oled.println("-------------------");
oled.print("Zeit ");
oled.print(LaufZeit/1000,0);
oled.println(" s");
oled.println(" MB-2025-06-13");
}
/********************************************************************************************************
*
* Ausgabe am seriellen Monitor
*
*********************************************************************************************************/
void SerialAusgabe(){
Serial.print(LaufZeit/1000,0);
Serial.print(" s | ");
Serial.print(ppm_pwm);
Serial.print(" ppm | ");
Serial.print(T,1);
Serial.print(" C | ");
Serial.print(p0);
Serial.print(" hPa | ");
Serial.print(P);
Serial.print(" hPa Luftdruck gemessen in Borgfelde 8 m ueber NN");
Serial.println();
}
/********************************************************************************************************
*
* 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.
}
/********************************************************************************************************
*
* Prozedur zum Auslese des BMP-180 (Druck- und Temperatursensor)
*
********************************************************************************************************/
void DruckUndTemperaturMessung(){
char status;
status = pressure.startTemperature();
if (status != 0) {
delay(status);
status = pressure.getTemperature(T);
if (status != 0) {
status = pressure.startPressure(3);
if (status != 0) {
delay(status);
status = pressure.getPressure(P, T);
if (status != 0) {
p0 = pressure.sealevel(P, ALTITUDE);
}
}
}
}
}
===== 3. Nano mit Sensoren, OLED-Display und SD-Karten-Speicher =====
==== Material ====
* Mikrocontroler ARDUINO NANO (oder UNO) ([[https://www.berrybase.de/kompatibler-arduino-uno-mit-atmel-mega-328p-prozessor?utm_source=google&utm_medium=cpc&gad_source=1&gad_campaignid=21582945112&gclid=Cj0KCQjwjJrCBhCXARIsAI5x66WoZonZllkIIUrHZWs-EI6MgMJrqfKx18rFMD6vKDiGpvgeduENqgwaAhVtEALw_wcB|5 bis 20 EURO]])
* Co2-Sensor [[https://www.winsen-sensor.com/d/files/MH-Z19B.pdf|MHZ 19B (10 bis 40 Euro]] - [[https://www.blikk.it/forum/blog.php?bn=neuemedien_fb&lang=de&id=1575901160|Funktionsweise MHZ-19]]
* Breadbord 400
* Lufttemperatur und Luftdruck
* BMP180 (1 bis 4 EURO)
* OLED zur Datenanzeige
* SD-Kartenspeicher
* Laptop (zum Programmieren)
* Steckverbindungen
* 22 bis 48 EURO (Asien/Europa)
==== Steckplan ====
{{ :www-fuer-alle:arduino:co2-sd-bmp180-oled-2025-06-11.png?direct&600 |}}
==== Code ====
* Co2-Messung über PWM-Kommunikation mit dem Sensor
===== 4. Nano mit Sensoren, OLED-Display und SD-Karten-Speicher im 3D-Druck-Gehäuse =====
==== Material ====
* Mikrocontroler ARDUINO NANO (oder UNO) ([[https://www.berrybase.de/kompatibler-arduino-uno-mit-atmel-mega-328p-prozessor?utm_source=google&utm_medium=cpc&gad_source=1&gad_campaignid=21582945112&gclid=Cj0KCQjwjJrCBhCXARIsAI5x66WoZonZllkIIUrHZWs-EI6MgMJrqfKx18rFMD6vKDiGpvgeduENqgwaAhVtEALw_wcB|5 bis 20 EURO]])
* Co2-Sensor [[https://www.winsen-sensor.com/d/files/MH-Z19B.pdf|MHZ 19B (10 bis 40 Euro]] - [[https://www.blikk.it/forum/blog.php?bn=neuemedien_fb&lang=de&id=1575901160|Funktionsweise MHZ-19]]
* Breadbord 400
* Lufttemperatur und Luftdruck
* BMP180 (1 bis 4 EURO)
* OLED zur Datenanzeige
* SD-Kartenspeicher
* Laptop (zum Programmieren)
* Steckverbindungen
* 22 bis 48 EURO (Asien/Europa)
==== Schaltplan ====
{{ :www-fuer-alle:arduino:co2-sd-bmp180-oled-2025-06-11.png?direct&600 |}}
==== Steckplan ====
{{:www-fuer-alle:arduino:nano-mhz-bmp-oled-sd-1.jpg?direct&100|}}
{{:www-fuer-alle:arduino:nano-mhz-bmp-oled-sd-2.jpg?direct&200|}}
{{:www-fuer-alle:arduino:nano-mhz-bmp-oled-sd-3.jpg?direct&300|}}
==== Code ====
* Co2-Messung über PWM-Kommunikation mit dem Sensor
/*********************************************************************************************************
*
* SD-Karte, MHZ-19B, BMP 180 und OLED 2025-06-13
*
*********************************************************************************************************/
#include // OLED
#include "SSD1306Ascii.h" // OLED
#include "SSD1306AsciiWire.h" // OLED
#define I2C_ADDRESS 0x3C // OLED
SSD1306AsciiWire oled; // OLED
/*********************************************************************************************************
*
* SD card datalogger
* MOSI - pin 11
* MISO - pin 12
* CLK - pin 13
* CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN) by Tom Igoe
*
********************************************************************************************************/
#include // SD-Karte
#include // SD-Karte In diesem Sketch verwenden wir die library
#define ALTITUDE 8.0 // BMP 180 Borgfelde liegt 8 m ueber dem Meer
#include // BMP 180
#include // BMP 180
SFE_BMP180 pressure; // BMP 180 - Creating an object pressure
const int chipSelect = 4; // CS-Pin der SD-Karte
bool SchreibZugriff = false; // Funktionsfaehigkeit beim Datensichern
float StartZeit, LaufZeit; // Zeitpunkt der Messung
String dataString = ""; // Ausgabestring
int LeerZeile = 0;
/**************************************
* 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;
/**************************************
* für den Betrieb des BMP 180 *
**************************************/
double T, P, p0; // Speicher fuer temp, Druck relativer Druck
/**************************************
* Festlegung Messintervall *
**************************************/
const int SchreibPause = 29998; // naechste Messung erst nach ca. 30 Sekunden
int WarteZeit;
void setup() {
StartZeit = millis();
/**************************************
* für den Betrieb des OLEDs *
**************************************/
Wire.begin();
Wire.setClock(400000L);
oled.begin(&Adafruit128x64, I2C_ADDRESS);
oled.setFont(System5x7); // Auswahl der Schriftart
oled.clear(); // Loeschen der aktuellen Displayanzeige
oled.println("+ Klimakoffer LMU + ");
delay(1000);
/**************************************
* für den Betrieb der Ausgaben *
**************************************/
Serial.begin(9600); // Serieller Monitor mit 9600 bit/s
Serial.print("Initializing SD card...");
if (!SD.begin(chipSelect)) { // SD-Karte suchen
Serial.println("SD-Karte fehlt"); // Keine SD-Karte gefunden
SchreibZugriff = false;
oled.setFont(System5x7); // Auswahl der Schriftart
for (int i=20; i > 0; i--){
oled.clear(); // Loeschen der aktuellen Displayanzeige
oled.println(" NWP 2024 ");
oled.println(" ----------------------");
oled.println(" ");
oled.println(" KEINE SD-Karte ");
oled.println(" ");
oled.println(" GEFUNDEN!! ");
oled.println(" ");
oled.println(i);
delay(1000);
}
}
else {
Serial.println("card initialized."); // alles ok
SchreibZugriff = true;
}
/**************************************
* für den Betrieb des MH-Z19B *
**************************************/
pinMode(pwmpin, INPUT); // PWM-Pin auf Eingang setzen
/**************************************
* für den Betrieb des BMP-180 *
**************************************/
if (!pressure.begin()) {
delay(3000);
Serial.println("BMP-180 init failed!"); // while(true); // wartet, bis der Sensor sich meldet
}
Serial.print("Provided altitude: ");
Serial.print(ALTITUDE, 0);
Serial.println(" meters");
}
/*********************************************************************************************************
*
* H A U P T P R O G R A M M - Loop
*
*********************************************************************************************************/
void loop() {
DatenAuslesen();
DatenStringErstellen();
DatenSichern();
DatenAnzeigen();
SerialAusgabe();
delay(5000);
}
/********************************************************************************************************
*
* Prozedur Datenauslesen
*
*********************************************************************************************************/
void DatenAuslesen(){
LaufZeit = millis() - StartZeit;
ppm_pwm = readCO2PWM(); // Messung der PWM-Länge mittels einer eigenen Funktion
DruckUndTemperaturMessung();
}
/********************************************************************************************************
*
* Prozedur String mit allen Informationen Zusammenstellen
*
*********************************************************************************************************/
void DatenStringErstellen(){
// make a string for assembling the data to log:
dataString = "";
dataString += String(LaufZeit/1000,0);
dataString += String(";s;");
dataString += String(ppm_pwm);
dataString += String(";ppm;");
dataString += String(T,1);
dataString += String("; C;");
dataString += String(p0);
dataString += String(";hPa;");
dataString += String(P);
dataString += String(";hPa");
}
/********************************************************************************************************
*
* Prozedur Daten auf der SD-Karte Sichern
*
*********************************************************************************************************/
void DatenSichern(){ // open the file. note that only one file can be open at a time,
File dataFile = SD.open("nwp-9-1.csv", FILE_WRITE); // so you have to close this one before opening another.
if (dataFile) { // if the file is available, write to it:
dataFile.println(dataString);
dataFile.close();
//Serial.println(dataString); // print to the serial port too:
SchreibZugriff = true;
}
else { // if the file isn't open, pop up an error:
Serial.println("error opening nwp-9-1.csv");
SchreibZugriff = false;
}
}
/********************************************************************************************************
*
* Prozedur Daten auf dem OLED anzeigen
*
*********************************************************************************************************/
void DatenAnzeigen(){
oled.setFont(System5x7); // Auswahl der Schriftart
oled.clear(); // Loeschen der aktuellen Displayanzeige
oled.print("CO2: ");
oled.print(ppm_pwm);
oled.println(" ppm");
oled.println("-------------------");
oled.print("Temp. ");
oled.print(T,1);
oled.println(" C");
oled.println("-------------------");
oled.print("Druck ");
oled.print(p0,0);
oled.println(" hPa");
oled.println("-------------------");
oled.print("Zeit ");
oled.print(LaufZeit/1000,0);
oled.println(" s");
oled.print("SD ");
if (SchreibZugriff == true){
oled.print("ok ");
}
else {
oled.print("no ");
}
oled.println("MB-2025-06-13");
}
/********************************************************************************************************
*
* Ausgabe am seriellen Monitor
*
*********************************************************************************************************/
void SerialAusgabe(){
Serial.print(LaufZeit/1000,0);
Serial.print(" s | ");
Serial.print(ppm_pwm);
Serial.print(" ppm | ");
Serial.print(T,1);
Serial.print(" C | ");
Serial.print(p0);
Serial.print(" hPa | ");
Serial.print(P);
Serial.print(" hPa Luftdruck gemessen in Borgfelde 6 m ueber NN");
if (SchreibZugriff == true) {
Serial.print(" SD ok");
}
else {
Serial.print(" SD fehlerhaft");
}
Serial.println();
}
/********************************************************************************************************
*
* 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.
}
/********************************************************************************************************
*
* Prozedur zum Auslese des BMP-180 (Druck- und Temperatursensor)
*
********************************************************************************************************/
void DruckUndTemperaturMessung(){
char status;
status = pressure.startTemperature();
if (status != 0) {
delay(status);
status = pressure.getTemperature(T);
if (status != 0) {
status = pressure.startPressure(3);
if (status != 0) {
delay(status);
status = pressure.getPressure(P, T);
if (status != 0) {
p0 = pressure.sealevel(P, ALTITUDE);
}
}
}
}
}
===== 5. Nano mit Sensoren, OLED-Display und SD-Karten-Speicher im 3D-Druck-Gehäuse mit Steckverbindungen =====
==== Material ====
* Mikrocontroler ARDUINO NANO (oder UNO) ([[https://www.berrybase.de/kompatibler-arduino-uno-mit-atmel-mega-328p-prozessor?utm_source=google&utm_medium=cpc&gad_source=1&gad_campaignid=21582945112&gclid=Cj0KCQjwjJrCBhCXARIsAI5x66WoZonZllkIIUrHZWs-EI6MgMJrqfKx18rFMD6vKDiGpvgeduENqgwaAhVtEALw_wcB|5 bis 20 EURO]])
* Co2-Sensor [[https://www.winsen-sensor.com/d/files/MH-Z19B.pdf|MHZ 19B (10 bis 40 Euro]] - [[https://www.blikk.it/forum/blog.php?bn=neuemedien_fb&lang=de&id=1575901160|Funktionsweise MHZ-19]]
* Lufttemperatur und Luftdruck
* BMP180 (1 bis 4 EURO)
* OLED zur Datenanzeige
* SD-Kartenspeicher
* Laptop (zum Programmieren)
* Steckverbindungen/Platine/direkt gelötet
* 3D-Druck (eigener Drucker oder im Makerspace in der Nähe oder ...)
* 22 bis 48 EURO (Asien/Europa)
* Powerbank (optional)
{{:www-fuer-alle:arduino:2023-10-26-nw-co2-handmessgeraet.png?400 |}}
==== Steckplan ====
* Mit Taster
{{:www-fuer-alle:arduino:2023-10-17-co2-sd-bmp180-oled.png?400 |}}
==== Code ====
* mit Taster
* Co2-Messung über PWM-Kommunikation mit dem Sensor
/**************************************************
*
* SD-Karte, CO2-Sensor, BMP 180 und OLED 2023-10-17
*
***************************************************/
#include // OLED
#include "SSD1306Ascii.h" // OLED
#include "SSD1306AsciiWire.h" // OLED
#define I2C_ADDRESS 0x3C // OLED
SSD1306AsciiWire oled; // OLED
/* SD card datalogger
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)
by Tom Igoe
*/
#include // SD-Karte
#include // SD-Karte In diesem Sketch verwenden wir die library
#define ALTITUDE 8.0 // BMP 180 Borgfelde liegt 8 m ueber dem Meer
#include // BMP 180
#include // BMP 180
SFE_BMP180 pressure; // BMP 180 - Creating an object pressure
const int Taster = 2; // Der Taster zur OLED-Steuerung wurde an Pin 2 angeschlossen
const int chipSelect = 4; // CS-Pin der SD-Karte
bool SchreibZugriff = false; // Funktionsfaehigkeit beim Datensichern
bool Oledan = true; // Status der OLED-Anzeige
bool AnzeigenWechsel = false; // Wurde die Anzeige umgeschaltet
float StartZeit, LaufZeit; // Zeitpunkt der Messung
String dataString = ""; // Ausgabestring
int LeerZeile = 0;
volatile int TasterStatus = 0; // Variable die den Status des Taster ausliest, wird der sog. "Vektor" 0 zugewiesen
// Taster Anschluss an Pin 2 entspricht dem Vektor 0 (hier der Fall)
// Taster Anschluss an Pin 3 entspricht dem Vektor 1
/**************************************
* 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;
/**************************************
* für den Betrieb des BMP 180 *
**************************************/
double T, P, p0; //Creating variables for temp, pressure and relative pressure
/**************************************
* Festlegung Messintervall *
**************************************/
const int SchreibPause = 29998; // nächste Messung erst nach ca. 30 Sekunden
int WarteZeit;
void setup() {
StartZeit = millis();
pinMode(Taster, INPUT); // Hier wird der Taster als INPUT definiert
attachInterrupt(0, TasterUnterbricht, FALLING); // Hier findet die Einbindung unseres Interrupt-Befehls statt
/**************************************
* für den Betrieb des OLEDs *
**************************************/
Wire.begin();
Wire.setClock(400000L);
oled.begin(&Adafruit128x64, I2C_ADDRESS);
oled.setFont(System5x7); // Auswahl der Schriftart
oled.clear(); // Loeschen der aktuellen Displayanzeige
oled.println(" NW-Projekt 2023 ");
delay(1000);
/**************************************
* für den Betrieb der Ausgaben *
**************************************/
Serial.begin(9600); // Open serial communications and wait for port to open:
Serial.print("Initializing SD card...");
if (!SD.begin(chipSelect)) { // see if the card is present and can be initialized:
Serial.println("Card failed, or not present"); // don't do anything more:
SchreibZugriff = false;
oled.setFont(System5x7); // Auswahl der Schriftart
for (int i=20; i > 0; i--){
oled.clear(); // Loeschen der aktuellen Displayanzeige
oled.println(" NW-Projekt 2023 ");
oled.println(" ---------------------- ");
oled.println(" ");
oled.println(" KEINE SD-Karte ");
oled.println(" ");
oled.println(" GEFUNDEN!! ");
oled.println(" ");
oled.println(i);
delay(1000);
}
}
else {
Serial.println("card initialized."); // alles ok
SchreibZugriff = true;
}
/**************************************
* für den Betrieb des MH-Z19B *
**************************************/
pinMode(pwmpin, INPUT); // PWM-Pin auf Eingang setzen
/**************************************
* für den Betrieb des BMP-180 *
**************************************/
if (!pressure.begin()) {
Serial.println("BMP-180 init failed!");
//while(true);
}
Serial.print("Provided altitude: ");
Serial.print(ALTITUDE, 0);
Serial.println(" meters");
}
/**********************************************************************************************************
*
* H A U P T P R O G R A M M - Loop
*
***********************************************************************************************************/
void loop() {
// Messen
DatenAuslesen();
DatenStringErstellen();
DatenSichern();
if (Oledan == 0)
{DatenAnzeigenAus();}
else
{DatenAnzeigen();}
SerialAusgabe();
WarteZeit =0;
while (WarteZeit