MH-Z19B

A Winsen NDIR carbon dioxide sensor module that reports CO2 from 0 to 5000 ppm over UART, PWM or an analog voltage.

  • Supply voltage4.5 V to 5.5 V DC
  • CurrentUnder 60 mA average, 150 mA peak (at 5 V)
  • Range and accuracy0 to 2000 or 0 to 5000 ppm; ±(50 ppm + 3 % of reading)
  • Interface levelUART TTL at 3.3 V, compatible with 5 V
MH-Z19B, A Winsen NDIR carbon dioxide sensor module that reports CO2 from 0 to 5000 ppm over UART, PWM or an analog voltage.
In short

The MH-Z19B is Winsen's NDIR CO2 module: it measures 0 to 2000 or 0 to 5000 ppm with an accuracy of ±(50 ppm + 3 % of reading), runs from 4.5 V to 5.5 V and draws under 60 mA on average with 150 mA peaks (Winsen MH-Z19B manual v1.0, p. 4). Its UART runs at 9600 baud with 3.3 V levels that the manual calls 5 V compatible (pp. 4, 7), so TX and RX wire directly to an Uno, ESP32 or Pico. Allow a 3 minute preheat (p. 4).

The MH-Z19B measures carbon dioxide the way lab instruments do: an infrared lamp shines through a gold-plated chamber and a detector measures how much of the CO2 absorption band gets through. That makes it specific to CO2, unlike cheap metal-oxide 'air quality' sensors that react to many gases. It reports 0 to 2000 ppm or 0 to 5000 ppm, selectable by command, with ±(50 ppm + 3 % of reading) accuracy and temperature compensation (Winsen manual v1.0, p. 4).

It needs 4.5 V to 5.5 V because of the lamp, averaging under 60 mA with 150 mA peaks (p. 4). The outputs are all usable from 3.3 V boards: UART at 3.3 V TTL level (5 V compatible per the manual), a PWM signal with a 1004 ms cycle, and an analog voltage of 0.4 V to 2 V (pp. 4 to 6). Over UART, the host sends a 9-byte 0x86 command and the sensor answers with the concentration (p. 7).

Automatic baseline calibration (ABC) ships enabled (p. 8): the sensor periodically re-zeroes itself on the assumption that it regularly sees fresh air at about 400 ppm. That suits rooms aired out daily and drifts badly in a greenhouse or a sealed box, where you should turn ABC off and calibrate zero in fresh air. Winsen now lists the MH-Z19B as discontinued on its product page, but modules remain widely sold and the protocol is unchanged.

MH-Z19B pinout

tinkered.ai/components/mh-z19bMH-Z19BVinPowerGNDGroundTxUART TXRxUART RXPWMPWMVoADCHDZero calibration
PinFunctionType
VinVin4.5 V to 5.5 Vpower in
GNDGNDpower in
TxUART TX3.3 V TTLoutput
RxUART RX3.3 V TTL, 5 V compatibleinput
PWMPWMoutput
VoADC0.4 V to 2 Voutput
HDZero calibrationinput

How to wire the MH-Z19B

Pin by pin, for the board you have.

MH-Z19BArduino UnoNote
Vin5V
GNDGND
TxD2SoftwareSerial RX
RxD3SoftwareSerial TX
  • The lamp pulls up to 150 mA (manual, p. 4): run the Uno from USB or a good 5 V supply, not a 9 V battery through the regulator.
Design this circuit on an Arduino Uno

MH-Z19B code

Every example here compiles for its board.

Libraries: wifwaf/MH-Z19
// MH-Z19B on Arduino Uno: wiring and a free simulation at https://www.tinkered.ai/components/mh-z19b
// MH-Z19B on an Arduino Uno: Vin 5V, sensor Tx to D2, sensor Rx to D3, 9600 baud
#include <SoftwareSerial.h>
#include <MHZ19.h>

SoftwareSerial co2Serial(2, 3);  // RX (from sensor Tx), TX (to sensor Rx)

MHZ19 co2;
unsigned long warmupEnd;

void setup() {
  Serial.begin(115200);
  co2Serial.begin(9600);
  co2.begin(co2Serial);
  // Automatic baseline calibration (ABC) is on from the factory; leave it on if the
  // sensor sees fresh outdoor air (about 400 ppm) regularly, else call co2.autoCalibration(false).
  warmupEnd = millis() + 180000UL;  // 3 minute preheat
  Serial.println("MH-Z19B started, warming up for 3 minutes");
}

void loop() {
  int ppm = co2.getCO2();
  if (co2.errorCode != RESULT_OK) {
    Serial.print("No valid reply, error code ");
    Serial.println(co2.errorCode);
  } else {
    Serial.print("CO2: ");
    Serial.print(ppm);
    Serial.print(" ppm   Sensor temperature: ");
    Serial.print(co2.getTemperature(), 0);
    Serial.print(" C");
    if ((long)(millis() - warmupEnd) < 0) Serial.print("   (still warming up)");
    Serial.println();
  }
  delay(5000);
}
Compiled for arduino:avr:uno on 2026-10-30

Before you wire it

Do
  • Power it from 4.5 V to 5.5 V with at least 150 mA to spare for the lamp's peaks (manual, p. 4).
  • Cross the UART: sensor Tx to the board's RX, sensor Rx to the board's TX (p. 6).
  • Ignore readings for the first 3 minutes after power-up (p. 4).
  • Decide on ABC: leave it on in rooms that are aired daily; turn it off in greenhouses, fermentation chambers or sealed boxes and calibrate zero in outdoor air (pp. 7 to 8).
