Giter VIP home page Giter VIP logo

erriezmhz19b's Introduction

Licence MIT Language C/C++ Release tag Open issue PlatformIO CI

Erriez MH-Z19B/C CO2 sensor library for Arduino

This is a MH-Z19B / MH-Z19C CO2 sensor library for Arduino. It has been built from scratch to support hardware and software serial with a small footprint.

The MH-Z19 is a NDIR (Non-Dispersive Infrared) type gas sensor with built-in temperature compensation to measure CO2 concentration in air.

MHZ19B

Library features

  • Small code/memory footprint
  • Hardware and software serial interface at 9600 baud 8N1
  • Read CO2 concentration 400..5000 ppm +/-50ppm+3% minimum 5 seconds interval
  • Chip detection
  • Smart warming-up detection
  • Read firmware version
  • Set/get range 2000 or 5000 ppm
  • Set/get auto calibration (Automatic Baseline Correction 24h interval)
  • Manual 400ppm calibration command
  • CRC checks on communication protocol and timeout handling
  • Interface for sending undocumented commands

Pins

WARNING: The pins between MH-Z19B and MH-Z19C are different. See tables below:

//     __     _______
// +------------------+
// |                  |
// |   . . . . . . .  |
// |   1 2 3 4 5 6 7  |
// +------------------+
//
// MH-Z19B front connector:
//   Pin 1: Yellow  None
//   Pin 2: Green   UART (TXD) TTL Level Data Output  -> TO RXD
//   Pin 3: Blue    UART (RXD) TTL Level Data Input   -> TO TXD
//   Pin 4: Red     Positive Power Supply (Vin +5V)
//   Pin 5: Black   Negative Power Supply (GND)
//   Pin 6: White   None
//   Pin 7: Brown   Analog Output Vo (Not used)
//
// MH-Z19C front connector:
//   Pin 1: PWM
//   Pin 2: UART (TXD) TTL Level data output  -> TO RXD
//   Pin 3: UART (RXD) TTL Level data input   -> TO TXD
//   Pin 4: Positive Power Supply (Vin +5V)
//   Pin 5: Negative Power Supply (GND)
//   Pin 6: Analog Output Vo
//   Pin 7: HD (Hand-operated calibration)
//
// The following ESP8266 pins are reserved:
//    TX/RX:  Serial (in use)
//    A0:     Analog (cannot be used)
//    D0-RST: Wake (cannot be used)
//    D1/D2:  I2C (can be used when I2C not used)
//    D3:     Output data flash (corrupts MH-Z19B on boot)
//    D4:     Boot (in use by boot pin / LED)
//    D5..D8: SPI <- Can be used when SPI not used

Tested Hardware

The following targets are supported and tested:

  • AVR: UNO, MINI, Pro Mini 8/16 MHz, ATMega2560, Leonardo
  • ARM: DUE
  • ESP8266: Mini D1 & D2, NodeMCU
  • ESP32: Lolin D32

Examples

Documentation

CO2 Concentrations

The table below displays the human impact of CO2:

CO2 ppm Description
0..399 Incorrect values. Minimum value starts at 400ppm outdoor fresh air.
400..1000 Concentrations typical of occupied indoor spaces with good air exchange.
1000..2000 Complaints of drowsiness and poor air quality. Ventilation is required.
2000..5000 Headaches, sleepiness and stagnant, stale, stuffy air. Poor concentration, loss of attention, increased heart rate and slight nausea may also be present.
>5000 Higher values are extremely dangerous and cannot be measured by this sensor.

Usage

  • Operating voltage is between 4.5 and 5VDC, 150mA peak current (average < 60mA).
  • UART pins are compatible with processors running at 3.3V without level converters.
  • Keep sensor outside direct sunlight.

Calibration

The sensor requires an internal calibration regularly. Without it, the minimum value drifts away which is noticeable after a few weeks of operation. With my experiments, the minimum value was drifted to 800ppm after 3 months continues operation without a calibration.

There are two calibration options:

  1. Automatic calibration, performed every 24 hours (default).
  2. Manual calibration.

1. Automatic Calibration

