ESP32 C3 Super Mini - SCD40 CO2 Sensor

Is the air in your room fresh, or is it time to open a window? A CO2 reading answers that question. In this tutorial, the ESP32 C3 Super Mini reads carbon dioxide from a Sensirion SCD40 module and tells you if the air is Good, Moderate or Poor. At the end, we also read the temperature and humidity that the same sensor gives for free.

In this tutorial, you'll learn:

ESP32 C3 Super Mini - SCD40 CO2 Sensor

Hardware Preparation

1×ESP32 C3 Super Mini
1×USB Cable Type-A to Type-C (for USB-A PC)
1×USB Cable Type-C to Type-C (for USB-C PC)
1×SCD40 CO2 Sensor Module
1×Breadboard
1×Jumper Wires

Or you can buy the following kits:

1×DIYables Sensor Kit (18 sensors/displays)
Disclosure: Some of the links provided in this section are Amazon affiliate links. We may receive a commission for any purchases made through these links at no additional cost to you.
Additionally, some of these links are for products from our own brand, DIYables .

Overview of SCD40 CO2 Sensor

The SCD40 is a small CO2 sensor from Sensirion, part of the SCD4x family. It uses photoacoustic NDIR sensing: a tiny infrared light pulses inside the sensor chamber, CO2 absorbs some of that light and makes a very small pressure "sound", and a microphone picks it up. More CO2 gives a stronger sound. Because of this, the SCD40 measures true CO2. Cheap gas sensors such as the MQ2 gas sensor or "eCO2" chips only guess the CO2 value from other gases.

Key Features:

  • Supply voltage: 2.4V to 5.5V, so the 3.3V pin of the ESP32 C3 Super Mini works well
  • I2C interface, address 0x62
  • Output range: 0 to 40,000 ppm
  • Accuracy: ±(50 ppm + 5% of reading) from 400 to 2,000 ppm
  • New reading every 5 seconds (low-power mode: every 30 seconds)
  • Built-in temperature sensor (±0.8°C from 15°C to 35°C) and humidity sensor (±6 %RH)
  • About 15 mA average current at 3.3V in periodic mode

Why SCD40 is Great for Beginners:

  • Only 4 wires, and the module already has I2C pull-up resistors
  • The official library does all the math, you just get a number in ppm
  • Self-calibration (ASC) is ON by default, so no setup is needed

※ NOTE THAT:

Automatic self-calibration assumes the sensor sees fresh, outdoor-level air (about 400 ppm) at least once a week, ideally for an hour or more. Air out the room from time to time. Also, the first few readings after power-up can be less accurate while the sensor warms up.

SCD40 Module Pinout

SCD40 CO2 Sensor Pinout
  • VCC pin: power input, 2.4V to 5.5V. Connect it to 3.3V of the ESP32 C3 Super Mini.
  • GND pin: ground (0V).
  • SCL pin: I2C clock line.
  • SDA pin: I2C data line.

Some modules print VIN instead of VCC. It is the same pin.

What Do the CO2 Numbers Mean?

CO2 is measured in ppm (parts per million). The more people breathe in a closed room, the higher it goes.

CO2 Level (ppm) Air Quality What to Do
About 400 Outdoor air Nothing, this is fresh air
400 to 1,000 Good Normal indoor air
1,000 to 2,000 Moderate The room feels stuffy, open a window
Above 2,000 Poor Headache or sleepiness can happen, ventilate now

Wiring Diagram between SCD40 CO2 Sensor and ESP32 C3 Super Mini

The wiring diagram between ESP32 C3 Super Mini SCD40 CO2 Sensor

This image is created using Fritzing. Click to enlarge image

SCD40 Module Pin ESP32 C3 Super Mini Pin
VCC 3.3V
GND GND
SDA GPIO6
SCL GPIO7
  • Note: The ESP32 C3 can put I2C on almost any GPIO. The code starts I2C with Wire.begin(6, 7), so GPIO6 is SDA and GPIO7 is SCL.
  • Note: We skip GPIO8 and GPIO9 on purpose. They are boot pins on the C3, and GPIO8 also drives the on-board LED.
  • Note: Use 3.3V for VCC. Then the I2C lines stay at 3.3V, which is safe for the C3 pins.
  • Note: Keep the sensor away from your breath and from the hot regulator of the board. Both can change the reading.

