Sensor reading showing randomly

I'm currently using some sensors and one of them seems like showing values but randomly, there is no continuity, and only after i unplug rx/tx of it and plug it back to arduino mega. This is the code:

#include <math.h>
#include <Arduino.h>
#include "PMS.h"
#include "SparkFun_SGP30_Arduino_Library.h" // Click here to get the library: http://librarymanager/All#SparkFun_SGP30
#include <Wire.h>
 
SGP30 mySensor; //create an object of the SGP30 class
// Define the serial port for MH-Z19B sensor (Serial2 on Arduino Mega)
#define MHZ19B_SERIAL Serial2

// Define the serial port for Bluetooth (Serial3 on Arduino Mega)
#define BLUETOOTH_SERIAL Serial3

// Define the baud rate for MH-Z19B sensor
#define MHZ19B_BAUDRATE 9600



// Define the command to read CO2 concentration
uint8_t MHZ19B_CMD_READ_CO2[] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};

PMS pms(Serial1);
PMS::DATA data;


enum channel {
  CH_NH3, CH_RED, CH_OX
};
typedef enum channel channel_t;

// Enum for proper gas declaration
enum gas {
  CO, NO2, NH3, C3H8, C4H10, CH4, H2, C2H5OH
};
typedef enum gas gas_t;

#define NH3PIN A1
#define COPIN A0
#define OXPIN A2

uint16_t NH3baseR;
uint16_t REDbaseR;
uint16_t OXbaseR;

/**
   Requests the current resistance for a given channel
   from the sensor. The value is an ADC value between
   0 and 1024.

   @param channel
          The channel to read the base resistance from.
   @return The unsigned 16-bit base resistance
           of the selected channel.
*/

uint16_t getResistance(channel_t channel) {
      unsigned long rs = 0;
      int counter = 0;

  switch (channel) {
    case CH_NH3:
      for(int i = 0; i < 100; i++) {
        rs += analogRead(NH3PIN);
        counter++;
        delay(2);
      }
      return rs/counter;
    case CH_RED:
      for(int i = 0; i < 100; i++) {
        rs += analogRead(COPIN);
        counter++;
        delay(2);
      }
      return rs/counter;
    case CH_OX:      
      for(int i = 0; i < 100; i++) {
        rs += analogRead(OXPIN);
        counter++;
        delay(2);
      }
      return rs/counter;

  }

  return 0;
}

void calibrateMICS() {
  // Continuously measure the resistance,
  // storing the last N measurements in a circular buffer.
  // Calculate the floating average of the last seconds.
  // If the current measurement is close to the average stop.

  // Seconds to keep stable for successful calibration
  // (Keeps smaller than 64 to prevent overflows)
  uint8_t seconds = 10;
  // Allowed delta for the average from the current value
  uint8_t delta = 2;

  // Circular buffer for the measurements
  uint16_t bufferNH3[seconds];
  uint16_t bufferRED[seconds];
  uint16_t bufferOX[seconds];
  // Pointers for the next element in the buffer
  uint8_t pntrNH3 = 0;
  uint8_t pntrRED = 0;
  uint8_t pntrOX = 0;
  // Current floating sum in the buffer
  uint16_t fltSumNH3 = 0;
  uint16_t fltSumRED = 0;
  uint16_t fltSumOX = 0;

  // Current measurements;
  uint16_t curNH3;
  uint16_t curRED;
  uint16_t curOX;

  // Flag to see if the channels are stable
  bool NH3stable = false;
  bool REDstable = false;
  bool OXstable = false;

  // Initialize buffer
  for (int i = 0; i < seconds; ++i) {
    bufferNH3[i] = 0;
    bufferRED[i] = 0;
    bufferOX[i] = 0;
  }

  do {
    // Wait a second
    delay(1000);
    Serial.print(".");
    // Read new resistances
    unsigned long rs = 0;
    delay(50);
    for (int i = 0; i < 3; i++) {
    delay(1);
    rs += analogRead(NH3PIN);
    }
    curNH3 = rs/3;
    rs = 0;
    delay(50);
    for (int i = 0; i < 3; i++) {
    delay(1);
    rs += analogRead(COPIN);
    }
    curRED = rs/3;
    rs = 0;
    delay(50);
    for (int i = 0; i < 3; i++) {
    delay(1);
    rs += analogRead(OXPIN);
    }
    curOX = rs/3;

    // Update floating sum by subtracting value
    // about to be overwritten and adding the new value.
    fltSumNH3 = fltSumNH3 + curNH3 - bufferNH3[pntrNH3];
    fltSumRED = fltSumRED + curRED - bufferRED[pntrRED];
    fltSumOX = fltSumOX + curOX - bufferOX[pntrOX];

    // Store new measurement in buffer
    bufferNH3[pntrNH3] = curNH3;
    bufferRED[pntrRED] = curRED;
    bufferOX[pntrOX] = curOX;

    // Determine new state of flags
    NH3stable = abs(fltSumNH3 / seconds - curNH3) < delta;
    REDstable = abs(fltSumRED / seconds - curRED) < delta;
    OXstable = abs(fltSumOX / seconds - curOX) < delta;

    // Advance buffer pointer
    pntrNH3 = (pntrNH3 + 1) % seconds ;
    pntrRED = (pntrRED + 1) % seconds;
    pntrOX = (pntrOX + 1) % seconds;

    //Mikä kestää?
    if(!NH3stable) {
      Serial.print("(NH3:");
      Serial.print(abs(fltSumNH3 / seconds - curNH3));
      Serial.println(")");
    }
    if(!REDstable) {
      Serial.print("(RED:");
      Serial.print(abs(fltSumRED / seconds - curRED));
      Serial.println(")");
    }
    if(!OXstable) {
      Serial.print("(OX:");
      Serial.print(abs(fltSumOX / seconds - curOX));
      Serial.println(")");
    }

  } while (!NH3stable || !REDstable || !OXstable);

  NH3baseR = fltSumNH3 / seconds;
  REDbaseR = fltSumRED / seconds;
  OXbaseR = fltSumOX / seconds;

  // Store new base resistance values in EEPROM
}

