How do I understand TVOC values and get formaldehyde and other VOC values?

I am using this VOC CJMCU-1100 sensor:

This code works for my TVOC and TPH sensor, but how do I understand TVOC values and programme to identify formaldehyde and other VOC values it is measuring??

The code outputs the TVOC as an analogue value, where the value is of course higher with the more total volatile organic compounds detected. But I can't find any specifications which explain how to compare the values? I also can't work out how to programme the sensor to log the values of the individual gases it is reading. Does anyone know how to go about this? Would help my data credibility immensely! TIA!

Code for reading VOC:

/*********GET VOC ************/
 int a=analogRead(Aout);
  int b=digitalRead(Dout);
  Serial.print("   A0:");

Full code for my VOCxTPH sensor:

//********************Start of code for TPH sensor***********************

#include <Wire.h>
#include "RTClib.h"
#include <BME280I2C.h>
#include <SPI.h>
#include <SD.h>

BME280I2C bme; 

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

RTC_DS1307 rtc;

uint32_t delayMS;

const int chipSelect = 10;
const int pingPin = 7;

unsigned int rtcd;
unsigned int rtcm;
unsigned int rtcy;
unsigned int rtcs;
unsigned int rtcmin;
unsigned int rtchr;

//This sensor measures changes in VOC gas levels//

#define Aout A0
#define Dout 2

void setup() {


  // Open serial communications and wait for port to open:


 if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
  // following line sets the RTC to the date & time this sketch was compiled
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  // This line sets the RTC with an explicit date & time, for example to set
  // January 21, 2014 at 3am you would call:
  // rtc.adjust(DateTime(2020, 12, 16, 10, 36, 0));

    Serial.println("Could not find BME280 sensor!");

  // bme.chipID(); // Deprecated. See chipModel().
     case BME280::ChipModel_BME280:
       Serial.println("Found BME280 sensor! Success.");
     case BME280::ChipModel_BMP280:
       Serial.println("Found BMP280 sensor! No Humidity available.");
       Serial.println("Found UNKNOWN sensor! Error!");


  Serial.print("Initializing SD card...");

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    while (1);
  Serial.println("card initialized.");

void loop() {

/*****************Get Temp, Pressure and Humidity********************/

  float temp(NAN), hum(NAN), pres(NAN);

   BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
   BME280::PresUnit presUnit(BME280::PresUnit_Pa);, temp, hum, tempUnit, presUnit);

float preshpa = (pres/100);  //create space for conversion of pascals to hectopascals (hPa) which is more usual measure
float corr_temp = (temp-0.0);  //create space for correction of temperature according to unique sensor validation (will be different for each sensor)
float corr_hum = (hum+0);  //create space for correction of humidity according to unique sensor validation (will be different for each sensor)
float corr_preshpa = (preshpa+10);  //create space for correction of pressure according to unique sensor validation (will be different for each sensor)

      Serial.print("Temp: ");
   Serial.print("°"+ String(tempUnit == BME280::TempUnit_Celsius ? 'C' :'F'));
   Serial.print("\t\tHumidity: ");
   Serial.print("% RH");
   Serial.print("\t\tPressure: ");
   Serial.print(" hPa   ");

/*********GET VOC ************/
 int a=analogRead(Aout);
  int b=digitalRead(Dout);
  Serial.print("   A0:");

/*********GET TIME ************/

//rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

    DateTime now =;
    Serial.print(now.year(), DEC);
    Serial.print(now.month(), DEC);
    Serial.print(, DEC);
    Serial.print(" (");
    Serial.print(") ");
    Serial.print(now.hour(), DEC);
    Serial.print(now.minute(), DEC);
    Serial.print(now.second(), DEC);
    //Serial.print(" since midnight 1/1/1970 = ");
    //Serial.print("s = ");
    //Serial.print(now.unixtime() / 86400L);

// DateTime now =;
  rtcs = now.second();
  rtcmin = now.minute();
  rtchr = now.hour();
  rtcy = now.year();
  rtcm = now.month();
  rtcd =;

/*********STORE DATA TO SD CARD ************/

// open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile ="datalog.csv", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {

    //dataFile.print(cm);        dataFile.print(",CM,");
    dataFile.print(rtchr);              dataFile.print(":");
    dataFile.print(rtcmin);             dataFile.print(":");
    dataFile.print(rtcs);               dataFile.print(",TIME,");
    dataFile.print(rtcd);               dataFile.print("/");
    dataFile.print(rtcm);               dataFile.print("/");
    dataFile.print(rtcy);             dataFile.print(",DATE,");
dataFile.print(corr_temp);             dataFile.print(",Temperature,");
dataFile.print(corr_preshpa);             dataFile.print(",Pressure,");
dataFile.print(corr_hum);             dataFile.print(",Humidity,");
dataFile.print(b);             dataFile.print(",TVOC Digital,");
dataFile.print(a);             dataFile.println(",TVOC Analogue");
    // print to the serial port too:
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.csv");



// ***********************End of Code -- you are DONE!*******************************

Generally, sensors like that are sensitive to multiple gasses. However, they have no way to distinguish which is which. I suspect your sensor is the same - check the data sheet.

Can you please post links to TVOC and TPH sensors?

Tom... :grinning: :+1: :coffee: :australia:

A sensor such as this will just give a “value” for the gases it senses in total not the individual components . It will have different sensitivity for different gases .
You will need to calibrate it against known concentrations of the gas of which you are interested .

Don’t expect hi end performance from a cheap sensor , it may drift , be temperature sensitive - you need to play with it, the spec probably doesn’t tell you everything !

This might help

The sensor is useful for telling you that something has changed in the local gaseous environment, but is not useful for measuring concentrations of different gases.

1 Like

Yes it is, thank you.

Thank you ! I assumed you could change the sensitivity from the data sheet where it highlights the formulation of Formaldehyde and Toluene but i also have no idea aha. Cheers