Don’t
  • Never run zero calibration (0x87 or HD low) anywhere but fresh outdoor-level air for at least 20 minutes: it sets the current reading as 400 ppm (p. 7).
  • Never power it from a 3.3 V pin; it needs at least 4.5 V.
  • Never block the gold chamber's vents or press on the optical body; the gas reaches the chamber through them.
  • The UART is request and reply: send 0xFF 0x01 0x86 0x00 0x00 0x00 0x00 0x00 0x79 and read 9 bytes; CO2 = byte2 × 256 + byte3 (manual, p. 7). The library does this and checks the checksum.
  • PWM output gives CO2 without a UART: with the 2000 ppm range, Cppm = 2000 × (TH - 2 ms) / (TH + TL - 4 ms) over a 1004 ms cycle (p. 6).
  • The analog Vo output spans 0.4 V to 2 V (p. 5), within any board's ADC range, but it is coarser than the UART value.
  • Add a 100 µF capacitor across Vin and GND close to the module if the lamp's 150 mA pulses disturb other parts.

Specifications

Supply voltage
4.5 V to 5.5 V DCWinsen MH-Z19B user's manual v1.0, p. 4
Current
Under 60 mA average, 150 mA peak (at 5 V)Winsen MH-Z19B user's manual v1.0, p. 4
Range and accuracy
0 to 2000 or 0 to 5000 ppm; ±(50 ppm + 3 % of reading)Winsen MH-Z19B user's manual v1.0, p. 4
Interface level
UART TTL at 3.3 V, compatible with 5 VWinsen MH-Z19B user's manual v1.0, p. 4
UART settings
9600 baud, 8 data bits, 1 stop bit, no parity; read command 0xFF 0x01 0x86 ... 0x79Winsen MH-Z19B user's manual v1.0, p. 7
Other outputs
PWM (1004 ms cycle), analog Vo 0.4 V to 2 VWinsen MH-Z19B user's manual v1.0, pp. 5 to 6
Preheat and response
3 min preheat; T90 under 120 sWinsen MH-Z19B user's manual v1.0, p. 4
Operating conditions
0 to 50 °C, 0 to 90 %RH non-condensing; 33 × 20 × 9 mm, 5 gWinsen MH-Z19B user's manual v1.0, p. 4
Calibration
ABC on by default; zero point is 400 ppm after 20 minutes in fresh air; HD low for over 7 s also zeroesWinsen MH-Z19B user's manual v1.0, pp. 5, 7 to 8

From the MH-Z19B user's manual v1.0, published by Zhengzhou Winsen Electronics.

Common mistakes

  1. Readings creep down to 400 ppm and stay there

    ABC is on from the factory (manual, p. 8) and assumes the sensor regularly sees fresh air at about 400 ppm. In a space that never gets fresh air, that baseline is wrong. Turn ABC off with autoCalibration(false) and calibrate zero outdoors.

  2. No reply on the UART

    Usually Tx and Rx are not crossed, or the baud rate is not 9600 8N1 (p. 7). Check that the module's Tx goes to the board's RX pin.

  3. Brownouts and resets

    The lamp draws 150 mA peaks (p. 4). A board powered from a weak source or long thin wires resets as it fires; power from USB or a solid 5 V rail.

  4. Trusting the first few minutes

    The sensor needs a 3 minute preheat (p. 4) and its response time is up to 120 s for 90 % of a step, so readings right after power-up or after breathing on it lag.

MH-Z19B questions

Is the MH-Z19B 3.3 V or 5 V?

Its supply is 4.5 V to 5.5 V, but its UART uses 3.3 V levels and the manual calls them 5 V compatible (Winsen manual v1.0, p. 4). So it runs from 5 V and talks directly to 3.3 V and 5 V boards.

How accurate is the MH-Z19B?

±(50 ppm + 3 % of reading) (p. 4): about ±80 ppm at 1000 ppm. Good enough to know when to open a window; calibration and ABC settings matter more than the spec.

MH-Z19B or SCD41?

Both are true CO2 sensors. The SCD41 is smaller, uses I2C, runs at 3.3 V and adds humidity and temperature; the MH-Z19B is larger and needs 5 V but is cheap and widely documented.

Should I turn automatic baseline calibration off?

Only if the sensor never sees fresh air. ABC is on from the factory (p. 8) and works in homes and offices aired daily. In a greenhouse or a closed box, turn it off and calibrate zero outdoors for 20 minutes (p. 7).

Which library should I use?

WifWaf's MH-Z19 (PlatformIO: wifwaf/MH-Z19). It sends the commands, checks checksums and exposes getCO2(), getTemperature(), autoCalibration() and calibrate().

Build something with the MH-Z19B

  • Classroom CO2 traffic light

    Green under 800 ppm, amber to 1200, red above: time to open a window.

    Build this
  • Wi-Fi CO2 logger

    Send CO2 readings to a dashboard every minute.

    Build this
  • Grow tent monitor

    Track CO2 in a sealed tent with ABC turned off.

    Build this
For AI assistants

This page as plain Markdown, for ChatGPT, Claude or your own agent. /components/mh-z19b.md

What will you build with it?