Arduino Mega - SCD40 CO2 Sensor

This tutorial instructs you how to use the Arduino Mega 2560 to measure the amount of carbon dioxide (CO2) in a room with the Sensirion SCD40 sensor. A stuffy classroom, office or bedroom is often a sign of too much CO2, and the SCD40 shows it as a real number in ppm. In detail, we will learn:

We suggest:

Arduino Mega and SCD40 CO2 sensor

Hardware Preparation

1×Arduino MEGA
1×Alternatively, DIYables MEGA Development Board
1×USB 2.0 cable type A/B (for USB-A PC)
1×USB 2.0 cable type C/B (for USB-C PC)
1×SCD40 CO2 Sensor Module
1×Jumper Wires
1×Recommended: Screw Terminal Block Shield for Arduino Uno/Mega
1×Recommended: Sensors/Servo Expansion Shield for Arduino Mega
1×Recommended: Breadboard Shield for Arduino Mega
1×Recommended: Enclosure for Arduino Mega

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 is a tiny sensor that measures real CO2. Many cheap "air quality" sensors, like the MQ135 or CCS811, only guess an "eCO2" value from other gases. The SCD40 does not guess. It uses photoacoustic NDIR sensing: a small infrared light flashes inside the sensor chamber, the CO2 molecules absorb some of that light and make a very faint pressure "sound", and a tiny microphone hears it. More CO2 means a louder signal.

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

The sensor also has a built-in temperature and humidity sensor. It uses them to correct the CO2 value, and the Arduino Mega can read them too (see the end of this tutorial).

The SCD40 CO2 Sensor Pinout

SCD40 CO2 sensor module pinout

The SCD40 module has four pins:

  • VCC pin: must be connected to the 5V pin of the Arduino Mega (3.3V also works).
  • GND pin: must be connected to GND (0V).
  • SDA pin: the I2C data line. It must be connected to pin 20 (SDA) of the Arduino Mega.
  • SCL pin: the I2C clock line. It must be connected to pin 21 (SCL) of the Arduino Mega.

Some boards label the VCC pin as VIN. Most modules already include the I2C pull-up resistors, so no extra resistors are needed.

※ NOTE THAT:

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

What the CO2 Value Means

Fresh outdoor air has about 400 ppm of CO2. Indoors, every person breathes out more CO2, so the level climbs when the windows are closed.

CO2 level Air quality What to do
About 400 ppm Outdoor air Nothing
400 to 1,000 ppm Good indoor air Nothing
1,000 to 2,000 ppm Stuffy Open a window
Above 2,000 ppm Poor Ventilate now, headache and sleepiness are possible

Self-Calibration and Warm-Up

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. It uses the lowest value it sees as its 400 ppm reference. So, open a window from time to time near the sensor. Also, the first few readings after power-on can be less accurate. Give it a few minutes before trusting the numbers.

Wiring Diagram

The SCD40 talks over I2C, so it goes to the dedicated I2C pins of the Arduino Mega: pin 20 (SDA) and pin 21 (SCL). Note that this is different from the Arduino Uno, which uses A4 and A5.

The wiring diagram between Arduino Mega SCD40 CO2 sensor

This image is created using Fritzing. Click to enlarge image

SCD40 Module Arduino Mega
VCC 5V
GND GND
SDA Pin 20 (SDA)
SCL Pin 21 (SCL)

The Arduino Mega also has SDA and SCL header pins next to the AREF pin. They are the same signals as pins 20 and 21, so you can use either one.

How To Program For SCD40 CO2 Sensor

  • The first step is to include the Sensirion library and the Wire library:
#include <Arduino.h> #include <SensirionI2cScd4x.h> #include <Wire.h>
  • A sensor object is declared:
SensirionI2cScd4x scd4x;
  • In setup(), the I2C bus is started on the Mega's default pins, and the sensor is attached at address 0x62:
Wire.begin(); scd4x.begin(Wire, SCD40_I2C_ADDR_62);
  • The sensor is given a clean start, then periodic measurement is started (one new value every 5 seconds):
