Arduino Nano ESP32 - SCD40 CO2 Sensor

A room full of people slowly fills up with CO2. You do not see it or smell it, but you feel it as a heavy head and lost focus. In this guide, we will learn how to use the SCD40 CO2 sensor with the Arduino Nano ESP32 to put a real number on that. In detail, we will learn:

Arduino Nano ESP32 SCD40 CO2 sensor

Hardware Preparation

1×Arduino Nano ESP32
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
1×Recommended: Screw Terminal Expansion Board for Arduino Nano
1×Recommended: Breakout Expansion Board for Arduino Nano
1×Recommended: Power Splitter for Arduino Nano ESP32

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 from Sensirion measures true CO2, not an "eCO2" guess like the MQ135 or CCS811. Inside its small chamber, an infrared light flashes on and off. CO2 absorbs some of that light and makes a tiny pressure "sound", and a built-in microphone hears it. More CO2 gives a stronger signal. The module talks to the Arduino Nano ESP32 over I2C, so it needs only two signal wires.

SCD40 CO2 sensor module pinout

The module has four pins:

  • VCC pin: connect to 3.3V (the sensor accepts 2.4V to 5.5V). Some boards label it VIN.
  • GND pin: connect to GND (0V).
  • SDA pin: I2C data line. Connect to A4 of the Arduino Nano ESP32.
  • SCL pin: I2C clock line. Connect to A5 of the Arduino Nano ESP32.

Most SCD40 modules already have I2C pull-up resistors on board, so you do not need to add them.

SCD40
Supply voltage 2.4V to 5.5V
Interface I2C, address 0x62
CO2 output range 0 to 40,000 ppm
CO2 accuracy ±(50 ppm + 5% of reading), from 400 to 2,000 ppm
New reading every 5 seconds (every 30 seconds in low-power mode)
Temperature accuracy ±0.8°C (15°C to 35°C)
Humidity accuracy ±6 %RH (15°C to 35°C, 20 to 65 %RH)
Average current about 15mA at 3.3V

What Do the CO2 Numbers Mean?

CO2 (ppm) Air quality What to do
around 400 Outdoor air Nothing, this is fresh air
400 to 1000 Good indoor air Nothing
1000 to 2000 Stuffy Open a window
above 2000 Poor Ventilate now, headache and sleepiness are possible

※ NOTE THAT:

Automatic self-calibration (ASC) is ON by default. The sensor expects to see fresh, outdoor-level air (about 400 ppm) at least once a week, ideally for an hour or more. If it never gets fresh air, its readings can slowly drift. Also, the first few readings after power-on may be less accurate.

Wiring Diagram

The SCD40 uses the default I2C pins of the Arduino Nano ESP32: A4 for SDA and A5 for SCL. Since the board runs at 3.3V, power the module from the 3V3 pin.

The wiring diagram between Arduino Nano ESP32 and SCD40 CO2 sensor

This image is created using Fritzing. Click to enlarge image

SCD40 Module Arduino Nano ESP32
VCC → 3V3
GND → GND
SDA → A4
SCL → A5

How To Program For SCD40

  • Include the libraries.
#include <SensirionI2cScd4x.h> #include <Wire.h>
  • Create the sensor object.
SensirionI2cScd4x scd4x;
  • Start I2C and tell the library which bus and address to use.
Wire.begin(); scd4x.begin(Wire, SCD40_I2C_ADDR_62);
  • Start periodic measurement (one new value every 5 seconds).
scd4x.startPeriodicMeasurement();
  • Check if a new value is ready, then read it.
bool dataReady = false; scd4x.getDataReadyStatus(dataReady); if (dataReady) { scd4x.readMeasurement(co2, temperature, humidity); }

The library always reads CO2, temperature and humidity together. In the first sketch, we only print the CO2 value.

Arduino Nano ESP32 Code - SCD40 CO2 Sensor

/* * This Arduino Nano ESP32 code was developed by newbiely.com * * This Arduino Nano ESP32 code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-nano-esp32/arduino-nano-esp32-scd40-co2-sensor */ // Read the CO2 level (ppm) from an SCD40 sensor and print it with a simple air-quality word. // Wiring (I2C): SDA -> A4, SCL -> A5, VCC -> 3V3, GND -> GND #include <Arduino.h> #include <SensirionI2cScd4x.h> // "Sensirion I2C SCD4x" library by Sensirion #include <Wire.h> SensirionI2cScd4x scd4x; // the SCD40 sensor object char errorMessage[64]; // buffer for error text int16_t error; // 0 = no error void setup() { Serial.begin(9600); delay(1000); Wire.begin(); // Nano ESP32 default I2C pins: A4 (SDA), A5 (SCL) scd4x.begin(Wire, SCD40_I2C_ADDR_62); // the SCD40 address is 0x62 // Clean start: wake the sensor, stop any old measurement, reload its settings scd4x.wakeUp(); // may return an error if the sensor is already awake, that is OK scd4x.stopPeriodicMeasurement(); scd4x.reinit(); // Start periodic mode: one new reading about every 5 seconds error = scd4x.startPeriodicMeasurement(); if (error != 0) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Cannot start measurement: "); Serial.println(errorMessage); return; } Serial.println("SCD40 started. Waiting for the first CO2 reading..."); } void loop() { // Ask the sensor if a new reading is ready bool dataReady = false; error = scd4x.getDataReadyStatus(dataReady); if (error != 0) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Data ready error: "); Serial.println(errorMessage); delay(1000); return; } if (!dataReady) { // not ready yet, check again soon delay(500); return; } // Read the measurement (the library always returns all three values) uint16_t co2 = 0; float temperature = 0.0f; float humidity = 0.0f; error = scd4x.readMeasurement(co2, temperature, humidity); if (error != 0) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Read error: "); Serial.println(errorMessage); return; } // Print the CO2 value and a simple air-quality word Serial.print("CO2: "); Serial.print(co2); Serial.print(" ppm -> "); Serial.println(airQualityText(co2)); } // Turn a ppm value into a simple word const char* airQualityText(uint16_t ppm) { if (ppm < 1000) return "Good"; if (ppm < 2000) return "Moderate - open a window"; return "Poor - ventilate now"; }

Detailed Instructions

To get started with Arduino Nano ESP32, follow these steps:

  • If you are new to Arduino Nano ESP32, refer to the tutorial on how to set up the environment for Arduino Nano ESP32 in the Arduino IDE.
  • Wire the SCD40 module to the Arduino Nano ESP32 according to the table and diagram above.
  • Connect the Arduino Nano ESP32 board to your computer using a USB cable.
  • Launch the Arduino IDE on your computer.
  • Select the Arduino Nano ESP32 board and its corresponding COM port.
  • Open the Library Manager by clicking on the Library Manager icon on the left navigation bar of Arduino IDE.
  • Type "SCD4x" on the search box, then look for the Sensirion I2C SCD4x library by Sensirion.
  • Click the Install button.
  • A window asks to install a dependency (Sensirion Core). Click Install All.
  • Search for Sensirion I2C SCD4x created by Sensirion and click the Install button.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
Arduino Nano ESP32
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
Arduino Nano ESP32 on COM15
1
  • Copy the code above and paste it into the Arduino IDE.
  • Click the Upload button to send the code to the Arduino Nano ESP32.
  • Open the Serial Monitor. The first value comes after about 5 seconds.
  • Breathe gently near the sensor for a few seconds and watch the CO2 value climb, then fall again.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
Arduino Nano ESP32
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'Arduino Nano ESP32' on 'COM15')
New Line
9600 baud
SCD40 started. Waiting for the first CO2 reading... CO2: 612 ppm -> Good CO2: 608 ppm -> Good CO2: 615 ppm -> Good CO2: 1340 ppm -> Moderate - open a window CO2: 1185 ppm -> Moderate - open a window CO2: 947 ppm -> Good CO2: 731 ppm -> Good CO2: 664 ppm -> Good
Ln 11, Col 1
Arduino Nano ESP32 on COM15
2

※ NOTE THAT:

If you see an error message instead of numbers, check that SDA goes to A4 and SCL goes to A5, not the other way around.

Reading Temperature and Humidity from the SCD40

The SCD40 has its own small temperature and humidity sensor inside. It uses them to correct the CO2 value, and the library gives them to us for free in the same readMeasurement() call. So with no extra wiring, the Arduino Nano ESP32 can show all three values. The wiring and the library stay the same as above.

※ NOTE THAT:

The sensor warms up a little while it works, so its temperature can read slightly higher than the room. It is fine for a room monitor, but use a dedicated sensor if you need precise temperature.

Arduino Nano ESP32 Code - SCD40 CO2, Temperature and Humidity

/* * This Arduino Nano ESP32 code was developed by newbiely.com * * This Arduino Nano ESP32 code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-nano-esp32/arduino-nano-esp32-scd40-co2-sensor */ // Read CO2 (ppm), temperature (°C) and humidity (%RH) from an SCD40 sensor. // Wiring (I2C): SDA -> A4, SCL -> A5, VCC -> 3V3, GND -> GND #include <Arduino.h> #include <SensirionI2cScd4x.h> // "Sensirion I2C SCD4x" library by Sensirion #include <Wire.h> SensirionI2cScd4x scd4x; // the SCD40 sensor object char errorMessage[64]; // buffer for error text int16_t error; // 0 = no error void setup() { Serial.begin(9600); delay(1000); Wire.begin(); // Nano ESP32 default I2C pins: A4 (SDA), A5 (SCL) scd4x.begin(Wire, SCD40_I2C_ADDR_62); // the SCD40 address is 0x62 // Clean start scd4x.wakeUp(); // an error here only means the sensor was already awake scd4x.stopPeriodicMeasurement(); scd4x.reinit(); error = scd4x.startPeriodicMeasurement(); // new data about every 5 seconds if (error != 0) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Cannot start measurement: "); Serial.println(errorMessage); return; } Serial.println("SCD40 started (CO2 + temperature + humidity)"); } void loop() { bool dataReady = false; error = scd4x.getDataReadyStatus(dataReady); if (error != 0 || !dataReady) { // error or no new data yet: wait and try again delay(500); return; } uint16_t co2 = 0; float temperature = 0.0f; float humidity = 0.0f; error = scd4x.readMeasurement(co2, temperature, humidity); if (error != 0) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Read error: "); Serial.println(errorMessage); return; } // Print all three values on one line Serial.print("CO2: "); Serial.print(co2); Serial.print(" ppm | Temperature: "); Serial.print(temperature, 1); Serial.print(" °C | Humidity: "); Serial.print(humidity, 1); Serial.println(" %"); }

Detailed Instructions

  • Copy the code above and paste it into the Arduino IDE.
  • Click the Upload button to send the code to the Arduino Nano ESP32.
  • Open the Serial Monitor to see all three values on one line.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
Arduino Nano ESP32
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'Arduino Nano ESP32' on 'COM15')
New Line
9600 baud
SCD40 started (CO2 + temperature + humidity) CO2: 702 ppm | Temperature: 25.6 °C | Humidity: 47.3 % CO2: 709 ppm | Temperature: 25.6 °C | Humidity: 47.1 % CO2: 716 ppm | Temperature: 25.7 °C | Humidity: 46.9 % CO2: 711 ppm | Temperature: 25.7 °C | Humidity: 47.0 %
Ln 11, Col 1
Arduino Nano ESP32 on COM15
2

Video Tutorial

※ 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!