ESP32 C3 Super Mini Code - SCD40 CO2

This first sketch prints only the CO2 value and an air-quality word.

What the code does:

  • Starts I2C on GPIO6 (SDA) and GPIO7 (SCL)
  • Connects to the SCD40 at address 0x62
  • Stops any old measurement and resets the sensor settings for a clean start
  • Starts periodic measurement, one result every 5 seconds
  • Checks once per second if a new result is ready
  • Prints the CO2 value in ppm with "Good", "Moderate" or "Poor"
  • Prints a readable error message if the sensor does not answer
/* * This ESP32 C3 Super Mini code was developed by newbiely.com * * This ESP32 C3 Super Mini code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-c3/esp32-c3-super-mini-scd40-co2-sensor */ /* * ESP32 C3 Super Mini - SCD40 CO2 Sensor (CO2 only) * * Library: "Sensirion I2C SCD4x" by Sensirion (it also needs "Sensirion Core"). * The SCD40 talks over I2C at address 0x62. * In periodic mode it makes one new measurement every 5 seconds. */ #include <Arduino.h> #include <Wire.h> // I2C library #include <SensirionI2cScd4x.h> // SCD4x library by Sensirion #define SDA_PIN 6 // ESP32 C3 Super Mini GPIO6 -> SCD40 SDA (I2C data) #define SCL_PIN 7 // ESP32 C3 Super Mini GPIO7 -> SCD40 SCL (I2C clock) SensirionI2cScd4x scd4x; // create the sensor object char errorMessage[64]; // text buffer for error messages from the library int16_t error; // 0 means OK, any other number is an error code // Turn a CO2 value (ppm) into a simple word you can understand quickly const char* airQuality(uint16_t co2) { if (co2 < 1000) return "Good"; // normal fresh indoor air if (co2 < 2000) return "Moderate"; // a bit stuffy, open a window return "Poor"; // too much CO2, let fresh air in now } // Print the library error code as readable text void printError(const char* where) { errorToString(error, errorMessage, sizeof errorMessage); // convert the code to text Serial.print("Error in "); Serial.print(where); Serial.print(": "); Serial.println(errorMessage); } void setup() { Serial.begin(115200); // start the Serial Monitor at 115200 baud delay(1000); // short wait so the USB serial port is ready Wire.begin(SDA_PIN, SCL_PIN); // start I2C on GPIO6 (SDA) and GPIO7 (SCL) scd4x.begin(Wire, SCD40_I2C_ADDR_62); // use this I2C bus and the sensor address 0x62 // Clean start: the sensor may still be measuring from before a reset scd4x.wakeUp(); // wake the sensor (an error here is OK if it was already awake) error = scd4x.stopPeriodicMeasurement(); // stop any old measurement if (error) printError("stopPeriodicMeasurement"); error = scd4x.reinit(); // reload the sensor settings if (error) printError("reinit"); // Start measuring: one new result every 5 seconds error = scd4x.startPeriodicMeasurement(); if (error) { printError("startPeriodicMeasurement"); return; // something is wrong, check the wiring } Serial.println("SCD40 started. First result comes in about 5 seconds..."); } void loop() { delay(1000); // check about once per second if a new result is ready bool dataReady = false; error = scd4x.getDataReadyStatus(dataReady); // ask the sensor: is new data ready? if (error) { printError("getDataReadyStatus"); return; } if (!dataReady) { return; // not ready yet, try again in the next loop } uint16_t co2 = 0; // CO2 in ppm (parts per million) float temperature = 0.0f; // the library also gives temperature... float humidity = 0.0f; // ...and humidity, but this sketch only prints CO2 error = scd4x.readMeasurement(co2, temperature, humidity); // read the new result if (error) { printError("readMeasurement"); return; } Serial.print("CO2: "); Serial.print(co2); // print the CO2 value Serial.print(" ppm -> "); Serial.println(airQuality(co2)); // print Good / Moderate / Poor }