scd4x.wakeUp(); scd4x.stopPeriodicMeasurement(); scd4x.reinit(); scd4x.startPeriodicMeasurement();
  • In loop(), the code first asks if a new value is ready, then reads it:
bool dataReady = false; scd4x.getDataReadyStatus(dataReady); if (dataReady) { uint16_t co2 = 0; float temperature = 0.0f; float humidity = 0.0f; scd4x.readMeasurement(co2, temperature, humidity); }

Every function returns an error code. If it is not 0, the code turns it into a text message with errorToString() and prints it, which helps a lot when the wiring is wrong.

Arduino Mega 2560 Code for SCD40 CO2 Sensor

The code below reads the CO2 value every time a new measurement is ready, prints it in ppm, and adds an air quality word based on the table above.

/* * This Arduino Mega code was developed by newbiely.com * * This Arduino Mega code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-mega/arduino-mega-scd40-co2-sensor */ // Arduino Mega reads the CO2 level (ppm) from the SCD40 sensor // Wiring: SDA -> pin 20 (SDA), SCL -> pin 21 (SCL), VCC -> 5V, GND -> GND // Library: "Sensirion I2C SCD4x" by Sensirion (needs "Sensirion Core") #include <Arduino.h> #include <SensirionI2cScd4x.h> #include <Wire.h> SensirionI2cScd4x scd4x; char errorMessage[64]; int16_t error; // Turn a CO2 value into a simple air quality word const char* airQuality(uint16_t co2) { if (co2 < 1000) return "Good"; if (co2 < 2000) return "Moderate - open a window"; return "Poor"; } void setup() { Serial.begin(9600); while (!Serial) { delay(10); } Wire.begin(); // Arduino Mega I2C: pin 20 (SDA), pin 21 (SCL) scd4x.begin(Wire, SCD40_I2C_ADDR_62); // Clean start: wake up, stop any old measurement, reload settings scd4x.wakeUp(); // may report an error if the sensor is already awake - this is OK scd4x.stopPeriodicMeasurement(); scd4x.reinit(); // Start measuring: the sensor gives a new value 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. First value comes in about 5 seconds..."); } void loop() { delay(1000); // check once per second // Is a new measurement ready? bool dataReady = false; error = scd4x.getDataReadyStatus(dataReady); if (error != 0) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Data ready check failed: "); Serial.println(errorMessage); return; } if (!dataReady) { return; // not yet, try again in the next loop } // Read the measurement (the sensor always sends CO2, temperature and humidity together) 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 failed: "); Serial.println(errorMessage); return; } // Print only the CO2 value Serial.print("CO2: "); Serial.print(co2); Serial.print(" ppm -> "); Serial.println(airQuality(co2)); }

Detailed Instructions

  • If this is the first time you use Arduino Mega 2560, see how to setup environment for Arduino Mega on Arduino IDE.
  • Wire the components as shown in the diagram.
  • Connect the Arduino Mega board to your computer using a USB cable.
  • Open Arduino IDE on your computer.
  • Select the Arduino Mega or Mega 2560 board and the correct COM port.
  • Click the Libraries icon on the left side of the Arduino IDE.
  • Type SCD4x in the search box, then find the Sensirion I2C SCD4x library by Sensirion.
  • Click the Install button.
  • 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 Mega Or...
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 Mega Or... on COM15
1
  • A window appears and asks to install the dependency Sensirion Core. Click the Install All button.
  • Copy the above code and paste it into the Arduino IDE.
  • Click the Upload button to upload the code to the Arduino Mega.
  • Open the Serial Monitor and set the baud rate to 9600.
  • Wait about 5 seconds for the first value. Then breathe gently toward the sensor, or close the door of a small room for a while.
  • See the result on the Serial Monitor:
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
Arduino Mega Or...
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'Arduino Mega Or...' on 'COM15')
New Line
9600 baud
SCD40 started. First value comes in about 5 seconds... CO2: 538 ppm -> Good CO2: 541 ppm -> Good CO2: 547 ppm -> Good CO2: 812 ppm -> Good CO2: 1164 ppm -> Moderate - open a window CO2: 1083 ppm -> Moderate - open a window CO2: 926 ppm -> Good CO2: 754 ppm -> Good
Ln 11, Col 1
Arduino Mega Or... on COM15
2

