Why does UART only work after the pins are reversed then unreversed in my project?

I'm using a MHZ19B CO2 sensor with an ESP32 D1 Mini communicating over UART coded in the Arduino IDE to pull CO2 concentration and temperature from the sensor (I really only care about CO2 concentration). My code works, but it can't seem to initialize the sensor right on boot unless I swap the UART pins, then swap them back. To be specific, the following is what happens in sequence from what I can see in the output:

Load the code. Outputs random characters in a repeating loop (I think this is happening in the setup when it tries to initialize the sensor). Remove both of the UART pins, nothing changes in the output, maybe some different characters in the random repeating loop. Put UART pins back in reverse order (tx-tx and rx-rx), random characters stop and outputs CO2 being 0 (because it's not getting data from the sensor). Reinstall UART pins correctly, starts outputting what I think are correct CO2 values.

Why is this happening? Are there any good workarounds to prevent this issue? Code, output and links are below.

Ps. Sorry if this is not how I should have posted my code, it's my first time using code blocks.

CO2 sensor: MH-Z19B ndir CO2 sensor for indoor air quality monitoring--Winsen

Sensor library (my code is adapted from the basic usage example): GitHub - WifWaf/MH-Z19: For Arduino Boards (&ESP32). Additional Examples/Commands., Hardware/Software Serial

Microcontroller: Amazon.com: ACEIRMC D1 Mini NodeMCU ESP32 ESP-WROOM-32 WLAN WiFi Bluetooth IoT Development Board 5V Compatible for Arduino (3pcs) : Electronics

#include <Arduino.h>
    #include "MHZ19.h"

    #define RX_PIN 10                                          // Rx pin which the MHZ19 Tx pin is attached to
    #define TX_PIN 9                                          // Tx pin which the MHZ19 Rx pin is attached to
    #define BAUDRATE 9600                                      // Device to MH-Z19 Serial baudrate (should not be changed)

    MHZ19 myMHZ19;                                             // Constructor for library
    #if defined(ESP32)
    HardwareSerial mySerial(2);                                // On ESP32 we do not require the SoftwareSerial library, since we have 2 USARTS available
    #else
    #include <SoftwareSerial.h>                                //  Remove if using HardwareSerial or non-uno compatible device
    SoftwareSerial mySerial(RX_PIN, TX_PIN);                   // (Uno example) create device to MH-Z19 serial
    #endif

    unsigned long getDataTimer = 0;

    void setup()
    {
        Serial.begin(9600);                                     // Device to serial monitor feedback

        mySerial.begin(9600, SERIAL_8N1, RX_PIN, TX_PIN);                               // (Uno example) device to MH-Z19 serial start
        myMHZ19.begin(mySerial);                                // *Serial(Stream) reference must be passed to library begin().

        myMHZ19.autoCalibration();                              // Turn auto calibration ON (OFF autoCalibration(false))
    }

    void loop()
    {
        if (millis() - getDataTimer >= 2000)
        {
            int CO2;

            /* note: getCO2() default is command "CO2 Unlimited". This returns the correct CO2 reading even
            if below background CO2 levels or above range (useful to validate sensor). You can use the
            usual documented command with getCO2(false) */

            CO2 = myMHZ19.getCO2();                             // Request CO2 (as ppm)

            Serial.print("CO2 (ppm): ");
            Serial.println(CO2);

          
            getDataTimer = millis();
        }
    }




19:36:12.610 -> a@�tC cbP1�F��%5�
�BB]
 19:36:13.684 -> 