Detailed Instructions

  • New to ESP32 C3 Super Mini? Complete our Getting Started with ESP32 C3 Super Mini tutorial first to set up your development environment.
  • Wire the sensor: Connect the SCD40 module to the ESP32 C3 Super Mini as in the wiring table above.
  • Connect USB cable: Plug the board into your computer with a USB Type-C cable.
  • Open Arduino IDE: Select the ESP32 C3 Super Mini board and its COM port.
  • Open Library Manager: Click the Libraries icon on the left bar of the Arduino IDE.
  • Search for library: Type "SCD4x" in the search box.
  • Install library: Find "Sensirion I2C SCD4x" by Sensirion and click Install.
  • Search for Sensirion I2C SCD4x created by Sensirion and click the Install button.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32C3 Dev Module
Library Manager
Type:
All
Topic:
All
Sensirion I2C SCD4x by Sensirion
Enables you to use the SCD4X sensor family via I2C. More info
1.1.0
INSTALL
Newbiely.ino
···
1 void setup() {
Output
Serial Monitor
Ln 1, Col 1
ESP32C3 Dev Module on COM15
1
  • Install dependency: A window asks to install "Sensirion Core" too. Click Install All.
  • Copy the code: Paste the CO2 code above into Arduino IDE.
  • Upload the code: Click the Upload button.
How to upload ESP32 C3 Super Mini code on Arduino IDE
  • Open Serial Monitor: Set the baud rate to 115200.
  • Test it: Wait about 5 seconds for the first value. Then breathe gently toward the sensor from a short distance and watch the CO2 number jump up.
  • Pro Tip: If you only see "Error in ..." lines, check SDA and SCL first. Swapped I2C wires are the most common mistake.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32C3 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32C3 Dev Module' on 'COM15')
New Line
9600 baud
SCD40 started. First result comes in about 5 seconds... CO2: 618 ppm -> Good CO2: 624 ppm -> Good CO2: 631 ppm -> Good CO2: 1187 ppm -> Moderate CO2: 1452 ppm -> Moderate CO2: 1106 ppm -> Moderate CO2: 873 ppm -> Good CO2: 702 ppm -> Good
Ln 11, Col 1
ESP32C3 Dev Module on COM15
2

The jump to over 1,000 ppm in the middle comes from breathing near the sensor. The value falls back once fresh air reaches it again.

Line-by-line Code Explanation

The above ESP32 C3 Super Mini code contains line-by-line explanation. Please read the comments in the code!

Reading Temperature and Humidity from the SCD40

The SCD40 also has its own temperature and humidity sensor. It uses them to correct the CO2 value, and it sends both numbers in the same reading as CO2. In fact, the first sketch already gets them from readMeasurement(). It just does not print them. The sketch below prints all three values on one line. The wiring and the library stay the same.

What the code does:

  • Uses the same I2C pins (GPIO6 and GPIO7) and the same start-up steps
  • Reads CO2, temperature and humidity in one call
  • Prints CO2 in ppm, temperature in °C and humidity in %, each new result every 5 seconds
/* * This ESP32 C3 Super Mini code was developed by newbiely.com * * This ESP32 C3 Super Mini code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-c3/esp32-c3-super-mini-scd40-co2-sensor */ /* * ESP32 C3 Super Mini - SCD40 CO2 Sensor (CO2 + temperature + humidity) * * Same wiring and library as the CO2-only sketch. * The SCD40 sends CO2, temperature and humidity in ONE reading, * so we only need to print the two extra values. */ #include <Arduino.h> #include <Wire.h> // I2C library #include <SensirionI2cScd4x.h> // SCD4x library by Sensirion #define SDA_PIN 6 // ESP32 C3 Super Mini GPIO6 -> SCD40 SDA (I2C data) #define SCL_PIN 7 // ESP32 C3 Super Mini GPIO7 -> SCD40 SCL (I2C clock) SensirionI2cScd4x scd4x; // create the sensor object char errorMessage[64]; // text buffer for error messages from the library int16_t error; // 0 means OK, any other number is an error code // Print the library error code as readable text void printError(const char* where) { errorToString(error, errorMessage, sizeof errorMessage); // convert the code to text Serial.print("Error in "); Serial.print(where); Serial.print(": "); Serial.println(errorMessage); } void setup() { Serial.begin(115200); // start the Serial Monitor at 115200 baud delay(1000); // short wait so the USB serial port is ready Wire.begin(SDA_PIN, SCL_PIN); // start I2C on GPIO6 (SDA) and GPIO7 (SCL) scd4x.begin(Wire, SCD40_I2C_ADDR_62); // the SCD40 address is 0x62 scd4x.wakeUp(); // wake the sensor (ignore the result) error = scd4x.stopPeriodicMeasurement(); // stop any old measurement first if (error) printError("stopPeriodicMeasurement"); error = scd4x.reinit(); // reload the sensor settings if (error) printError("reinit"); error = scd4x.startPeriodicMeasurement(); // new result every 5 seconds if (error) { printError("startPeriodicMeasurement"); return; // something is wrong, check the wiring } Serial.println("SCD40 started. Waiting for the first result..."); } void loop() { delay(1000); // check once per second bool dataReady = false; error = scd4x.getDataReadyStatus(dataReady); // is a new result ready? if (error) { printError("getDataReadyStatus"); return; } if (!dataReady) { return; // not yet, check again next time } uint16_t co2 = 0; // CO2 in ppm float temperature = 0.0f; // temperature in °C float humidity = 0.0f; // relative humidity in % error = scd4x.readMeasurement(co2, temperature, humidity); // read all three values at once if (error) { printError("readMeasurement"); return; } Serial.print("CO2: "); Serial.print(co2); Serial.print(" ppm | Temperature: "); Serial.print(temperature, 1); // 1 digit after the decimal point Serial.print(" °C | Humidity: "); Serial.print(humidity, 1); Serial.println(" %"); }
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32C3 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32C3 Dev Module' on 'COM15')
New Line
9600 baud
SCD40 started. Waiting for the first result... CO2: 655 ppm | Temperature: 24.6 °C | Humidity: 47.3 % CO2: 659 ppm | Temperature: 24.6 °C | Humidity: 47.1 % CO2: 664 ppm | Temperature: 24.7 °C | Humidity: 47.0 % CO2: 670 ppm | Temperature: 24.7 °C | Humidity: 46.8 %
Ln 11, Col 1
ESP32C3 Dev Module on COM15
2

※ NOTE THAT:

The temperature can read 1 to 2°C higher than the room when the sensor sits close to the ESP32 C3 Super Mini, because the board warms up a little when it runs. Move the module a few centimeters away on longer wires for a better reading. For temperature and humidity alone, see the ESP32 C3 Super Mini - Temperature Humidity Sensor tutorial.

Applications and Project Ideas

A small board and a true CO2 sensor are a good pair for indoor air projects:

  • A classroom or office CO2 meter that tells you when to open the windows
  • A bedroom monitor that logs CO2 during the night
  • A traffic-light indicator: green, yellow and red LEDs for Good, Moderate and Poor
  • A WiFi air-quality dashboard that uses the built-in WiFi of the C3
  • A smart fan that turns on a ventilation fan when CO2 goes above 1,000 ppm
  • A grow-tent or mushroom-room monitor that tracks CO2, temperature and humidity together

Video Tutorial

Watch the video below for a visual walkthrough of this project.

Challenge Yourself

Try these ideas with your ESP32 C3 Super Mini and SCD40:

  • Easy: Change the "Good" limit from 1,000 ppm to 800 ppm for a stricter rule
  • Easy: Print the temperature in Fahrenheit as well as Celsius
  • Medium: Light a red LED when CO2 is above 1,500 ppm
  • Medium: Show CO2, temperature and humidity on an OLED display that shares the same I2C bus
  • Advanced: Switch the sensor to low-power periodic mode (one reading every 30 seconds) to save battery
  • Advanced: Send the CO2 value to your phone over WiFi or Bluetooth every minute

※ OUR MESSAGES

  • As freelancers, We are AVAILABLE for HIRE. See how to outsource your project to us
  • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!