Skip to content
My Account

Reference

SCD40 / SCD41 CO2 Sensor Complete Guide

The SCD40 and SCD41 CO2 sensors: the real accuracy numbers, wiring, the full command set, calibration (ASC, altitude, temperature offset), code and the traps that give wrong readings.

  • CO2 400 to 5000 ppm
  • I2C address 0x62
  • 2.4 to 5.5 V
  • Photoacoustic NDIR
No ratings yet, be the first.

The SCD40 and SCD41 are Sensirion’s small CO2 sensors. They measure carbon dioxide in parts per million with photoacoustic NDIR (non-dispersive infrared) sensing, and they measure temperature and humidity as well. That is a different measurement from the BME280 or the SHT sensors: none of those measures CO2. The chip is only 10.1 × 10.1 × 6.5 mm and talks I2C.

This guide covers the difference between the SCD40 and SCD41 with the real numbers, the pins, wiring, the full command set, calibration (ASC, forced recalibration, altitude and pressure), a code example that talks to the chip, and the traps that give wrong readings. The chip data comes from the Sensirion SCD4x datasheet (version 1.5, July 2023). Breakout boards differ from seller to seller, so check the labels on your own board.

SCD40 or SCD41

SCD40SCD41
Specified CO2 range400 to 2000 ppm400 to 5000 ppm
CO2 accuracy±(50 ppm + 5 % of the reading) over 400 to 2000 ppm±(50 ppm + 2.5 %) over 400 to 1000 ppm, ±(50 ppm + 3 %) over 1001 to 2000 ppm, ±(40 ppm + 5 %) over 2001 to 5000 ppm
Single shot modeNoYes, one measurement on command
Low-power single shotNoYes, 0.45 mA average at one measurement every 5 minutes (3.3 V)
Periodic measurementYes, one every 5 sYes, one every 5 s
I2C address0x620x62

Both have the same pins, address and commands, so code written for one runs on the other, except for the single shot commands that only the SCD41 knows. Take the SCD41 for battery projects, for a wider range or for the best accuracy. The SCD40 is cheaper and fine for a monitor on mains power.

Source: Sensirion SCD4x datasheet, version 1.5 (July 2023).

Getting started

1. What you needA breakout with an SCD40 or SCD41, an ESP32 or Arduino, four jumper wires and a breadboard.
2. Wire it upVDD to 3.3 V (or 5 V if your board allows), GND to GND, SDA to GPIO21 and SCL to GPIO22 on a classic ESP32.
3. Upload the sketch and waitInstall the SparkFun SCD4x library, upload the sketch and wait. The first CO2 value arrives after 5 seconds, and the first minutes are less accurate.

Specifications

CO2, humidity and temperature

CO2 output range0 to 40000 ppm
CO2 repeatability±10 ppm typical
CO2 accuracy with ASC±(5 ppm + 0.5 % of the reading) typical over 400 to 2000 ppm
Humidity range and accuracy0 to 100 %RH, ±6 %RH typical (15 to 35 °C, 20 to 65 %RH), ±9 %RH over the full range
Humidity response90 s (63 %), drift less than 0.25 %RH per year
Temperature range and accuracy−10 to 60 °C, ±0.8 °C typical (15 to 35 °C), ±1.5 °C over the full range
Temperature response120 s (63 %), drift less than 0.03 °C per year

Electrical

Supply voltage2.4 to 5.5 V, 3.3 or 5 V typical. Absolute maximum 6 V
Supply rippleAt most 30 mV peak to peak, an LDO is recommended
Average current, periodic15 mA at 3.3 V, 11 mA at 5 V (one measurement every 5 s)
Average current, low-power periodic3.2 mA at 3.3 V
Average current, single shot (SCD41)0.45 mA at 3.3 V, 0.36 mA at 5 V (one measurement every 5 minutes)
InterfaceI2C, up to 400 kHz, address 0x62, a CRC on every 16-bit word
Power-up time30 ms at most
Storage10 to 50 °C recommended

