User Rating: 4 / 5

Star ActiveStar ActiveStar ActiveStar ActiveStar Inactive

When trying to measure CO2-level in the air, the MH-Z14 sensor from Winsensor offers a set of modules that give output in digital and calibrated form...

The MH-Z14 is a rather advanced CO2-sensor that offers calibrated output in digital or analog form. The datasheet offers the most important data on the different approaches to read out the sensor. The sensor can be bought with 3 different ranges (2000, 5000 or 10000 PPM - with an accuracy or resp. 2,5 or 10 PPM). For this test, I'm using the 2000 PPM sensor module.

Because of the limited resolution of the analog ports (only 1023 values between 0 and 5 volts), the analog outputs of the sensor (0-2.4V) are not very useful.

The digital pins communicate via PWM or UART. Output (and input for UART) of these ports work on 3.3 Volts - this means you should change the ARef of your Arduino - or rescale your values.

For the first experiment, values are read from the PWM.

Using an Op-Amp and 2 resistors (200 MΩ and 100MΩ) values are amplified with a factor 1.5 (but capped to the 5V of the Arduino that the OpAmp gets as supply).

The datasheet learns us that the PWM values are calculated by multiplying the milliseconds of the low cycle of the block-wave with 2 (for the 2000 PPM version) and the full cycle takes 1004 milliseconds.

Using the following code, the PPM value (and some other statistical values) are outputted:

// set pin numbers:
const int sensorPin = 2;     // the number of the sensor pin

long laag = 0;
long hoog = 0;
long laagTijd = 0;
long hoogTijd = 0;

void setup() {
  // initialize the sensor pin as an input
  pinMode(sensorPin, INPUT);
  // Read starting value for millis... (just some value)
while(digitalRead(sensorPin) == LOW) {;}
  hoog = millis();

void loop(){
  // Check for high and low timing - low time * 2 = PPM
  while(digitalRead(sensorPin) == HIGH) {;}
  laag = millis();
  hoogTijd = laag - hoog;
  while(digitalRead(sensorPin) == LOW) {;}
  hoog = millis();
  laagTijd = hoog - laag;

  // Validity check high+low = 1004 (small margin or error allowed -> 998)  if(laagTijd + hoogTijd > 998)
    Serial.print("H: ");
    Serial.print("L: ");
    Serial.print("CO2  -  ");
    Serial.print(laagTijd * 2,DEC);
    Serial.println(" ppm");    
  } else {
    // Output in case of invalid check: value instead of 1004 ms
    Serial.print("-- CK:");
    Serial.println(laagTijd+hoogTijd, DEC);

Obviously, this code is prone to improvement (using pulseIn() for more accurate readings) ... but for now, it works well enough. Using error checking (adding low and high time), values with a possibly higher error margin are removed from the results.

Next step is to implement this nice piece of hardware into the sensor logging kit I'm working on.

Just for fun... a tiny video of the cool sensor with the flashing light:

Leave your comments

Post comment as a guest

0 / 4096 Character restriction
Your text should be in between 42-4096 characters
Your comments are subjected to administrator's moderation.
terms and condition.
Powered by Komento