Example Code for Arduino-CO2 Concentration Measurement

Last revision 2026/01/12

This tutorial is designed for you to learn how to use the infrared CO2 sensor to measure the current CO2 concentration in the air in 5 minutes.

Sample Code

/*!
 * @file  CO2SensorPWMInterface.ino
 * @brief  This example The sensors detect CO2
 * @details  Infrared CO2 Sensor range : 400-4980ppm
 * @copyright  Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
 * @license  The MIT License (MIT)
 * @author  [qsjhyy]([email protected])
 * @version  V2.0
 * @date  2023-01-15
 */

#if defined(ESP32) || defined(ESP8266)
  // D7 pin is used as interrupt pin by default, other non-conflicting pins can also be selected as external interrupt pins.
  #define SENSOR_DATA_PIN   (D7)   // Sensor PWM interface
  #define INTERRUPT_NUMBER   digitalPinToInterrupt(SENSOR_DATA_PIN)   // interrupt number
#elif defined(ARDUINO_SAM_ZERO)
  // Pin 5 is used as interrupt pin by default, other non-conflicting pins can also be selected as external interrupt pins
  #define SENSOR_DATA_PIN   (5)   // Sensor PWM interface
  #define INTERRUPT_NUMBER   digitalPinToInterrupt(SENSOR_DATA_PIN)   // interrupt number
#else
  /* The Correspondence Table of AVR Series Arduino Interrupt Pins And Terminal Numbers
   * ---------------------------------------------------------------------------------------
   * |                                        |  DigitalPin  | 2  | 3  |                   |
   * |    Uno, Nano, Mini, other 328-based    |--------------------------------------------|
   * |                                        | Interrupt No | 0  | 1  |                   |
   * |-------------------------------------------------------------------------------------|
   * |                                        |    Pin       | 2  | 3  | 21 | 20 | 19 | 18 |
   * |               Mega2560                 |--------------------------------------------|
   * |                                        | Interrupt No | 0  | 1  | 2  | 3  | 4  | 5  |
   * |-------------------------------------------------------------------------------------|
   * |                                        |    Pin       | 3  | 2  | 0  | 1  | 7  |    |
   * |    Leonardo, other 32u4-based          |--------------------------------------------|
   * |                                        | Interrupt No | 0  | 1  | 2  | 3  | 4  |    |
   * |--------------------------------------------------------------------------------------
   * ---------------------------------------------------------------------------------------------------------------------------------------------
   *                      The Correspondence Table of micro:bit Interrupt Pins And Terminal Numbers
   * ---------------------------------------------------------------------------------------------------------------------------------------------
   * |             micro:bit                       | DigitalPin |P0-P20 can be used as an external interrupt                                     |
   * |  (When using as an external interrupt,      |---------------------------------------------------------------------------------------------|
   * |no need to set it to input mode with pinMode)|Interrupt No|Interrupt number is a pin digital value, such as P0 interrupt number 0, P1 is 1 |
   * |-------------------------------------------------------------------------------------------------------------------------------------------|
   */
  // Open the external interrupt 0, connect INT1/2 to the digital pin of the main control: 
  // UNO(2), Mega2560(2), Leonardo(3), microbit(P0).
  #define SENSOR_DATA_PIN   (2)   // Sensor PWM interface
  #define INTERRUPT_NUMBER   (0)   // interrupt number
#endif

// Used in interrupt, calculate pulse width variable
volatile unsigned long pwmHighStartTicks=0, pwmHighEndTicks=0;
volatile unsigned long pwmHighVal=0, pwmLowVal=0;
// interrupt flag
volatile uint8_t flag=0;

void interruptChange()
{
  if (digitalRead(SENSOR_DATA_PIN)) {
    pwmHighStartTicks = micros();    // store the current micros() value
    if(2 == flag){
      flag = 4;
      if(pwmHighStartTicks > pwmHighEndTicks) {
        pwmLowVal = pwmHighStartTicks - pwmHighEndTicks;
      }
    }else{
      flag = 1;
    }
  } else {
    pwmHighEndTicks = micros();    // store the current micros() value
    if(1 == flag){
      flag = 2;
      if(pwmHighEndTicks > pwmHighStartTicks){
        pwmHighVal = pwmHighEndTicks - pwmHighStartTicks;
      }
    }
  }
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("beginning...");
  pinMode(SENSOR_DATA_PIN, INPUT);
  attachInterrupt(INTERRUPT_NUMBER, interruptChange, CHANGE);
}

void loop() {
  if(flag == 4){
    flag = 1;
    float pwmHighVal_ms = (pwmHighVal * 1000.0) / (pwmLowVal + pwmHighVal);

    if (pwmHighVal_ms < 0.01){
      Serial.println("Fault");
    }
    else if (pwmHighVal_ms < 80.00){
      Serial.println("preheating");
    }
    else if (pwmHighVal_ms < 998.00){
      float concentration = (pwmHighVal_ms - 2) * 5;
      // Print pwmHighVal_ms
      Serial.print("pwmHighVal_ms:");
      Serial.print(pwmHighVal_ms);
      Serial.println("ms");
      //Print CO2 concentration
      Serial.print(concentration);
      Serial.println("ppm");
    }else{
      Serial.println("Beyond the maximum range : 398~4980ppm");
    }
    Serial.println();
  }
}

Result

Please wait at least 3 minutes (preheat process) until the data is stable. At this time, the sensor can display the CO2 concentration.

Was this article helpful?

ON THIS PAGE

TOP