Source: Sensirion SCD4x datasheet, version 1.5 (July 2023). The accuracy holds at 25 °C, 50 %RH and 1013 mbar with the ASC working.

Dimensions

The chip is 10.1 × 10.1 mm and 6.5 mm high, with a protection membrane on top. Breakout boards come in many sizes, so measure your own before you design a case. Leave the membrane free: air must reach it, and a conformal coating or glue blocks it.

Source: Sensirion SCD4x datasheet.

Pins

PinTypeFunction
VDDPowerSupply, 2.4 to 5.5 V
VDDHPowerSupply of the infrared source. Must be tied to VDD (bare chip). Breakouts do this for you
GNDPowerGround
SDAI2CData, needs a pull-up, for example 10 kΩ
SCLI2CClock, needs a pull-up, for example 10 kΩ

A breakout normally brings out VDD (or VIN), GND, SDA and SCL. The order differs between makers, so read the print on yours.

Source: Sensirion SCD4x datasheet, pin assignment.

Wiring

SCD4x pinESP32Arduino Uno / NanoRaspberry PiESP8266
VDD3.3 V3.3 V3.3 V (pin 1)3.3 V
GNDGNDGNDGND (pin 6)GND
SDAGPIO21A4GPIO2 (pin 3)D2 (GPIO4)
SCLGPIO22A5GPIO3 (pin 5)D1 (GPIO5)

The chip draws 15 mA on average and has current peaks, so power it from a stable supply and keep the wires short. A noisy supply (more than 30 mV ripple) disturbs the sensor. An Arduino Uno at 5 V needs a board with level shifting.

Software setup

PlatformWhat to do
Arduino IDEInstall SparkFun SCD4x Arduino Library, or Sensirion’s Sensirion I2C SCD4x, from the Library Manager
PlatformIOAdd sparkfun/SparkFun SCD4x Arduino Library to lib_deps
ESP-IDFUse the I2C master driver and the commands below
NoteThere is no first-party Adafruit Arduino library for this chip, only a CircuitPython driver

Read the sensor

#include <Wire.h>
#include <SparkFun_SCD4x_Arduino_Library.h>

SCD4x co2Sensor;

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);
  if (!co2Sensor.begin()) {
    Serial.println("Couldn't find SCD4x sensor");
    while (1) delay(10);
  }
}

void loop() {
  if (co2Sensor.readMeasurement()) {
    Serial.print("CO2 (ppm): ");
    Serial.print(co2Sensor.getCO2());
    Serial.print("  Temp (C): ");
    Serial.print(co2Sensor.getTemperature());
    Serial.print("  Humidity (%RH): ");
    Serial.println(co2Sensor.getHumidity());
  }
  delay(5000); // the sensor itself only produces a new reading every 5s
}

I did not run this sketch on a board, it follows the library example.

Talking to the chip yourself

All commands are 16 bits and every data word has an 8-bit CRC (polynomial 0x31, start value 0xFF). Start periodic measurement, wait 5 seconds, ask whether data is ready and read nine bytes: CO2, temperature and humidity, each followed by its CRC.

uint8_t crc8(const uint8_t *d, int n) {
  uint8_t c = 0xFF;
  for (int i = 0; i < n; i++) {
    c ^= d[i];
    for (int b = 0; b < 8; b++)
      c = (c & 0x80) ? (c << 1) ^ 0x31 : (c << 1);
  }
  return c;
}

void cmd(uint16_t c) {
  Wire.beginTransmission(0x62);
  Wire.write(c >> 8); Wire.write(c & 0xFF);
  Wire.endTransmission();
}

bool ready() {
  cmd(0xE4B8);                            // get_data_ready_status
  delay(1);
  Wire.requestFrom(0x62, 3);
  uint16_t w = (Wire.read() << 8) | Wire.read(); Wire.read();
  return (w & 0x07FF) != 0;               // lower 11 bits zero = not ready
}

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);
  cmd(0x3F86); delay(500);                // stop, in case it is running
  cmd(0x21B1);                            // start_periodic_measurement
}