,�M���������,�u�1X�A���GA�R%�f@�܉%�����'#e��"V��L&02e=	 
��t'^������ʍ��dHa�*#�'z? b\u,Ŏ� �	�"�K�6u�&�*���Y�	 
!B/ı.i� (�	���@�CO2 (ppm): 0
19:36:26.273 -> CO2 (ppm): 0
19:36:28.776 -> CO2 (ppm): 0
19:36:31.284 -> CO2 (ppm): 0
19:36:33.804 -> CO2 (ppm): 0
19:36:36.311 -> CO2 (ppm): 0
19:36:38.352 -> CO2 (ppm): 624
19:36:40.374 -> CO2 (ppm): 629
19:36:42.410 -> CO2 (ppm): 630
19:36:44.488 -> CO2 (ppm): 631
19:36:46.520 -> CO2 (ppm): 633

Welcome to the Arduino forum. Since your device has been discontinued, where and when did you buy it? What are you using for 5 volt supply that can supply more than 150mA to the device?

just like all gas sensors

#include <Arduino.h>
#include "MHZ19.h"

#define RX_PIN 10                                          // Rx pin which the MHZ19 Tx pin is attached to
#define TX_PIN 9                                          // Tx pin which the MHZ19 Rx pin is attached to
#define BAUDRATE 9600                                      // Device to MH-Z19 Serial baudrate (should not be changed)

MHZ19 myMHZ19;                                             // Constructor for library
#if defined(ESP32)
HardwareSerial mySerial(2);                                // On ESP32 we do not require the SoftwareSerial library, since we have 2 USARTS available
#else
#include <SoftwareSerial.h>                                //  Remove if using HardwareSerial or non-uno compatible device
SoftwareSerial mySerial(RX_PIN, TX_PIN);                   // (Uno example) create device to MH-Z19 serial
#endif

unsigned long getDataTimer = 20000;// give 20 seconds to warm up sensor

void setup() {
  Serial.begin(115200);                                     // Device to serial monitor feedback
  mySerial.begin(BAUDRATE, SERIAL_8N1, RX_PIN, TX_PIN);                               // (Uno example) device to MH-Z19 serial start
  myMHZ19.begin(mySerial);                                // *Serial(Stream) reference must be passed to library begin().
  myMHZ19.autoCalibration();                              // Turn auto calibration ON (OFF autoCalibration(false))
}

void loop() {
  if (millis() - getDataTimer >= 2000)  {
    int CO2 = myMHZ19.getCO2();                             // Request CO2 (as ppm)
    Serial.print("CO2 (ppm): ");
    Serial.println(CO2);
    getDataTimer = millis();
  }
}

Thanks!

Gpio9 and 10 are connected to spi flash. I would generally avoid using them. You can use almost all "normal" Gpio pins for Serial on Esp32.

Where did you see that my sensor is discontinued? There's listings all over amazon for both the sensor and microcontroller, which is where I got both from. I've seen people say there are fakes out there but I found a wiki discussing the differences between a fake and real MHZ19B and mine seemed to be the real thing based on visible hardware features, although I haven't tested it with an Oscope to really prove it.

I've got a 5V 3A power adapter that's powering a TSL2561 (lux), a HTU21D (temp/hum) and the MHZ19B.

The board I was using may now be corrupt as I can't write to it with the exact same sketch and hardware setup. And a different board only connecting the MHZ19B (directly to the board and the sensor's own dedicated power 5V 3A power, with common ground) and running the same sketch won't get out of jibberish like before. This "swapping pins fix" nonsense has been repeatable over multiple sketches, multiple main boards, multiple hardware configs and multiple days. I don't know why it's suddenly not working but I'll have to test it later since I have to go to work. I'll get back to you when I can.

Thanks for your help.

HTU21D: Adafruit HTU21D-F Temperature & Humidity Sensor Breakout Board [STEMMA QT] : ID 1899 : Adafruit Industries, Unique & fun DIY electronics and kits

TSL2561: Adafruit TSL2561 Digital Luminosity/Lux/Light Sensor Breakout : ID 439 : Adafruit Industries, Unique & fun DIY electronics and kits
(I know this is discontinued but it works well)

Really? I've been making my circuit based on this pinout diagram. You can see that pins 9 and 10 are designated as UART1 pins, pointed to with some big blue arrows. Do you know why this would be designated as UART specific pins if any can be used?

Don't believe everything you find online...

You can use almost whatever pins for UART1, to make it simple pick any from 16 to 33
Or if you like your pinmap image, use UART2, it has working default pins 16 and 17

Right at the factory web site! That is why you are seeing so many for sale.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.