Arduino - SCD40 CO2 Sensor

In this tutorial, we are going to learn:

Arduino SCD40 CO2 Sensor

When many people stay in a closed room, the CO2 level goes up. High CO2 makes us tired and slow to think. With an SCD40 and an Arduino Uno, we can see this number and know when it is time to open a window.

About SCD40 CO2 Sensor

The SCD40 is a small CO2 sensor made by Sensirion. It measures the real amount of carbon dioxide in the air. This is different from cheap gas sensors like the MQ series (see Arduino - Gas Sensor), which only estimate air quality. How does it work? Inside the sensor, a tiny infrared light blinks. CO2 gas absorbs this light and makes a very small pressure wave, like a sound. A tiny microphone hears it. The more CO2 there is, the louder the sound. This method is called photoacoustic NDIR.

SCD40 CO2 Sensor Pinout
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 new value every 5 seconds
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

The SCD40 module has four pins:

  • VCC pin: needs to be connected to VCC (5V, or 3.3V)
  • GND pin: needs to be connected to GND (0V)
  • SDA pin: the I2C data pin. It needs to be connected to the SDA pin of Arduino
  • SCL pin: the I2C clock pin. It needs to be connected to the SCL pin of Arduino

Most SCD40 modules already have pull-up resistors for the I2C lines, so we do not need to add any.

What Does the CO2 Value Mean?

The sensor gives CO2 in ppm (parts per million). We can use this simple guide:

CO2 Level Air Quality
About 400 ppm Fresh outdoor air
400 to 1,000 ppm Good indoor air
1,000 to 2,000 ppm Stuffy, open a window
Above 2,000 ppm Poor, may cause headache or sleepiness

※ NOTE THAT:

  • The SCD40 calibrates itself automatically (Automatic Self-Calibration). For this to work, the sensor needs to see fresh air (about 400 ppm) at least once a week, for example near an open window for an hour.
  • The first few readings after power on may be less accurate. Give it a few minutes.

Wiring Diagram

On Arduino Uno, the I2C pins are A4 (SDA) and A5 (SCL).

Arduino SCD40 CO2 sensor wiring diagram

This image is created using Fritzing. Click to enlarge image

Wiring table of SCD40 Module and Arduino Uno

SCD40 Module Arduino Uno
VCC → 5V
GND → GND
SDA → A4
SCL → A5

How To Program For SCD40 CO2 Sensor

  • Include the libraries:
#include <Arduino.h> #include <SensirionI2cScd4x.h> #include <Wire.h>
  • Declare an SCD4x object:
SensirionI2cScd4x scd4x;
  • Initialize I2C and the sensor:
Wire.begin(); scd4x.begin(Wire, SCD40_I2C_ADDR_62);
  • Start the measurement. After this, the sensor makes a new reading every 5 seconds:
scd4x.startPeriodicMeasurement();
  • Check if a new reading is ready:
bool dataReady = false; scd4x.getDataReadyStatus(dataReady);
  • Read the values. The function always gives three values together:
uint16_t co2 = 0; float temperature = 0.0f; float humidity = 0.0f; scd4x.readMeasurement(co2, temperature, humidity);

Arduino Code - SCD40 CO2 Sensor

The below code prints the CO2 level and a simple word for the air quality: Good, Moderate or Poor.

/* * Created by ArduinoGetStarted.com * * This example code is in the public domain * * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-scd40-co2-sensor */ #include <Arduino.h> #include <SensirionI2cScd4x.h> #include <Wire.h> // SCD40 is connected to the Arduino Uno I2C pins: SDA = A4, SCL = A5 SensirionI2cScd4x scd4x; char errorMessage[64]; int16_t error; void setup() { Serial.begin(9600); while (!Serial) { delay(10); } Wire.begin(); // start I2C on the default pins (A4, A5) scd4x.begin(Wire, SCD40_I2C_ADDR_62); // the SCD40 address is 0x62 // clean start: wake the sensor up, stop any old measurement and reset it scd4x.wakeUp(); // may return an error if the sensor is already awake - ignore it scd4x.stopPeriodicMeasurement(); scd4x.reinit(); // start measuring: the SCD40 gives a new value every 5 seconds error = scd4x.startPeriodicMeasurement(); if (error) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Cannot start the SCD40: "); Serial.println(errorMessage); return; } Serial.println("SCD40 started. Waiting for the first reading..."); } void loop() { delay(1000); // check the sensor once per second // is a new reading ready? bool dataReady = false; error = scd4x.getDataReadyStatus(dataReady); if (error) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Data ready error: "); Serial.println(errorMessage); return; } if (!dataReady) { return; // not yet, try again in the next loop } // read the new values (temperature and humidity are not used here) uint16_t co2 = 0; float temperature = 0.0f; float humidity = 0.0f; error = scd4x.readMeasurement(co2, temperature, humidity); if (error) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Read error: "); Serial.println(errorMessage); return; } // print the CO2 level and a simple air quality word Serial.print("CO2 = "); Serial.print(co2); Serial.print(" ppm -> "); Serial.println(airQuality(co2)); } // turn a 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 - get fresh air"; }