uint16_t getBaseResistance(channel_t channel) {
  /* if (1 == __version) {
     // Version 1 can query every channel independently
     // Reply is 4 bytes long with relevant data in second and third byte
     switch (channel) {
       case CH_NH3:
         return getRuntimeData(CMD_V1_GET_R0_NH3, 4, 1);
       case CH_RED:
         return getRuntimeData(CMD_V1_GET_R0_RED, 4, 1);
       case CH_OX:
         return getRuntimeData(CMD_V1_GET_R0_OX, 4, 1);
     }
    }
    if (2 == __version) {
     // Version 2 uses the same command every time, but different offsets*/
     switch (channel) {
       case CH_NH3:
         return NH3baseR;
       case CH_RED:
         return REDbaseR;
       case CH_OX:
         return OXbaseR;
     }
  //  }
  
  return 0;
}


/**
   Calculates the current resistance ratio for the given channel.

   @param channel
          The channel to request resistance values from.
   @return The floating-point resistance ratio for the given channel.
*/
float getCurrentRatio(channel_t channel) {
  float baseResistance = (float) getBaseResistance(channel);
  float resistance = (float) getResistance(channel);

  return resistance / baseResistance * (1023.0 - baseResistance) / (1023.0 - resistance);
  

  return -1.0;
}

/**
   Measures the gas concentration in ppm for the specified gas.

   @param gas
          The gas to calculate the concentration for.
   @return The current concentration of the gas
           in parts per million (ppm).
*/
float measureMICS(gas_t gas) {
  float ratio;
  float c = 0;

  switch (gas) {
    case CO:
      ratio = getCurrentRatio(CH_RED);
      c = pow(ratio, -1.179) * 4.385;
      break;
    case NO2:
      ratio = getCurrentRatio(CH_OX);
      c = pow(ratio, 1.007) / 6.855;
      break;
    case NH3:
      ratio = getCurrentRatio(CH_NH3);
      c = pow(ratio, -1.67) / 1.47;
      break;
    case C3H8:
      ratio = getCurrentRatio(CH_NH3);
      c = pow(ratio, -2.518) * 570.164;
      break;
    case C4H10:
      ratio = getCurrentRatio(CH_NH3);
      c = pow(ratio, -2.138) * 398.107;
      break;
    case CH4:
      ratio = getCurrentRatio(CH_RED);
      c = pow(ratio, -4.363) * 630.957;
      break;
    case H2:
      ratio = getCurrentRatio(CH_RED);
      c = pow(ratio, -1.8) * 0.73;
      break;
    case C2H5OH:
      ratio = getCurrentRatio(CH_RED);
      c = pow(ratio, -1.552) * 1.622;
      break;
  }

  return isnan(c) ? -1 : c;
}




void setup() {
  // Initialize Serial Monitor for debugging
  BLUETOOTH_SERIAL.begin(9600);
  Serial.begin(9600);
  Serial1.begin(9600); // For PMS5003
  MHZ19B_SERIAL.begin(MHZ19B_BAUDRATE);
  
  // Wait for the sensor to warm up
  delay(2000);

  Serial.println("MICS-6814 Sensor Test v0.1");
  Serial.print("Calibrating Sensor");
  calibrateMICS();
  Serial.println("OK!");

  Wire.begin();
  //Initialize sensor
  if (mySensor.begin() == false) 
{
    Serial.println("No SGP30 Detected. Check connections.");
    while (1);
  }
  //Initializes sensor for air quality readings
  //measureAirQuality should be called in one second increments after a call to initAirQuality
  mySensor.initAirQuality();



}

