====== WWW CO2-Messungen BIO ======
* [[Weimar|2026-6]]
===== 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:nano-mhz-bmp-oled-sd-4.jpg?direct&200|}} {{:www-fuer-alle:arduino:nano-2024-basitikum-co2.jpg?200|}}
{{ :www-fuer-alle:arduino:co2-sd-bmp180-oled-2025-06-11.png?direct&600 |}}
===== Aufbau =====
{{:www-fuer-alle:arduino:2023-11-29-co2-basikikum-aufbau.jpg?200 |}}
{{:www-fuer-alle:deckel-co2-basilikum.png?400|}}
===== 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|}}
{{:www-fuer-alle:arduino:nano-mhz-bmp-oled-sd-4.jpg?direct&600|}}
==== 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 |}}
{{ :www-fuer-alle:arduino:nano-messbox-a-sd-oled-fest.png?direct&150|}}
{{ :www-fuer-alle:arduino:nano-messbox-a-sd-oled-fest-2d.png?direct&150|}}
==== 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
====== Copyright (C) 2025 Biebl/Sankt-Ansgar-Schule Hamburg ======
"ARDUINO im Unterricht" von Martin Biebl/Sankt-Ansgar-Schule Hamburg,
lizenziert unter CC BY-SA 4.0
(https://creativecommons.org/licenses/by-sa/4.0/)
Diese Programme sind freie Software: Sie können es unter den
Bedingungen der GNU General Public License, wie von der Free
Software Foundation veröffentlicht, weitergeben und/oder
modifizieren, entweder gemäß Version 3 der Lizenz oder (nach
Ihrer Wahl) jeder späteren Version.
Die Veröffentlichung dieser Programme erfolgt in der Hoffnung,
dass es Ihnen von Nutzen sein wird, aber OHNE JEDE GEWÄHRLEISTUNG,
sogar ohne die implizite Gewährleistung der MARKTFÄHIGKEIT oder
EIGNUNG FÜR EINEN BESTIMMTEN ZWECK. Details finden Sie in der
GNU General Public License.
Vollständiger Lizenztext: https://www.gnu.org/licenses/gpl-3.0.de.html