Measurement of eCO2 and VOC (Volatile Organic Compounds) with CCS811
Contents
CCS811
This article describes the measurement of eCO2 (equivalent carbon dioxide) and TVOC (total volatile organic compounds) with ESP32 and CCS811 module and display on OLED display.
What is eCO2?
The CO2 (carbon dioxide) that can be measured by CCS811 is called eCO2 (equivalent CO2), which is not exactly the same as CO2.
The following description can be found on this site.
“It’s important to recognize that the CCS811 cannot measure CO2 and that the “equivalent CO2″ being reported by the CCS811 has nothing to do with actual CO2 present in the area.”
https://www.sparkfun.com/news/2369
When the cap of a magic pen was opened and placed close to the sensor, the CO2 concentration of a commercial CO2 measuring instrument (NDIR-based product costing about $180) did not change, but the eCO2 value of the CCS811 increased.
When the CCS811’s eCO2 value increased in response to volatile gases, it seemed that the CCS811’s eCO2 value also increased in response to volatile gases, although it could be used as a CO2 measurement if there were “no gases around.
However, from the viewpoint of “whether indoor ventilation is necessary or not,” there is no problem with eCO2, and in fact, eCO2 may be easier to use because it reacts to volatile gases in addition to carbon dioxide.
If you want to measure purely CO2 concentration, I think MH-Z19C (NDIR method), which I wrote about in a previous article, is better.
What is TVOC?
TVOC (Total Volatile Organic Compounds) is a generic term for organic compounds that become gas in the atmosphere.
TVOC is effective as an indicator for detecting “air pollution” because its value increased in response to gases such as paint, ink, and gasoline.
Specifications
The main specifications are as follows
- eCO2: 400 – 8,192 ppm (parts per million)
- TVOC: 0 – 1187 ppb (parts per billion)
- I2C communication: Address 0x5A or 0x5B
- Voltage: 3.3V
- Conditioning time: Valid values are output at least 20 minutes after startup
Appearance
Pins, from top.
- RST: Used for hardware reset
- INT: Output when measurement ends or threshold is exceeded (not used this time)
- WAK: Used to switch between startup and hibernation to save power. High:hibernation, Low:startup
- SCL: SCL
- SDA: SDA
- 3.3V: Power supplied by ESP32
- GND: GND
There is a terminal for connecting an NTC thermistor at the bottom center.
The image of the back side is as follows.
The pin slightly below the center is the I2C address control pin, which is 0x5B (default) when open, and 0x5A when shorted, allowing the I2C address to be changed.
The pull-up resistor in the lower center is normally left short-circuited.
When opened, the pull-up resistor is disabled.
NTC Thermistor
There is an optional NTC(Negative Thermal Coefficient) thermistor that can be added by soldering to compensate for gas concentration based on ambient temperature, but it seems that the temperature guarantee is no longer supported (the connector is still there).
It said that an external sensor such as BME280 is recommended instead of NTC .
Baseline application time
There is a function that automatically corrects resistance values in response to variations in sensor manufacturing and changes over time.
Since the correction is made in 24 hours, it is better to assume that the correct value is output after 24 hours or more, in addition to the aforementioned conditioning time (20 minutes).
Other Parts
Other main parts prepared are as follows.
ESP32 module
The pin layout is the same as ESP32 DEVKIT V1 (30 pins).
OLED Module
The 0.96-inch OLED (Organic Light Emitting Diode) display was used.
The specifications are as follows
- Size: 0.96 inches
- Voltage: 3.3V to 5V
- Resolution: 128 × 64
- I2C connection: 0x3C (default) or 0x3D
- SSD1306 Compatible
Library Installation
The development environment was Arduino IDE (Ver 1.8.19).
Install the necessary libraries in advance.
CCS811
Download the library from sparkfun’s Github and add the library from the Arduino IDE by going to Sketch->Include Library->Add .ZIP Library.
SSD1306
Install the SSD1306 library for OLED displays.
From the Arduino IDE, go to Tools > Manage Libraries and search for “SSD1306” in the search field to install Adafruit SSD1306.
Wiring Diagram
The wiring is as follows.
INT is not connected this time, and RST and WAK are used. However, if you simply want to acquire and display values without considering power saving, it is not necessary to connect them.
It is possible to acquire values only by connecting GND, 3.3V, SDA, and SCL.
Scketch
The sketch measures eCO2 and TVOC at approximately 60-second intervals and displays them on the display.
ccs811_oled.ino
/*
* Created on Sun Feb 27 21:46:24 2022
*
* CCS811 Co2 Sensor & OLED Display
*
* @author: Souichirou Kikuchi
*/
#include <Wire.h> // I2C
#include <SparkFunCCS811.h> // CCS811
#include <Adafruit_SSD1306.h> // OLED Display
#define CCS811_ADDRESS 0x5B // CCS811 I2C Address
#define SCREEN_ADDRESS 0x3C // OLED Display Address
// I2C Pin
constexpr short int SDA_PIN = 21;
constexpr short int SCL_PIN = 22;
constexpr short int RESET_PIN = 5;
constexpr short int WAKE_UP_PIN = 4;
// OLED Display
constexpr short int SCREEN_WIDTH = 128; // OLED display width, in pixels
constexpr short int SCREEN_HEIGHT = 64; // OLED display height, in pixels
constexpr short int OLED_RESET = 4; // Reset pin # (or -1 if sharing Arduino reset pin)
CCS811 eco2_sensor(CCS811_ADDRESS); // eCo2 Sensor
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // OLEDDisplay
void ccs811_hw_reset() { // CCS811 Hardware Reset
pinMode(RESET_PIN, OUTPUT);
digitalWrite(RESET_PIN, LOW);
delay(10);
digitalWrite(RESET_PIN, HIGH);
}
void ccs811_wake() { // Wake up
digitalWrite(WAKE_UP_PIN, LOW);
delay(10);
}
void ccs811_sleep() { // Lower power consumption
digitalWrite(WAKE_UP_PIN, HIGH);
}
void setup()
{
int cnt;
const short int MAX_RETRY = 10;
Serial.begin(115200);
Serial.println("Program Start");
pinMode(WAKE_UP_PIN, OUTPUT);
ccs811_hw_reset();
ccs811_wake();
// I2C
Wire.begin(SDA_PIN, SCL_PIN);
// CCS811
cnt = 0;
while ((eco2_sensor.begin() == false) and (cnt < MAX_RETRY)) {
Serial.print("CCS811 initialize attempt");
Serial.println(cnt);
delay(1000);
cnt++;
}
if (cnt >= MAX_RETRY){
Serial.println("CCS811 initialize Error.");
} else {
Serial.println("CCS811 Initialized.");
}
ccs811_sleep();
// OLED Display Initialize
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
}
// Display settings
display.setTextSize(1); // size 1~5
display.setTextColor(SSD1306_WHITE);
display.display();
delay(10000);
}
void loop()
{
short int co2_ppm;
short int voc_ppb;
int co2_ttl;
int voc_ttl;
std::vector<int> co2List;
std::vector<int> vocList;
constexpr short int DATA_COUNT = 5; // Number of data acquisition
ccs811_wake();
co2List.clear();
vocList.clear();
// Maximum and minimum values are truncated
if (eco2_sensor.dataAvailable()) {
for (int i = 0; i < DATA_COUNT; i++) {
eco2_sensor.readAlgorithmResults();
co2List.push_back(eco2_sensor.getCO2());
vocList.push_back(eco2_sensor.getTVOC());
delay(1000);
}
} else {
Serial.println("CCS811 not Available");
}
ccs811_sleep();
std::sort(co2List.begin(), co2List.end());
std::sort(vocList.begin(), vocList.end());
co2List.pop_back(); // Delete trailing (maximum) data
vocList.pop_back();
co2List.erase(co2List.begin()); // Delete the first (minimum) data
vocList.erase(vocList.begin());
// average
co2_ttl = 0;
voc_ttl = 0;
// for (int i = 0; i < DATA_COUNT-2; i++) {
for (int i = 0; i < co2List.size(); i++) {
Serial.println(co2List[i]);
co2_ttl += co2List[i];
voc_ttl += vocList[i];
}
co2_ppm = co2_ttl / co2List.size();
voc_ppb = voc_ttl / vocList.size();
display.clearDisplay(); // Buffer Clear
display.setCursor(0, 0); // X Y
display.println("eCO2:" + String(co2_ppm) + " ppm");
display.setCursor(0, 30); // X Y
display.println("VOC:" + String(voc_ppb) + " ppb");
display.display();
delay(60000); // 60秒
}
supplementary explanation
ccs811_hw_reset
Function to hardware reset the CCS811.
Low and High are sent to the reset pin to reset.
ccs811_wake
Function to start up CCS811.
Low is sent to the Wake up pin.
ccs811_sleep
Function to put the CCS811 into power-saving mode.
High is sent to the Wake up pin.
setup
Initial Processing.
Hardware reset and initialization of the CCS811 and initialization of the OLED display.
loop
CCS811, however, when I tried to obtain the value continuously every second, I found that there was a slight difference each time.
In addition, it was confirmed that a large value was sometimes suddenly detected, and one second later, the value returned to the original value or thereabouts.
Example: 447 → 449 → 680 → 445 → 450 …
For this reason, I consider it problematic to assume that a value is positive after only one measurement, so I obtain the value several times in succession, truncate the maximum and minimum values, and take the average of all values except the truncated ones.
In the program, the maximum and minimum values are truncated after five consecutive measurements, and the average of the three intermediate data is taken.
Execution
The execution is shown below.
eCo2 concentration and TVOC are measured at 60 second intervals and displayed on the display.
This concludes this article.
I hope this article will be useful to someone somewhere.
Recent Comments