Automatic calibration is recommended when the sensor cannot be moved outdoor with fresh air. This calibration method requires a regularly ventilated room at 400ppm, at least once in 1..3 weeks. Additionally, it requires continues power-up without interruptions, otherwise the calibration data will not be updated correctly.

Automatic calibration configuration:

  • Set auto calibration on: setAutoCalibration(true) (Default from manufacture).
  • Set auto calibration off: setAutoCalibration(false).

The status can be read with function getAutoCalibration().

Note:
For simplicity, this library uses the terminology Automatic Calibration which is identical to the ABC (Automatic Baseline Correction) logic on/off mentioned in the datasheet.

2. Manual ZERO Calibration (400ppm)

Procedure for manual calibration at 400ppm:

  • Turn automatic calibration off.
  • Power the sensor up outdoor in fresh air for at least 20 minutes. (Not in a forest or a farm which produces background CO2)
  • Call startZeroCalibration() once. This will send command 0x87 Zero Point Calibration, but is not a zero calibration as stated in the datasheet. There is no nitrogen needed as this calibration is performed at 400ppm.

Now the sensor is calibrated. Repeat the sequence more often for higher accuracy.

3. MH-Z19B only: Manual SPAN Calibration

The SPAN point calibration procedure is not implemented in this library as it requires special calibration equipment. This functionality is not available in MH-Z19C.

4. MH-Z19C only: Hand-operated calibration

Procedure according to the MH-Z19C datasheet:

  • Connect module’s HD pin to low level(0V), lasting for 7 seconds at least.
  • Before calibrating the zero point, please ensure that the sensor is stable for more than 20 minutes at 400ppm ambient environment.
  • The application is responsible to control the external MH-Z19C HD pin and is not available on the MH-Z19B.

MH-Z19B/C API

Initialization Software Serial

Use a Software Serial when no hardware serial is available. Sometimes a 3rd party library is required, for example for ESP32 targets by installing ESPSoftwareSerial. It must be installed into .arduino15/packages/esp32/hardware/esp32/<version>/libraries/EspSoftwareSerial, because the library contains a naming conflict with existing SoftwareSerial.h built-in libraries.

#include <ErriezMHZ19B.h>
#include <SoftwareSerial.h>

// Pin defines
#define MHZ19B_TX_PIN        4
#define MHZ19B_RX_PIN        5

// Create software serial object
SoftwareSerial mhzSerial(MHZ19B_TX_PIN, MHZ19B_RX_PIN);

// Create MHZ19B object with software serial
ErriezMHZ19B mhz19b(&mhzSerial);

Initialization Hardware Serial

Any hardware serial like Serial, Serial1, Serial2 etc can be used when supported by the CPU. Multiple hardware serial ports are only available on targets like ATMEGA2560, Leonardo and SAM DUE boards:

#include <ErriezMHZ19B.h>

// Create MHZ19B object with hardware serial
ErriezMHZ19B mhz19b(&Serial1);

General initialization

The optional items of the initialization sequence can be omitted.

void setup()
{
    // Initialize serial
    Serial.begin(115200);
    Serial.println(F("\nErriez MH-Z19B CO2 Sensor example"));

    // Initialize software serial at fixed baudrate
    mhzSerial.begin(9600);

    // Optional: Detect MH-Z19B sensor (check wiring / power)
    while ( !mhz19b.detect() ) {
        Serial.println(F("Detecting MH-Z19B sensor..."));
        delay(2000);
    };

    // Sensor requires 3 minutes warming-up after power-on
    while (mhz19b.isWarmingUp()) {
        Serial.println(F("Warming up..."));
        delay(2000);
    };
}

Read CO2 loop

Read CO2 with minimum interval asynchronous function isReady(). A good practice is to check error returns < 0.