void readPM() {
  const int timeOut = 2000;
  if (pms.readUntil(data, timeOut)) {
    Serial.print("PM 1.0 (ug/m3): ");
    Serial.println(data.PM_AE_UG_1_0);

    BLUETOOTH_SERIAL.print(data.PM_AE_UG_1_0);
    BLUETOOTH_SERIAL.print("ug/m3");
    BLUETOOTH_SERIAL.print(",");

    Serial.print("PM 2.5 (ug/m3): ");
    Serial.println(data.PM_AE_UG_2_5);

    BLUETOOTH_SERIAL.print(data.PM_AE_UG_2_5);
    BLUETOOTH_SERIAL.print("ug/m3");
    BLUETOOTH_SERIAL.print(",");

    Serial.print("PM 10.0 (ug/m3): ");
    Serial.println(data.PM_AE_UG_10_0);

    BLUETOOTH_SERIAL.print(data.PM_AE_UG_10_0);
    BLUETOOTH_SERIAL.print("ug/m3");
    BLUETOOTH_SERIAL.print(",");
  } else {
    Serial.println("Failed to read PM data");
  }
}



void readCO2() {
  // Send command to MH-Z19B sensor to read CO2 concentration
  MHZ19B_SERIAL.write(MHZ19B_CMD_READ_CO2, sizeof(MHZ19B_CMD_READ_CO2));
  
  // Read response from the sensor
  uint8_t response[9];
  MHZ19B_SERIAL.readBytes(response, 9);
  
  // Check if response is valid
  if (response[0] == 0xFF && response[1] == 0x86) {
    // Calculate CO2 concentration (high byte * 256 + low byte)
    int co2 = response[2] * 256 + response[3];
    
    // Print CO2 concentration to Serial Monitor
    Serial.print("CO2 Level: ");
    Serial.print(co2);
    Serial.println(" ppm");

    BLUETOOTH_SERIAL.print(co2);
    BLUETOOTH_SERIAL.print("ppm");
    BLUETOOTH_SERIAL.print(",");
  } else {
    // Print error if response is invalid
    Serial.println("Error: Invalid response from sensor");
  }
}

void readtvoc(){
  
  mySensor.measureAirQuality();
  Serial.print(mySensor.TVOC);
  Serial.println(" ppb");
  BLUETOOTH_SERIAL.print(mySensor.TVOC);
  BLUETOOTH_SERIAL.print(" ppb");
  BLUETOOTH_SERIAL.print(",");

}


void readmics(){

  Serial.print("NH3: ");
  Serial.print(getResistance(CH_NH3));
  Serial.print("/");
  Serial.print(getBaseResistance(CH_NH3));
  Serial.print(" = ");
  Serial.print(getCurrentRatio(CH_NH3));
  Serial.print(" => ");  
  Serial.print(measureMICS(NH3));
  Serial.println("ppm");
  BLUETOOTH_SERIAL.print(measureMICS(NH3));
  BLUETOOTH_SERIAL.print("ppm");
  BLUETOOTH_SERIAL.print(",");

  delay(50);

  Serial.print("CO: ");
  Serial.print(getResistance(CH_RED));
  Serial.print("/");
  Serial.print(getBaseResistance(CH_RED));
  Serial.print(" = ");
  Serial.print(getCurrentRatio(CH_RED));
  Serial.print(" => ");  
  Serial.print(measureMICS(CO));
  Serial.println("ppm");
  BLUETOOTH_SERIAL.print(measureMICS(CO));
  BLUETOOTH_SERIAL.print("ppm");
  BLUETOOTH_SERIAL.print(",");

  delay(50);

  Serial.print("NO2: ");
  Serial.print(getResistance(CH_OX));
  Serial.print("/");
  Serial.print(getBaseResistance(CH_OX));
  Serial.print(" = ");
  Serial.print(getCurrentRatio(CH_OX));
  Serial.print(" => ");  
  Serial.print(measureMICS(NO2));
  Serial.println("ppm");
  BLUETOOTH_SERIAL.print(measureMICS(NO2));
  BLUETOOTH_SERIAL.print("ppm");
  BLUETOOTH_SERIAL.print(";");
  

  delay(50);


  delay(1000);
}


void loop() {
  
  readPM();
  readCO2();
  readtvoc();
  readmics();
  delay(2000);
    
}

Sensors are powered externally using 9V@1A which goes through a dc-dc buck converter to 5V. Every sensor uses 5V. The arduino mega is as well powered like this. I have no idea what could have gone wrong.

5 posts were merged into an existing topic: Mh-z19b being weird