0
\$\begingroup\$

What I want to achieve

Use a CO2 sensor module MH-Z19C to detect CO2 in the room using UART with Arduino Nano.

Issue

The sensor gave an unreasonable value 0 ppm. Generally speaking, CO2 in the air is at least around 400 ppm.

Environment

  • Windows 10
  • Arduino IDE 2.1.1
  • Arduino Nano

Schematic

enter image description here

Code

//
//    FILE: MHZCO2_sw_serial.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo
//    DATE: 2020-09-01
// https://github.com/RobTillaart/MHZCO2/blob/master/examples/MHZCO2_sw_serial/.arduino-ci.yml


#include "SoftwareSerial.h"
#include "MHZCO2.h"

const int RX = 3;
const int TX = 2;
SoftwareSerial ss(TX, RX);


MHZ19B MHZ19B;


void setup()
{
  Serial.begin(9600);
  Serial.println(__FILE__);

  MHZ19B.begin(&ss);
  ss.begin(9600);
}


void loop()
{
  MHZ19B.measure();

  Serial.println("------------------");
  Serial.print("CO2:  ");
  Serial.println(MHZ19B.getCO2());
  Serial.print("MCO2: ");
  Serial.println(MHZ19B.getMinCO2());
  Serial.print("Temp: ");
  Serial.println(MHZ19B.getTemperature());
  Serial.print("Accu: ");
  Serial.println(MHZ19B.getAccuracy());

  delay(1000);
}

Output on Serial Monitor

CO2: 0
MCO2: 0
Temp: 0
Accu: 0

What I tried so far

I searched "MH-Z19C not working" and found several pages but none of them seemed to be useful. I also looked into the datasheet but this didn't help me out.

https://akizukidenshi.com/download/ds/winsen/MH-Z19C_20210518.pdf

I made sure there was 5.0-5.02 volts between Vin and GND on MH-Z19C.

Any help would be appreciated. Thanks in advance.

\$\endgroup\$
0

2 Answers 2

3
\$\begingroup\$

I'm assuming you're using this SoftwareSerial library.

The constructor looks as follows:

SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false);

This line of code:

SoftwareSerial ss(TX, RX);

... should be changed to:

SoftwareSerial ss(RX, TX);

You also need to define the pin modes for TX and RX:

void setup()  {
    Serial.begin(9600);
    Serial.println(__FILE__);

    pinMode(RX, INPUT);
    pinMode(TX, OUTPUT);

    MHZ19B.begin(&ss);
    ss.begin(9600);
}

From the comments:

Somehow the output changed . Now they are CO2: -1, MCO2: -1, Temp: 215, Accu: 255,

The measure method calculates the separate values as follows:

_CO2         = data[2] * 256 + data[3];
_temperature = data[4] - 40;
_accuracy    = data[5];
_minCO2      = data[6] * 256 + data[7];

The values you've received indicates that every received data byte has the value 0xFF. So something definitively doesn't seem right.

Have you evaluated the result returned by the measure method?

MHZCO2.h lists following return values:

#define MHZCO2_OK                 0
#define MHZCO2_TIMEOUT            -10
#define MHZCO2_ERROR_CRC          -11

Next comment:

I didn't understand what you meant by "evaluated the result returned by the measure method." Could you explain?

When you analyze the MHZCO2 source code, you'll see that measure() returns an int value.

int MHZCO2::measure()
{
  _lastMeasurement = millis();

  uint8_t data[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  data[8] = checksum(data);
  send(data, 9);

  int rv = receive(data);
  //  allow partial good data?
  if ((rv == MHZCO2_OK) || (rv == MHZCO2_ERROR_CRC))
  {
    _CO2         = data[2] * 256 + data[3];
    _temperature = data[4] - 40;
    _accuracy    = data[5];
    _minCO2      = data[6] * 256 + data[7];
  }

  return rv;
}

The result will be one of the return values specified above. When you check this return value, you'll have an indication if something went wrong.

\$\endgroup\$
5
  • \$\begingroup\$ Thanks for the answer. The CO2 value is now 71. It's still a bit off. Do you have any suggestions? \$\endgroup\$
    – dixhom
    Commented Jul 13, 2023 at 11:26
  • \$\begingroup\$ Perhaps you have to calibrate the sensor? Are at least the other parameters plausible (min CO2, temperature, accuracy)? \$\endgroup\$
    – Velvet
    Commented Jul 13, 2023 at 11:46
  • \$\begingroup\$ Somehow the output changed . Now they are CO2: -1, MCO2: -1, Temp: 215, Accu: 255, \$\endgroup\$
    – dixhom
    Commented Jul 13, 2023 at 13:30
  • \$\begingroup\$ Hi, I didn't understand what you meant by "evaluated the result returned by the measure method." Could you explain? \$\endgroup\$
    – dixhom
    Commented Jul 14, 2023 at 22:50
  • \$\begingroup\$ Thanks. I executed measure() and got -10. It is MHZCO2_TIMEOUT. So the program didn't get into the if clause and the variable weren't updated. However, I have no idea why it timed out. Any suggestions? \$\endgroup\$
    – dixhom
    Commented Jul 17, 2023 at 0:47
1
\$\begingroup\$

With the help from @Velvel, I figured out the cause of the problem and solved it. The Arduino is now generating outputs like below.


CO2: 1163
MCO2: 0
Temp: 23
Accu: 0

There were four issues in my environment.

  1. The parameters of the function ss() were wrong

It should have been SoftwareSerial ss(TX, RX); instead of SoftwareSerial ss(RX, TX);.

  1. The pin modes should have been defined.

    void setup() { Serial.begin(9600); Serial.println(FILE);

     pinMode(RX, INPUT); // this line was added
     pinMode(TX, OUTPUT); // this line was added
    
     MHZ19B.begin(&ss);
     ss.begin(9600);
    

    }

  2. Some of the jumper wires had contact failure.

I tested the contact of all the wires and got rid of the defective ones.

  1. The power wasn't supplied to the sensor.

The power is supplied from the Arduino 5V pin to a DC-DC converter then to the sensor. However, The maximum current from the pin was 40mA while the maximum consumption in the sensor was 125mA. The converter stopped supplying the current and the sensor stopped sending signals to Arduino.

I brought 5V current from an AC100V-DC5V converter and the sensor started to generate CO2 signals.

There is still a concern. The return value of measure() is -11 which is MHZCO2_ERROR_CRC. It seems like an error but measure() in GitHub repo (https://github.com/RobTillaart/MHZCO2/blob/master/MHZCO2.cpp) says "// allow partial good data?" so it looks like the developer is already aware of this behavior.

\$\endgroup\$
2
  • \$\begingroup\$ Good to know you got it working. I don't like that measure() returns a CRC error, but I've seen several posts on the web about claims that the CRC isn't working properly. In your case at least the values for CO2 and Temp seem plausible. If I were you, I'd sanity check the data (CO2 and Temp should be in a specific range) before using them. \$\endgroup\$
    – Velvet
    Commented Jul 17, 2023 at 6:17
  • \$\begingroup\$ Thank you for your information @Velvel. The temperature was 23 degrees while the actual one was 28. The CO2 level 1163 ppm is quite typical in a closed room. So none of them was contradictory. \$\endgroup\$
    – dixhom
    Commented Jul 17, 2023 at 7:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.