void loop()
{
    int16_t result;

    // Minimum interval between CO2 reads
    if (mhz19b.isReady()) {
        // Read CO2 from sensor
        result = mhz19b.readCO2();

        // Print result
        if (result < 0) {
            // Print error code
            switch (result) {
                case MHZ19B_RESULT_ERR_CRC:
                    Serial.println(F("CRC error"));
                    break;
                case MHZ19B_RESULT_ERR_TIMEOUT:
                    Serial.println(F("RX timeout"));
                    break;
                default:
                    Serial.print(F("Error: "));
                    Serial.println(result);
                    break;
            }
        } else {
            // Print CO2 concentration in ppm
            Serial.print(result);
            Serial.println(F(" ppm"));
        }
    }
}

Print internal settings

All tests are performed with sensor version string "0443".

char firmwareVersion[5];

// Optional: Print firmware version
Serial.print(F("  Firmware: "));
mhz19b.getVersion(firmwareVersion, sizeof(firmwareVersion));
Serial.println(firmwareVersion);

// Optional: Set CO2 range 2000ppm or 5000ppm (default) once
// Serial.print(F("Set range..."));
// mhz19b.setRange2000ppm();
// mhz19b.setRange5000ppm();

// Optional: Print operating range
Serial.print(F("  Range: "));
Serial.print(mhz19b.getRange());
Serial.println(F("ppm"));

// Optional: Print Automatic Baseline Calibration status
Serial.print(F("  Auto calibrate: "));
Serial.println(mhz19b.getAutoCalibration() ? F("On") : F("Off"));

Set automatic calibration

Turn automatic calibration on or off once at startup:

// Optional: Set automatic calibration on (true) or off (false) once
mhz19b.setAutoCalibration(true);

Documented commands

The following commands are documented, used and tested by the library:

Command Description
0x79 Set auto calibration on/off
0x86 Read CO2 concentration
0x87 Calibration zero point at 400ppm (not 0 ppm)
0x88 Calibrate span point (NOT IMPLEMENTED)
0x99 Set detection range

Not documented commands (tested)

The following commands are not documented, are used and tested by the library:

Command Description
0x7D Get auto calibration status (NOT DOCUMENTED)
0x9B Get range detection (NOT DOCUMENTED)
0xA0 Get firmware version (NOT DOCUMENTED)

More information about undocumented commands: https://revspace.nl/MH-Z19B.

NOTE: Sending untested commands may damage the sensor permanently! Use at your own risk.

int16_t result;

result = mhz19b.sendCommand(MHZ19B_CMD_NOT_DOCUMENTED, 0x00, 0x00, 0x00, 0x00, 0x00);

// 9 Bytes response is located in mhz19b.rxBuffer[9]

Library configuration

Unfortunately, the sensor has no possibility to read warming-up status, so the library must wait at least 3 minutes after reset or power-on. To speedup the boot process, macro MHZ19B_SMART_WARMING_UP can be enabled in ErriezMHZ19B.h to enable smart warming-up when the MCU is reset and MH-Z19B powered > 3 minutes.

Response timing

The screenshot below displays the response timing of a synchronous readCO2() call which takes 22.1ms on an Arduino UNO:

  • 9.4ms: Transmit 9 Bytes at 9600 baud
  • 3.2ms: MH-Z19B to process command
  • 9.3ms: Return response 9 Bytes at 9600 baud
  • 183us: Arduino UNO to process response with Software Serial.

Logic Analyzer Screenshot MHZ19B UNO readCO2()

Library installation

Please refer to the Wiki page.

Other Arduino Libraries and Sketches from Erriez

Erriez Libraries and Sketches

MIT License

This project is published under MIT license with an additional end user agreement (next section).

End User Agreement 🇺🇦

End users shall accept the End User Agreement holding export restrictions to Russia to stop the WAR before using this project.

erriezmhz19b's People

Contributors

erriez avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

erriezmhz19b's Issues

MH-Z19C not working with Wemos D1 Mini

Board

Wemos D1 mini

Hardware setup

Wemos D1 Mini (clone) and MH-Z19C.

Version

latest master (checkout manually)

IDE Name

Arduino Ide

Description

When trying to use RX TX pins other than the default D6 D5, the code throws "Detecting MH-Z19B sensor..." even though the sensor is correctly connected to the set pins.

