Last active
May 24, 2021 13:07
-
-
Save haeshh/4418c31b0ca5756c84abf70ea0d9040f to your computer and use it in GitHub Desktop.
ESP32-Beispielprogramme zur CO2-Messung mit dem Sensor MH-Z19B per Pulsweitenmodulation (PWM) und serieller Schnittstelle (https://unsinnsbasis.de/co2-sensor-mhz19b/)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* CO2-Messung mit dem Sensor MH-Z19B | |
* per Pulsweitenmodulation (PWM) | |
* | |
* Anzeige der Messwerte als CO2-Ampel | |
* | |
* 2020-11-08 Heiko (unsinnsbasis.de) | |
*/ | |
// Definition der GPIO-Pins | |
// (für die LEDs beim Arduino jeweils einen freien Digitalpin Dx verwenden) | |
#define LED_GREEN 32 | |
#define LED_YELLOW 33 | |
#define LED_RED 25 | |
#define SENSOR_PIN 14 // beim Arduino z.B. D3 (oder 5, 6, 9, 10, 11) | |
// Bitrate für die Datenübertragung zum seriellen Monitor | |
// (ESP: z.B. 115200, Arduino: zwingend 9600) | |
#define BITRATE 115200 // Arduino: 9600 | |
// tatsächliche Dauer eines Messzyklus des MH-Z19B | |
// (wenn nicht bekannt, den Standardwert von 1004 ms verwenden) | |
#define INTERVALL 997 // Standard: 1004 | |
// Obergrenze des Messbereichs des Sensors | |
// (0-2000. 0-5000, 0-10000 ppm CO2) | |
#define RANGE 5000 | |
// Grenzen des "grünen" und "gelben" Bereichs | |
#define LIMIT_GREEN 1000 | |
#define LIMIT_YELLOW 2000 | |
void setup() { | |
// Sensor-Pin als Eingang verwenden | |
pinMode(SENSOR_PIN, INPUT); | |
// GPIO-Pins der LEDs sind Ausgänge | |
pinMode(LED_GREEN, OUTPUT); | |
pinMode(LED_YELLOW, OUTPUT); | |
pinMode(LED_RED, OUTPUT); | |
// Übertragungsrate zum seriellen Monitor setzen | |
Serial.begin(BITRATE); | |
// alle LEDs aus | |
digitalWrite(LED_GREEN, LOW); | |
digitalWrite(LED_YELLOW, LOW); | |
digitalWrite(LED_RED, LOW); | |
} | |
void loop() { | |
int ppm; | |
// Verwendung der einfachen Formel; allerdings wird - sofern | |
// bekannt - mit dem Wert von INTERVALL die tatsächliche | |
// Intervalllänge des Sensors berücksichtigt | |
ppm = (pulseIn(SENSOR_PIN, HIGH, 2200000UL) / 1000 - 2) * RANGE / (INTERVALL - 4); | |
// Ausgabe des CO2-Werts in ppm im seriellen Monitor | |
Serial.print("PPM CO2: "); | |
Serial.println(ppm); | |
// je nach Wert die passende LED an- und die anderen | |
// beiden ausschalten | |
if (ppm < LIMIT_GREEN) { | |
digitalWrite(LED_GREEN, HIGH); | |
digitalWrite(LED_YELLOW, LOW); | |
digitalWrite(LED_RED, LOW); | |
} else if (ppm < LIMIT_YELLOW) { | |
digitalWrite(LED_GREEN, LOW); | |
digitalWrite(LED_YELLOW, HIGH); | |
digitalWrite(LED_RED, LOW); | |
} else { | |
digitalWrite(LED_GREEN, LOW); | |
digitalWrite(LED_YELLOW, LOW); | |
digitalWrite(LED_RED, HIGH); | |
} | |
delay(2500); // vor der nächsten Messung etwas warten | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Abfrage von Sensoren und Anzeige auf OLED | |
* - MH-Z19B: CO2 und Temperatur | |
* - DS18B20: Temperatur | |
* | |
* Die OLED-Anzeige ändert sich alle 5 Sekunden: | |
* - CO2-Wert: Abfrage des MH-Z19B seriell und per PWM | |
* - Temperatur: Messwerte beider Sensoren | |
* | |
* 2021-01-14 Heiko (unsinnsbasis.de) | |
*/ | |
/* ------------------------------------------------------------ | |
* Einbinden der benötigten Bibliotheken, | |
* Defintion der GPIO-Pins und anderer Konstanten, | |
* Anlegen der Datenobjekte | |
* ------------------------------------------------------------ */ | |
// Übertragungsrate für Ausgabe zum seriellen Monitor | |
#define SERIAL_BAUDRATE 115200 // Arduino: 9600, ESP32: z.B. 115200 | |
/* ------------------------------------------------------------ | |
* DS18B20 | |
* ------------------------------------------------------------ */ | |
#include <OneWire.h> | |
#include <DallasTemperature.h> | |
#define DS18B20_PIN 18 // GPIO-Pin für Daten des DS18B20 | |
// OneWire-Objekt erstellen ... | |
OneWire ow(DS18B20_PIN); | |
// ... und einen Zeiger darauf an ein Sensor-Objekt übergeben | |
DallasTemperature ds18b20(&ow); | |
DeviceAddress ds18b20_id; // ID des DS18B20 (Adresse) | |
/* ------------------------------------------------------------ | |
* MH-Z19B | |
* ------------------------------------------------------------ */ | |
#include <Arduino.h> | |
#include <MHZ19.h> | |
// Nutzung der Schnittstelle UART2 an den Default-Pins RX 16, TX 17 | |
#define RX2 16 | |
#define TX2 17 | |
#define MHZ19_BAUDRATE 9600 | |
#define MHZ19_PROTOCOL SERIAL_8N1 | |
#define MHZ19_RANGE 5000 // Obergrenze des Messbereichs des Sensors | |
#define MHZ19_PWM_PIN 5 | |
MHZ19 mhz19b; // Sensor-Objekt | |
/* ------------------------------------------------------------ | |
* SSD1306-OLED-Display (I2C) | |
* ------------------------------------------------------------ */ | |
// Bibliothek bindet auch <Adafruit_GFX.h>, <SPI.h>, <Wire.h> ein | |
#include <Adafruit_SSD1306.h> | |
// I2C-Adresse des Displays (0x3C oder 0x3D) | |
#define DISPLAY_I2C_ADDRESS 0x3C | |
// Auflösung des SSD1306-OLED-Displays | |
#define DISPLAY_WIDTH 128 // Breite in Pixeln | |
#define DISPLAY_HEIGHT 64 // Höhe in Pixeln | |
// Datenobjekt für das Display | |
// - Verbindung per I2C (Standard-Pins SCL, SDA) | |
// - Display hat keinen Reset-Pin | |
Adafruit_SSD1306 display(DISPLAY_WIDTH, DISPLAY_HEIGHT, &Wire, -1); | |
/* Timer für die Ausgabe: | |
* - alle 10 Sekunden die Temperatur des CO2-Sensors und | |
* des DS18B20 anzeigen | |
* -> immer wenn die Sekundenzahl auf 0 endet | |
* - 5 Sekunden später die CO2-Werte (seriell und PWM) anzeigen | |
* -> immer wenn die Sekundenzahl auf 5 endet | |
*/ | |
unsigned long timer_output_0 = 0, timer_output_5 = 5000; | |
// CO2-Werte bei serieller und PWM-Messung | |
int co2_ser, co2_pwm; | |
float temp_ds; //Temperatur des DS18B20 | |
int temp_mh; //Temperatur des MH-Z19B | |
/* ------------------------------------------------------------ */ | |
void setup(){ | |
int i; | |
bool error = false; | |
char mhz19_version[4]; | |
Serial.begin(SERIAL_BAUDRATE); | |
delay(500); // kurz warten, bis die ser. Schnittstelle bereit ist | |
Serial.println("\n\n"); // Abstand zur vorigen Ausgabe | |
// Display initialisieren | |
// im Fehlerfall Meldung ausgeben | |
if(!display.begin(SSD1306_SWITCHCAPVCC, DISPLAY_I2C_ADDRESS)) { | |
Serial.println("SSD1306 nicht gefunden"); | |
error = true; | |
} else { | |
display.clearDisplay(); // Display löschen | |
display.display(); | |
} | |
// Sensoren initialisieren | |
// ROM-Adresse (ID) des DS18B20 ermitteln und anzeigen | |
if (!ow.search(ds18b20_id)) { | |
Serial.println("Kein DS18B20-Sensor gefunden"); | |
error = true; | |
} else { | |
Serial.print("DS18B20 ID (Sensor-Adresse):"); | |
// Adress-Bytes als Hexadezimalwerte ausgeben | |
for (i = 0; i < sizeof(DeviceAddress); i++) { | |
Serial.print(' '); | |
Serial.print(ds18b20_id[i], HEX); | |
} | |
Serial.print(' '); | |
} | |
Serial.println(); | |
Serial2.begin(MHZ19_BAUDRATE, MHZ19_PROTOCOL, RX2, TX2); | |
mhz19b.begin(Serial2); // MH-Z19B-Sensor eine Schnittstelle zuweisen | |
// ein paar Daten der Sensor-Konfiguration ausgeben | |
mhz19b.getVersion(mhz19_version); | |
Serial.print("--------------------\nMH-Z19B Firmware Version: "); | |
for(i = 0; i < 4; i++) { | |
Serial.print(mhz19_version[i]); | |
if(i == 1) | |
Serial.print("."); | |
} | |
Serial.print("\nMH-Z19B Messbereich: "); | |
Serial.println(mhz19b.getRange()); | |
Serial.print("MH-Z19B Autokalibrierung (ABC): "); | |
mhz19b.getABC() ? Serial.println("AN") : Serial.println("AUS"); | |
Serial.println("--------------------"); | |
// im Fehlerfall Programm nicht fortsetzen (leere Dauerschleife)) | |
if(error) { | |
for(;;); | |
} | |
} | |
/* ------------------------------------------------------------ */ | |
void loop(){ | |
// Timer und Intervalllängen für die PWM-Messung des CO2-Werts | |
unsigned long pulse_high, pulse_high_2, time_start, timer; | |
timer = millis(); | |
if ((timer / 1000) % 10 == 0 && timer > timer_output_0) { | |
timer_output_0 += 10000; // nächste Anzeige in 10 Sekunden | |
ds18b20.requestTemperatures(); // DS18B20-Abfrage starten | |
temp_ds = ds18b20.getTempC(ds18b20_id); | |
temp_mh = mhz19b.getTemperature(); | |
display.clearDisplay(); | |
display.setTextColor(WHITE); // helle Schrift, dunkler Grund | |
display.setTextSize(2); // doppelt hohe Schrift | |
display.setCursor(0, 0); | |
display.print("Temperatur"); | |
display.setCursor(12, 20); | |
display.print("MH: "); | |
display.print(temp_mh); | |
display.setCursor(12, 48); | |
display.print("DS: "); | |
display.print(temp_ds, 1); | |
display.display(); | |
// im Anschluss die PWM-Messung durchführen (dauert bis zu | |
// zwei Sekunden), um die anschließende Ausgabe nicht | |
// zu verzögern; | |
// mit der vollständigen Formel und der | |
// tatsächlich gemessenen Intervalllänge arbeiten. | |
// Länge des HIGH-Pegels ermitteln | |
pulse_high = pulseIn(MHZ19_PWM_PIN, HIGH, 2200000UL) / 1000; | |
time_start = millis(); // jetzt beginnt der LOW-Pegel | |
// ... dann die Länge des folgenden HIGH-Pegels messen | |
pulse_high_2 = pulseIn(MHZ19_PWM_PIN, HIGH, 1100000UL) / 1000; | |
// die Dauer des LOW-Pegels ist die Zeit seit Beginn der | |
// Messung minus die Dauer des zweiten HIGH-Pegels; | |
// statt die Dauer des LOW-Pegels | |
// millis() - time_start - pulse_high_2 | |
// in einer Variablen zwischenzuspeichern, wird der Wert | |
// direkt in die Formel eingesetzt | |
co2_pwm = (pulse_high - 2) * MHZ19_RANGE / (pulse_high + (millis() - time_start - pulse_high_2) - 4); | |
co2_ser = mhz19b.getCO2(); | |
} else if ((timer / 1000) % 10 == 5 && timer > timer_output_5) { | |
timer_output_5 += 10000; | |
display.clearDisplay(); | |
display.setTextColor(WHITE); | |
display.setTextSize(2); | |
display.setCursor(0, 0); | |
display.print("CO2 (ppm)"); | |
display.setCursor(0, 20); | |
display.print("ser.: "); | |
display.print(co2_ser); | |
display.setCursor(0, 48); | |
display.print("PWM: "); | |
display.print(co2_pwm); | |
display.display(); | |
} | |
delay(100); // kurz warten (1/10 Sekunde; kann entfallen) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* CO2-Messung mit dem Sensor MH-Z19B | |
* per Pulsweitenmodulation (PWM) | |
* | |
* 2020-11-08 Heiko (unsinnsbasis.de) | |
*/ | |
// Definition der GPIO-Pins | |
#define SENSOR_PIN 14 // beim Arduino z.B. D3 (oder 5, 6, 9, 10, 11) | |
// Bitrate für die Datenübertragung zum seriellen Monitor | |
// (ESP: z.B. 115200, Arduino: zwingend 9600) | |
#define BITRATE 115200 // Arduino: 9600 | |
// Obergrenze des Messbereichs (0-2000. 0-5000, 0-10000 ppm CO2) | |
#define RANGE 5000 | |
void setup() { | |
// Sensor-Pin als Eingang verwenden | |
pinMode(SENSOR_PIN, INPUT); | |
// Übertragungsrate zum seriellen Monitor setzen | |
Serial.begin(BITRATE); | |
} | |
void loop() { | |
int pulse_high, pulse_high_2, pulse_low; | |
unsigned long time_start; | |
// pulseIn() arbeitet mit Mikro- (nicht Milli-)Sekunden | |
// erst einmal Länge des HIGH-Pegels ermitteln ... | |
pulse_high = pulseIn(SENSOR_PIN, HIGH, 2200000UL) / 1000; | |
time_start = millis(); // jetzt beginnt der LOW-Pegel | |
// ... dann die Länge des folgenden HIGH-Pegels messen | |
pulse_high_2 = pulseIn(SENSOR_PIN, HIGH, 1100000UL) / 1000; | |
// die Dauer des LOW-Pegels ist die Zeit seit Beginn der | |
// Messung minus die Dauer des zweiten HIGH-Pegels; | |
pulse_low = millis() - time_start - pulse_high_2; | |
// Ausgabe im seriellen Monitor: | |
// - CO2-Wert nach einfacher Formel | |
// - Wert nach vollständiger Formel | |
// - Roh-Werte der Messung | |
Serial.print("PPM CO2: "); | |
Serial.print((pulse_high - 2) * RANGE / 1000); | |
Serial.print(" (einfach); "); | |
Serial.print((pulse_high - 2) * RANGE / (pulse_high + pulse_low -4)); | |
Serial.print(" (korrekt); "); | |
Serial.print("Rohwerte (HIGH, LOW): "); | |
Serial.print(pulse_high); | |
Serial.print(", "); | |
Serial.println(pulse_low); | |
delay(2500); // vor der nächsten Messung etwas warten | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment