Arduino Nano - SCD40 CO2 Sensor

This tutorial instructs you how to use Arduino Nano to read the carbon dioxide (CO2) level of a room from the SCD40 sensor. In detail, we will learn:

Arduino Nano SCD40 CO2 Sensor

We suggest:

Hardware Preparation

1×Official Arduino Nano
1×Alternatively, DIYables Nano V3.0 Development Board
1×USB A to Mini-B USB cable
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

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 CO2 Sensor Pinout

The SCD40 from Sensirion measures true CO2 with photoacoustic NDIR sensing. Inside its small chamber, an infrared light flashes on and off. CO2 absorbs part of that light and creates a tiny pressure "sound", which a built-in microphone picks up: the more CO2, the stronger the signal. Because it measures the gas itself, its value is much more reliable than the "eCO2" estimate of sensors like the MQ135 or CCS811.

SCD40
Operating 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
Reading Rate one value 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 15 mA at 3.3V
SCD40 CO2 sensor pinout

The SCD40 module has four pins:

  • VCC pin: must be connected to VCC (5V or 3.3V)
  • GND pin: must be connected to GND (0V)
  • SDA pin: I2C data line, must be connected to the SDA pin of Arduino Nano (A4)
  • SCL pin: I2C clock line, must be connected to the SCL pin of Arduino Nano (A5)

Most SCD40 breakout boards already have I2C pull-up resistors, so no extra resistor is needed.

※ NOTE THAT:

The arrangement of pins on a module may differ from one manufacturer to another. Some boards label VCC as VIN. It is essential to always refer to the labels printed on the module when using it. Take a close look!

How To Read the CO2 Value

CO2 is measured in ppm (parts per million). The table below is a simple guide for indoor air:

CO2 Level Meaning
About 400 ppm Fresh outdoor air
400 to 1000 ppm Good indoor air
1000 to 2000 ppm Stuffy air, open a window
Above 2000 ppm Poor air, headache or drowsiness is possible

The SCD40 has Automatic Self-Calibration (ASC), which is ON by default. It assumes that the sensor sees fresh, outdoor-level air (about 400 ppm) at least once a week, ideally for an hour or more. So, air the room from time to time. Also, the first few readings after power-up may be less accurate while the sensor warms up.

Wiring Diagram

The SCD40 module talks to Arduino Nano over I2C, so it uses the A4 (SDA) and A5 (SCL) pins of the Arduino Nano.

The wiring diagram between Arduino Nano and SCD40 CO2 sensor

This image is created using Fritzing. Click to enlarge image

See The best way to supply power to the Arduino Nano and other components.

SCD40 Module Arduino Nano
VCC 5V
GND GND
SDA A4
SCL A5

How To Program For SCD40 CO2 Sensor

  • The first step is to include the libraries:
#include <Arduino.h> #include <SensirionI2cScd4x.h> #include <Wire.h>
  • Declare an SCD4x object:
SensirionI2cScd4x scd4x;
  • In setup(), start the I2C bus and attach the sensor at address 0x62:
Wire.begin(); scd4x.begin(Wire, SCD40_I2C_ADDR_62);
  • Make a clean start, then begin periodic measurement:
scd4x.wakeUp(); scd4x.stopPeriodicMeasurement(); scd4x.reinit(); scd4x.startPeriodicMeasurement();
  • In loop(), check if a new value is ready, then read it:
bool dataReady = false; scd4x.getDataReadyStatus(dataReady); if (dataReady) { scd4x.readMeasurement(co2, temperature, humidity); }
  • Every function returns an error code. When it is not 0, it can be turned into text:
errorToString(error, errorMessage, sizeof errorMessage);

Arduino Nano Code for SCD40 CO2 Sensor

The code below prints the CO2 value in ppm, followed by a simple word (Good, Moderate or Poor) based on the guide table above.

/* * This Arduino Nano code was developed by newbiely.com * * This Arduino Nano code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-nano/arduino-nano-scd40-co2-sensor */ // Arduino Nano + SCD40: read the CO2 level (ppm) // I2C wiring on Arduino Nano: SDA -> A4, SCL -> A5 #include <Arduino.h> #include <SensirionI2cScd4x.h> #include <Wire.h> SensirionI2cScd4x scd4x; // create the SCD40 object char errorMessage[64]; // buffer for error text int16_t error; void setup() { Serial.begin(9600); Wire.begin(); // Arduino Nano default I2C pins: A4 (SDA), A5 (SCL) scd4x.begin(Wire, SCD40_I2C_ADDR_62); // Clean start: wake up, stop any old measurement, reload settings scd4x.wakeUp(); // may return an error if the sensor is already awake - ignore it scd4x.stopPeriodicMeasurement(); scd4x.reinit(); // Start periodic measurement: a new value every 5 seconds error = scd4x.startPeriodicMeasurement(); if (error) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Cannot start measurement: "); Serial.println(errorMessage); } Serial.println("SCD40 started. Waiting for the first CO2 value..."); } void loop() { bool dataReady = false; uint16_t co2 = 0; float temperature = 0.0f; // not used in this sketch float humidity = 0.0f; // not used in this sketch delay(1000); // Check if a new measurement is ready error = scd4x.getDataReadyStatus(dataReady); if (error) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Data ready error: "); Serial.println(errorMessage); return; } if (!dataReady) { return; // not ready yet, try again in 1 second } // Read the measurement (CO2, temperature, humidity come together) error = scd4x.readMeasurement(co2, temperature, humidity); if (error) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Read error: "); Serial.println(errorMessage); return; } Serial.print("CO2: "); Serial.print(co2); Serial.print(" ppm -> "); Serial.println(airQuality(co2)); } // Turn the ppm value into a simple word const char* airQuality(uint16_t ppm) { if (ppm < 1000) return "Good"; if (ppm < 2000) return "Moderate - open a window"; return "Poor"; }

