Recently, gadgets showing the level of CO
2 are popular, as well as articles telling how a CO
2 monitor can be turned into a sensor connected to a computer. I want to show the solution to the problem from the other side.
Unlike older CO
2 sensors, the MH-Z19 does not require a specific voltage or high power and can transmit data through the UART and PWM.

- Hd - zero calibration will start if LOW is applied to Hd for more than 7 seconds. Calibration is not necessary.
- SR - not used
- Tx - signal level - 3.3V
- Rx - also 3.3V (works with 5V, but I would not recommend)
- Vo - output voltage 3.3V, not more than 10mA
- PWM data is removed as follows: the cycle length is 1004 ms, the first 2 ms is always HIGH, the last is always LOW, and the “middle” is proportional to the CO2 concentration in the range of 0 - 5000ppm (and not 2000ppm as in the documentation).
C ppm = 5000 * (T high - 2ms) / (T high + T low - 4ms)
I note that PWM is a very capricious thing, requiring careful soldering and 3.3V.
- AOT - not used
- Gnd - land
- Vin - supply voltage 3.6 - 5.5V (the sensor works and gives the same values ​​when powered 3.3V, but the manufacturer strongly recommends sticking to the framework)
')
Not that I didn’t trust PWM, but it’s better to get the data in digital and with checksum. UART allows you to request the level of concentration of CO
2 and do two types of calibration. Let's leave the calibration to Garrus and consider the data request. To do this, at a speed of 9600 (8 bit, stop - 1, parity - none) you need to send the following nine bytes:
• 0xFF - the beginning of any command
• 0x01 - the first sensor (it is only one)
• 0x86 - team
• 0x00, 0x00, 0x00, 0x00, 0x00 - data
• 0x79 - checksum.
In response, something like this will come:
• 0xFF - the beginning of any response
• 0x86 - team
• 0x01, 0xC1 - the highest and the lowest value (256 * 0x01 + 0xC1 = 449)
• 0x3C, 0x04, 0x3C, 0xC1 - the documentation says that something like 0x47, 0x00, 0x00, 0x00 should come, but in fact it is not clear what.
• 0x7B - checksum.
The checksum is calculated as follows: 7 bytes of the response are taken (all except the first and last), added, inverted, increased by 1: 0x86 + 0x01 ... + 0xC1 = 0x85, 0x85 xor 0xFF = 0x7A, 0x7A + 1 = 0x7B.
According to the documentation, it takes about three minutes for the sensor to enter operating mode. The first time after switching on it will produce either 5000ppm or 400ppm. After a particularly hard soldering can come to life for several hours.
The sensor responds to a change in CO
2 concentration with a delay of about a minute. If you exceed the concentration of 5000ppm (for example, you breathed heavily for a minute), it will give out false data for some time, underestimating the level of CO
2 - I received even 80ppm.
This is not reflected in the documentation, but you should not request data on the UART more than once every 10 seconds, otherwise the sensor starts to produce something strange.
It's time for pictures. Connect the sensor to Arduino Uno via Software Serial, TX / RX in A0 / A1, power in 5V, ground in Gnd:

Borrowed sketch with checksum verification added#include <SoftwareSerial.h>; SoftwareSerial mySerial(A0, A1); // A0 - TX , A1 - RX byte cmd[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79}; unsigned char response[9]; void setup() { Serial.begin(9600); mySerial.begin(9600); } void loop() { mySerial.write(cmd, 9); memset(response, 0, 9); mySerial.readBytes(response, 9); int i; byte crc = 0; for (i = 1; i < 8; i++) crc+=response[i]; crc = 255 - crc; crc++; if ( !(response[0] == 0xFF && response[1] == 0x86 && response[8] == crc) ) { Serial.println("CRC error: " + String(crc) + " / "+ String(response[8])); } else { unsigned int responseHigh = (unsigned int) response[2]; unsigned int responseLow = (unsigned int) response[3]; unsigned int ppm = (256*responseHigh) + responseLow; Serial.println(ppm); } delay(10000); }
Each measurement comes with an interval of 10 seconds. Values ​​stopped jumping when I moved away from the sensor.

Now we will make the sensor mobile. This will require an OTG device and a
DroidTerm application.
There is a subtlety: to establish a connection - you need to restart the Arduino.

After making sure everything works, remove the Arduino, replacing it with FTDI FT232RL.

Power to the sensor should be served after the connection so that there are no problems with the connection.
To send binary data via a COM port, I use
RealTerm :

It may be worth adding power management via DTR so that you can restart the sensor.
Useful links:
Manual on the sensor MH-Z19Connection diagram and code for PWMComparison with another sensorAn article on GT about MH-Z19 and ESP8266I have only one sensor and I really do not like to disassemble what I once did, so I suggest choosing you.