Testcase

  1. upload the board bellow and connect the green/blue wire to D6/D5. the library will correctly find the sensor.
  2. change the TX and RX pin, for example to D1/D2
  3. connect the wires to the different pins
  4. upload the code. the code will keep printing "Detecting MH-Z19B sensor..."

Sketch

#include <ErriezMHZ19B.h>
#define MHZ19B_TX_PIN D5
#define MHZ19B_RX_PIN D6

#include <SoftwareSerial.h>  // Use software serial
SoftwareSerial mhzSerial(MHZ19B_TX_PIN, MHZ19B_RX_PIN);

// Create MHZ19B object
ErriezMHZ19B mhz19b(&mhzSerial);
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  mhzSerial.begin(9600);
    while (!mhz19b.detect()) {
    Serial.println(F("Detecting MH-Z19B sensor..."));
    delay(1000);
  };
  Serial.println("found");
}

void loop() {}

Logs

N/A

Checks

  • I understand that this library is maintained by volunteers in spare time. Response time may vary.

Export restrictions.

Analog Voltage Output

Feature request

Read analog voltage output using pin Vo

Hardware setup

ESP32, Arduino Uno

Is your feature request related to a problem?

I have a project to ensure the output voltage from pin Vo is similar to the output PPM using the UART pin. But I don't have any reliable code to compare these two output.these two outputs

Describe the solution you'd like

In the library, could help me to add the reading of the voltage output from the Vo pin?

Additional context

No response

Checks

  • I understand that this library is maintained by volunteers in spare time. Response time may vary.

Export restrictions.

MH-Z19C also works on firebeetle

Board

dfrobot firebeetle esp32-e v1.0

Hardware setup

I have gotten it working using


#include <HardwareSerial.h>
HardwareSerial mhzSerial( 2 );
#define MHZ19B_TX_PIN        16
#define MHZ19B_RX_PIN        17

// Create MHZ19B object
ErriezMHZ19B mhz19b(&mhzSerial);

The firebeetle has 3 uart devices, but the first uses the same pins as the usb power port, the second is more complex to operate, so the third one is the simplest to use.

see
https://microcontrollerslab.com/esp32-uart-communication-pins-example/

Version

latest master (checkout manually)

IDE Name

arduino

Description

this is not a bug but a comment. Thank you for making this library, the libraries with pwm here and there I couldnt get to work.
I am using the winsen mh-z19C

If anything could be improved, you write that calibrating by hardware is undocumented.
For the mh-z19c is this not so, see

https://www.tinytronics.nl/shop/index.php?route=product/product/get_file&file=3109/MH-Z19C-DZ-terminal%20type%20CO2%20Manual(Ver1.21)-202103.pdf

Also the pins for the 19C are different.

In the section zero-calibration the hand-operated method is documented. Short out pin 1 for more than 7 second.
I have done so and that works fine.

Testcase

there's no problem, sorry

Sketch

no

Logs

n0

Checks

  • I understand that this library is maintained by volunteers in spare time. Response time may vary.

Export restrictions.

get temperature

Hi there,

it would be really awesome if you could implement sensor temperature readout, so it would be possible to get the current sensor temperature too.

Please see the following link as an example: https://www.blikk.it/forum/blog.php?bn=neuemedien_fb&lang=de&id=1575901160

Apparently, the temperature in degrees Celsius + 40 (to account for possible negative temperature numbers) is being transmitted in byte 5, so you only have to substract 40. Because return can only return a single value, the code from the page mentioned above uses variables and pointers:

void readSensor(int *ppm, int *temperature){
  byte cmd[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};
  byte response[9]; 
  co2Serial.write(cmd, 9);
  memset(response, 0, 9);
  while (co2Serial.available() == 0) {
    delay(1000);
  }
  co2Serial.readBytes(response, 9);
  (...)
  *ppm = 256 * (int)response[2] + response[3];
  *temperature = response[4] - 40;
}

Thank you!
hAcky

Why is the value only 400ppm?

Hello, I need help
I'm not sure why Co2 is only 400 ppm, but I've tried mouth-watering.
The value has changed, I'm not sure if my sensor is normal.
image

Thanks in advance for the answer

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.