SCD41 CO2 sensor
The Sensirion SCD41 measures real CO2 in ppm, with temperature and humidity, over I2C at 0x62, one reading every five seconds.
Aliases: SCD40, SCD4x, Adafruit SCD-41, Qwiic CO2 sensor. It is the sensor of classroom air monitors and ventilation alarms: unlike the eCO2 figure a gas sensor estimates, it counts CO2 molecules by the sound they make when a light pulse warms them.
Pins
| Pin | What it does |
|---|---|
VIN |
Supply, 2.4 to 5.5 V. |
GND |
Ground. |
SCL |
I2C clock. The board carries the pull-ups. |
SDA |
I2C data. |
Properties
co2 (ppm), temperature (degrees C, -10 to 60) and humidity (%RH) are the room;
the three sliders change them while the circuit runs.
Reading it on an Arduino
With Sensirion's library, which Mokxi ships as SensirionI2cScd4x.h:
#include <Wire.h>
#include <SensirionI2cScd4x.h>
SensirionI2cScd4x sensor;
void setup() {
Serial.begin(9600);
Wire.begin();
sensor.begin(Wire, SCD41_I2C_ADDR_62);
sensor.stopPeriodicMeasurement();
sensor.startPeriodicMeasurement();
}
void loop() {
bool ready = false;
sensor.getDataReadyStatus(ready);
if (ready) {
uint16_t co2;
float t, rh;
sensor.readMeasurement(co2, t, rh);
Serial.println(co2);
}
delay(1000);
}
How it talks
Commands are sixteen bits, high byte first. A command with an argument carries a word and its CRC; one with a response is followed by a read of words, each with its CRC.
- Power on takes 30 ms before the address is acknowledged.
- start_periodic_measurement (
0x21B1) gives the first result 5 s later and then one every 5 s. get_data_ready_status (0xE4B8) says when; read_measurement (0xEC05) returns CO2, temperature and humidity, and a read with no new result is refused. - stop_periodic_measurement (
0x3F86) takes 500 ms, during which nothing answers. While a measurement runs only reading, data ready, stop and the ambient pressure are taken. - measure_single_shot (
0x219D, 5 s) and the humidity-only shot (0x2196, 50 ms) are the SCD41's; power_down and wake_up put it to sleep and back. - The temperature offset, altitude, ambient pressure, self-calibration and the forced recalibration are held and read back; persist_settings keeps them for reinit.
T = -45 + 175 x S / 65536andRH = 100 x S / 65536.
What it does not model
The photoacoustic measurement's noise, and the effect of altitude, pressure and the temperature offset on the result: a reading is the slider's CO2 plus any forced recalibration's correction.
Common mistakes
Asking for anything but a reading while a periodic measurement runs: send
stopPeriodicMeasurement() and wait 500 ms first. Reading faster than every 5 s: the
second read in a period has nothing new and is refused.