Quick Steps

  • Connect Arduino to PC via USB cable
  • Open Arduino IDE, select the right board and port
  • Navigate to the Libraries icon on the left bar of the Arduino IDE.
  • Search “SCD4x”, then find the Sensirion I2C SCD4x library by Sensirion
  • Click 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 Uno
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 Uno on COM15
1
  • You will be asked to install the library dependency "Sensirion Core"
  • Click Install All button to install it too.
  • Copy the above code and open with Arduino IDE
  • Click Upload button on Arduino IDE to upload code to Arduino
  • Open the Serial Monitor. The first value comes after about 5 seconds.
  • Breathe slowly near the sensor, or close the door of a small room, and see the CO2 go up.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
Arduino Uno
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'Arduino Uno' on 'COM15')
New Line
9600 baud
SCD40 started. Waiting for the first reading... CO2 = 523 ppm -> Good CO2 = 531 ppm -> Good CO2 = 528 ppm -> Good CO2 = 874 ppm -> Good CO2 = 1362 ppm -> Moderate - open a window CO2 = 1148 ppm -> Moderate - open a window CO2 = 942 ppm -> Good CO2 = 761 ppm -> Good
Ln 11, Col 1
Arduino Uno on COM15
2

The jump to 1362 ppm happens when we breathe on the sensor. After a short time, the value goes back down.

Reading Temperature and Humidity from the SCD40

The SCD40 also has a built-in temperature and humidity sensor. It uses them to correct the CO2 value, but we can read them too. They come from the same readMeasurement() call, so we do not need any extra wiring or library. The code below prints all three values.

/* * Created by ArduinoGetStarted.com * * This example code is in the public domain * * Tutorial page: https://arduinogetstarted.com/tutorials/arduino-scd40-co2-sensor */ #include <Arduino.h> #include <SensirionI2cScd4x.h> #include <Wire.h> // SCD40 is connected to the Arduino Uno I2C pins: SDA = A4, SCL = A5 SensirionI2cScd4x scd4x; char errorMessage[64]; int16_t error; void setup() { Serial.begin(9600); while (!Serial) { delay(10); } Wire.begin(); scd4x.begin(Wire, SCD40_I2C_ADDR_62); // clean start scd4x.wakeUp(); // the result is ignored on purpose scd4x.stopPeriodicMeasurement(); scd4x.reinit(); error = scd4x.startPeriodicMeasurement(); if (error) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Cannot start the SCD40: "); Serial.println(errorMessage); return; } Serial.println("SCD40 started. New values come every 5 seconds."); } void loop() { delay(1000); bool dataReady = false; error = scd4x.getDataReadyStatus(dataReady); if (error || !dataReady) { return; // no new reading yet } uint16_t co2 = 0; float temperature = 0.0f; // in °C float humidity = 0.0f; // in %RH error = scd4x.readMeasurement(co2, temperature, humidity); if (error) { 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("\xC2\xB0"); // degree symbol Serial.print("C | Humidity: "); Serial.print(humidity, 1); Serial.println(" %"); }

Quick Steps

  • Keep the same wiring as above
  • Copy the above code and open with Arduino IDE
  • Click Upload button on Arduino IDE to upload code to Arduino
  • See the result on Serial Monitor
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
Arduino Uno
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'Arduino Uno' on 'COM15')
New Line
9600 baud
SCD40 started. New values come every 5 seconds. CO2: 612 ppm | Temperature: 25.3°C | Humidity: 47.2 % CO2: 618 ppm | Temperature: 25.3°C | Humidity: 47.0 % CO2: 625 ppm | Temperature: 25.4°C | Humidity: 46.9 % CO2: 633 ppm | Temperature: 25.4°C | Humidity: 46.8 %
Ln 11, Col 1
Arduino Uno on COM15
2

※ NOTE THAT:

The SCD40 is not made to be a high-accuracy thermometer. If you only need temperature and humidity, the Arduino - DHT22 tutorial is a simpler choice.

Video Tutorial

We are considering to make the video tutorials. If you think the video tutorials are essential, please subscribe to our YouTube channel to give us motivation for making the videos.

Function References

The Best Arduino Starter Kit

※ OUR MESSAGES