void loop() {
  if (ready()) {
    cmd(0xEC05); delay(1);                // read_measurement
    Wire.requestFrom(0x62, 9);
    uint8_t b[9];
    for (int i = 0; i < 9; i++) b[i] = Wire.read();
    if (crc8(b, 2) == b[2] && crc8(b + 3, 2) == b[5] && crc8(b + 6, 2) == b[8]) {
      uint16_t co2 = (b[0] << 8) | b[1];
      float t = -45.0f + 175.0f * ((b[3] << 8) | b[4]) / 65535.0f;
      float h = 100.0f * ((b[6] << 8) | b[7]) / 65535.0f;
      Serial.printf("%u ppm  %.2f C  %.1f %%RHn", co2, t, h);
    }
  }
  delay(1000);
}

This sketch has not been run on a board. The CRC routine is the same one as in the SHT sensors, where 0xBE 0xEF gives 0x92.

Commands

CommandWhat it does
0x21B1start_periodic_measurement (a new value every 5 s)
0xEC05read_measurement (1 ms, works during measurement)
0x3F86stop_periodic_measurement (wait 500 ms)
0xE4B8get_data_ready_status
0x21ACstart_low_power_periodic_measurement
0x241D / 0x2318set / get temperature offset (default 4 °C)
0x2427 / 0x2322set / get sensor altitude in metres (default 0)
0xE000set / get ambient pressure in pascal (70000 to 120000, default 101300)
0x362Fperform_forced_recalibration (400 ms)
0x2416 / 0x2313set / get automatic self-calibration enabled (default on)
0x3615persist_settings to EEPROM (800 ms)
0x3682get_serial_number
0x3639perform_self_test (10 s)
0x3632perform_factory_reset (1200 ms)
0x3646reinit (30 ms)
0x219Dmeasure_single_shot (SCD41, 5 s)
0x2196measure_single_shot_rht_only (SCD41, 50 ms)
0x36E0 / 0x36F6power_down / wake_up (SCD41, wake-up takes 30 ms)

The three values are CO2 [ppm] = word 0, T = −45 + 175 × word 1 / 65535 °C and RH = 100 × word 2 / 65535 %RH. Most settings can only be changed while the sensor is idle, so stop the periodic measurement first. Use persist_settings to keep a setting after a power cycle.

Source: Sensirion SCD4x datasheet, sections 3.4 to 3.10.

Calibration: ASC, altitude and pressure

Automatic self-calibration (ASC)

The ASC is on by default. It assumes the sensor sees fresh air with about 400 ppm CO2 at least once a week, and it corrects drift from that. If the sensor never sees fresh air (a sealed room, a greenhouse with CO2 enrichment, a bedroom that is always occupied), the ASC pulls the readings down and the values come out too low. Switch it off with 0x2416 in that case, or ventilate the room well once a week.

Forced recalibration

Put the sensor in outdoor air for several minutes, then send the forced recalibration command with the known value (about 400 to 420 ppm outside). Do this when you cannot rely on the ASC.

Altitude and pressure

CO2 readings depend on the air pressure. Set the altitude of your site once with 0x2427, or set the ambient pressure with 0xE000 when you have a pressure sensor, for example the BME280. Setting a pressure overrides the altitude.

Temperature offset

The chip heats itself, and the board around it heats it more. The default offset is 4 °C, valid values are 0 to 20 °C. Set the offset so the temperature and humidity match a reference thermometer, once the sensor has been running in its final enclosure. It only changes the temperature and humidity, not the CO2 value.

Source: Sensirion SCD4x datasheet, sections 3.6 and 3.7.