Your breath has a lot of CO2, so the value jumps quickly and then falls back as the air mixes. A new line appears about every 5 seconds, because that is how often the SCD40 makes a new measurement.

※ NOTE THAT:

If the Serial Monitor shows an error message, check that SDA goes to pin 20 and SCL goes to pin 21. Swapping these two wires is the most common mistake.

Reading Temperature and Humidity from the SCD40

Every measurement from the SCD40 already contains three values: CO2, temperature and humidity. The first code read all three but printed only the CO2. To show the other two, we only need to print the temperature and humidity variables as well. No extra wiring is needed.

Arduino Mega 2560 Code for CO2, Temperature and Humidity

/* * This Arduino Mega code was developed by newbiely.com * * This Arduino Mega code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/arduino-mega/arduino-mega-scd40-co2-sensor */ // Arduino Mega reads CO2, temperature and humidity from the SCD40 sensor // Wiring: SDA -> pin 20 (SDA), SCL -> pin 21 (SCL), VCC -> 5V, GND -> GND // Library: "Sensirion I2C SCD4x" by Sensirion (needs "Sensirion Core") #include <Arduino.h> #include <SensirionI2cScd4x.h> #include <Wire.h> SensirionI2cScd4x scd4x; char errorMessage[64]; int16_t error; void setup() { Serial.begin(9600); while (!Serial) { delay(10); } Wire.begin(); // Arduino Mega I2C: pin 20 (SDA), pin 21 (SCL) scd4x.begin(Wire, SCD40_I2C_ADDR_62); // Clean start scd4x.wakeUp(); // an error here is OK if the sensor is already awake scd4x.stopPeriodicMeasurement(); scd4x.reinit(); // New value 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 data..."); } void loop() { delay(1000); bool dataReady = false; error = scd4x.getDataReadyStatus(dataReady); if (error != 0) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Data ready check failed: "); Serial.println(errorMessage); return; } if (!dataReady) { return; // no new data yet } uint16_t co2 = 0; float temperature = 0.0f; // degrees Celsius float humidity = 0.0f; // percent relative humidity error = scd4x.readMeasurement(co2, temperature, humidity); if (error != 0) { errorToString(error, errorMessage, sizeof errorMessage); Serial.print("Read failed: "); 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 upload the code to the Arduino Mega.
  • Open the Serial Monitor and check the result:
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
Arduino Mega Or...
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'Arduino Mega Or...' on 'COM15')
New Line
9600 baud
SCD40 started. Waiting for data... CO2: 603 ppm | Temperature: 24.6°C | Humidity: 47.3% CO2: 609 ppm | Temperature: 24.6°C | Humidity: 47.1% CO2: 615 ppm | Temperature: 24.7°C | Humidity: 47.0% CO2: 622 ppm | Temperature: 24.7°C | Humidity: 46.8%
Ln 11, Col 1
Arduino Mega Or... on COM15
2

The sensor heats itself a little while it works, so the temperature can read slightly higher than a room thermometer. The CO2 value stays the main job of the SCD40; the temperature and humidity are a nice bonus.

Additional Knowledge

SCD40 vs MQ135 and Other Gas Sensors

SCD40 MQ135 / MQ-series
What it measures real CO2 (NDIR) mix of gases, CO2 is only estimated
Output CO2 in ppm, digital (I2C) analog voltage
Needs calibration in code no, self-calibration built in yes
Warm-up a few minutes minutes to hours
Extra values temperature and humidity none

It is evident that the SCD40 is the better choice when you need a trusted CO2 number, for example to decide when to open a window. An MQ-series sensor is cheaper and is still useful to detect smoke or a gas leak.

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!