Detailed Instructions

  • If this is the first time you use Arduino Nano, see how to setup environment for Arduino Nano on Arduino IDE.
  • Wire the components as shown in the diagram.
  • Connect the Arduino Nano board to your computer using a USB cable.
  • Open Arduino IDE on your computer, then select the Arduino Nano board and its COM port.
  • Click to the Libraries icon on the left bar of the Arduino IDE.
  • Search "SCD4x", then find the Sensirion I2C SCD4x library by Sensirion.
  • Click the Install button to install the library.
  • 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
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 on COM15
1
  • You will be asked to install the dependency. Click the Install All button to install the Sensirion Core library.
  • Copy the code above and paste it into Arduino IDE.
  • Click the Upload button to upload the code to Arduino Nano.
  • Open the Serial Monitor and set the baud rate to 9600.
  • Breathe gently toward the sensor from a short distance and watch the value go up, then let it settle.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
Arduino Nano
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'Arduino Nano' on 'COM15')
New Line
9600 baud
SCD40 started. Waiting for the first CO2 value... CO2: 538 ppm -> Good CO2: 541 ppm -> Good CO2: 547 ppm -> Good CO2: 812 ppm -> Good CO2: 1367 ppm -> Moderate - open a window CO2: 1184 ppm -> Moderate - open a window CO2: 903 ppm -> Good CO2: 692 ppm -> Good
Ln 11, Col 1
Arduino Nano on COM15
2

A new line appears about every 5 seconds, because that is how often the SCD40 makes a new measurement.

Reading Temperature and Humidity from the SCD40

The SCD40 also has its own temperature and humidity sensor. The sensor uses it inside to correct the CO2 value, but you can read it too. In fact, readMeasurement() already returns all three values at once, so the code only needs to print them.

Arduino Nano Code for SCD40 - CO2, Temperature and Humidity

/* * This Arduino Nano code was developed by newbiely.com * * This Arduino Nano code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-nano/arduino-nano-scd40-co2-sensor */ // Arduino Nano + SCD40: read CO2, temperature and humidity // I2C wiring on Arduino Nano: SDA -> A4, SCL -> A5 #include <Arduino.h> #include <SensirionI2cScd4x.h> #include <Wire.h> SensirionI2cScd4x scd4x; // create the SCD40 object char errorMessage[64]; int16_t error; void setup() { Serial.begin(9600); Wire.begin(); // A4 = SDA, A5 = SCL scd4x.begin(Wire, SCD40_I2C_ADDR_62); scd4x.wakeUp(); // ignore the result scd4x.stopPeriodicMeasurement(); scd4x.reinit(); error = scd4x.startPeriodicMeasurement(); if (error) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Cannot start measurement: "); Serial.println(errorMessage); } Serial.println("SCD40 started (CO2 + temperature + humidity)"); } void loop() { bool dataReady = false; uint16_t co2 = 0; float temperature = 0.0f; float humidity = 0.0f; delay(1000); error = scd4x.getDataReadyStatus(dataReady); if (error || !dataReady) { return; // no new data yet } error = scd4x.readMeasurement(co2, temperature, humidity); if (error) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Read error: "); Serial.println(errorMessage); return; } 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

  • Keep the same wiring.
  • Copy the code above and open it in Arduino IDE.
  • Click the Upload button to upload the code to Arduino Nano.
  • Open the Serial Monitor.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
Arduino Nano
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'Arduino Nano' on 'COM15')
New Line
9600 baud
SCD40 started (CO2 + temperature + humidity) CO2: 619 ppm | Temperature: 25.3°C | Humidity: 46.8% CO2: 624 ppm | Temperature: 25.4°C | Humidity: 46.5% CO2: 631 ppm | Temperature: 25.4°C | Humidity: 46.9% CO2: 628 ppm | Temperature: 25.5°C | Humidity: 47.2%
Ln 11, Col 1
Arduino Nano on COM15
2

※ NOTE THAT:

The temperature value is mainly there to help the CO2 measurement, so it may differ a little from a room thermometer. For a dedicated temperature and humidity reading, a sensor like the DHT22 is a better choice.

Additional Knowledge

Let's compare the SCD40 and the MQ2 gas sensor.

SCD40 MQ2
What it measures real CO2 in ppm general level of LPG, smoke, alcohol, methane, etc.
Sensing method photoacoustic NDIR heated metal-oxide element
Output digital (I2C) analog voltage and digital threshold
Extra data temperature and humidity none
Warm-up a few readings 5-10 minutes (24-48 hours if stored long)

It is evident that the SCD40 is the right choice for indoor air quality and ventilation, while the MQ2 is meant for gas leak and smoke alarms.

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!