Getting accurate readings

  • Wait for the warm-up. The first value comes after 5 seconds, and full accuracy needs a few minutes. After assembly, the accuracy is restored by the ASC or a forced recalibration within about 5 days.
  • Do not breathe on it while you test. Your breath is several thousand ppm and the reading takes a while to fall.
  • Mount it in the air, not in a closed box. The response time of the CO2 reading depends on airflow around the membrane.
  • Keep it away from heat sources. Voltage regulators, displays and the ESP32 itself warm the board and raise the temperature and lower the humidity readings.
  • Use a stable supply. Keep the ripple under 30 mV.
  • Use the SCD41 single shot mode for batteries. One measurement every 5 minutes costs 0.45 mA on average instead of 15 mA.
  • Do not cover the membrane with tape, glue or coating.

Real gotchas

  • The accuracy is not a flat number. It is a number of ppm plus a percentage of the reading, and it differs between SCD40 and SCD41.
  • The ASC can drive the values wrong. If the sensor never sees about 400 ppm, either switch the ASC off or ventilate once a week.
  • The temperature reads too high. The chip and the board heat it. Set the temperature offset (default 4 °C) or the humidity will also be wrong.
  • Wrong altitude, wrong CO2. Set the altitude or the ambient pressure, otherwise the error grows with height above sea level.
  • Settings are lost without persist_settings. Write them to the EEPROM if they must survive a power cycle. The EEPROM has a limited number of writes, so do not do it in a loop.
  • Stop before you configure. Most commands only work while the sensor is idle. Send stop_periodic_measurement and wait 500 ms first.
  • A single 5 V supply is not always fine. The chip takes 2.4 to 5.5 V, but the I2C lines of your microcontroller must match the supply of the board.
  • The SCD40 has no single shot mode. The commands 0x219D and 0x2196 only exist on the SCD41.
  • Not a safety device. Do not use it as the only protection against dangerous CO2 levels, and it is not a carbon monoxide (CO) sensor.

Compared with other air sensors

SensorMeasuresGood forWeak point
SCD40 / SCD41CO2 (NDIR), temperature, humidityReal CO2 valuesAbout 15 mA, a few seconds per sample
BME280Temperature, humidity, pressureCheap, tinyNo CO2
SHT4xTemperature, humidityAccurate humidityNo CO2
MQ or eCO2 gas sensorsA gas guessCheapA calculated eCO2 is not a real CO2 measurement

See the BME280 guide for pressure, which also feeds the SCD4x pressure compensation, and the SHT40/SHT41 guide for accurate humidity. The last row is general knowledge and not from a datasheet read for this guide.

What to build with it

  • Indoor air quality monitoring: CO2 buildup is a genuine, well-studied proxy for how stale/poorly-ventilated a room is.
  • Demand-controlled ventilation: only run an extractor fan or HRV when CO2 actually rises.
  • Meeting-room/classroom monitors: a common, practical use case for this exact chip.
  • Greenhouse CO2 supplementation control: closing the loop on CO2 enrichment for plant growth.
  • A CO2 traffic light with three LEDs: green below 800 ppm, orange up to 1200 ppm, red above.
  • A HomeKit air-quality sensor on an ESP32.

Safety notes

Before you wire anything up

  • Keep the supply between 2.4 and 5.5 V, never above 6 V.
  • Check the pin order on your own breakout before you apply power.
  • Never connect the board to mains voltage.
  • A CO2 sensor is not a safety device. High CO2 makes you drowsy, and the sensor does not measure carbon monoxide or fire.
  • Do not use it for life-safety decisions such as an alarm in a confined space.

Conclusion

The SCD40 and SCD41 are real CO2 sensors that fit in a few square centimetres. Take the SCD41 for a wider range, better accuracy and a low-power single shot mode, and the SCD40 for an always-powered monitor. Set the altitude, the temperature offset, and decide on the ASC, then the readings can be trusted. Keep it away from heat and leave the membrane free.

Chip data is from the Sensirion SCD4x datasheet, version 1.5. The comparison row for gas sensors is general knowledge.

Advertisement
All guides

More guides

Keep building.

From ESP32 HomeKit accessories to Arduino and ATtiny reference guides, there’s more where this came from.

All guides