CO₂ Sensor¶
Written by Grace Lo & Rachel Yan
A previous version describing the python implementation of the sensor can be found here.
The CO₂ recording procedure was developed and tested on the Sensirion SCD30 CO₂ Sensor Module for measuring carbon dioxide (CO₂) concentration, temperature, and humidity. It is a digital sensor communicating over I²C and is pre-calibrated under controlled environmental conditions. The basic CO₂ sensor functionality, intialization and reading data is borrowed from the Sensirion embedded-i2c-scd30 library. The data is provided in standard units (eg. ppm for CO₂, °C for temperature, and %RH for humidity) with specifications provided below.
Sensor | Range | Accuracy |
---|---|---|
CO₂ | 0 - 40,000 ppm | ±30 ppm + 3 %MV |
Temperature | 0 - 100 %RH | ±3 %RH |
Humidity | -40 - 70 °C | ±(0.4°C + 0.023 × (T [°C] – 25°C)) |
Pin Connections¶
Breadboarding best practices should be followed.

Pin connections from the CO₂ sensor → Pico are as follows:
- VIN → 3V3(OUT) (pin 36)
- GND → GND
- SCL → I2C0_SCL (pin 17)
- SDA → I2C0_SDA (pin 16)
- SEL → floating for selecting I2C
Code¶
All code is in the CornellFluxChamber Github repository. The code for interfacing with the CO₂ sensor is incorporated into flux_chamber.c
.
Includes¶
The first lines of code in the C source file include header files. Don't forget to link these in the CMakeLists.txt file!
The following files are required to interface with the CO₂ sensor and are provided by the Sensirion embedded-i2c-scd30 library (refer to the parent library for a description about each header file).
#include <stdio.h>
#include "scd30_i2c.h"
#include "sensirion_common.h"
#include "sensirion_i2c_hal.h"
Initializations¶
The C source file initializes the CO₂ sensor's I²C Hardware Abstraction Layer (HAL) and configures the driver with the I²C address of the sensor, which sets up the communication interface between the sensor and the Pico.
int16_t error = NO_ERROR;
sensirion_i2c_hal_init();
init_driver(SCD30_I2C_ADDR_61);
Then it ensures the sensor starts in a clear and ready state by terminating all previous reading loops, sending a reset signal, and verifying the communication responsiveness of the sensor one last time, before setting up the sensor with the periodic measurement.
scd30_stop_periodic_measurement();
scd30_soft_reset();
sensirion_i2c_hal_sleep_usec(2000000);
uint8_t major = 0;
uint8_t minor = 0;
error = scd30_read_firmware_version(&major, &minor);
if (error != NO_ERROR) {
printf("error executing read_firmware_version(): %i\n", error);
return error;
}
printf("firmware version major: %u minor: %u\n", major, minor);
error = scd30_start_periodic_measurement(0);
if (error != NO_ERROR) {
printf("error executing start_periodic_measurement(): %i\n", error);
return error;
}
Read¶
The CO₂ sensor module is read using scd30_blocking_read_measurement_data(&co2,&temp, &hum)
and directly written to the file.
An example of the data logging to a CSV file is provided below:

Sensor Testing¶
The CO₂ sensor was tested by manipulating CO₂ concentrations, temperature, and humidity through a series of covering the sensor with a hand and blowing on it. Current lab testing has shown CO₂ readings ranging from approximately 300 ppm to over 6000 ppm, temperature ranging from 24-28 °C, and 45-70% relative humidity.
The example provided below shows a series of data measurements, 5 seconds apart, while altering the sensor's immediate environmental conditions.
