Get Adobe Flash player
English Arabic French German Italian Portuguese Russian Spanish

Did you know?

Mobile phones will be discarded at a rate of 130 million since 2005, resulting in 65,000 tons of waste

Help us stay online:

small donate

logo IRC-A1More information about NDIR sensors are avaiable in article Non-Dispersive Infrared (NDIR) gas sensors. The IR gas sensor contains a lamp which is pulsed at low frequency by a lamp drive circuit. The pulses of infrared radiation reflect internally to provide a long path through the target gas. Pyroelectric detectors (pyros) are used to detect the change in infrared signal. The active pyro is sensitive to changes at IR wavelengths which are typically absorbed by the gas being detected. The reference pyro is sensitive to changes at a nearby IR wavelength which is not absorbed by the gas being detected.

The small pyro output signals are approximately sawtooth in shape and must be amplified and filtered. A bandpass amplifiers used to pass only the fundamental frequency and reduce any pyro noise at other frequencies. The amplifier outputs are roughly sinusoidal in shape.
The analog to digital converter (ADC) samples the maximum and minimum of the amplifier outputs to determine the peak-to-peak level. The ratio of peak-to-peak levels for the active and reference channel is used by the microprocessor calculate the actual gas concentration.
Both pyros are also sensitive to background temperature and a temperature sensoris necessary so that the microprocessor can compensate the pyro outputs for the effects of ambient temperature. That is the reason for presence of temperature sensor inside of NDIR sensor body.
Block Diagram of Typical Gas Detection System using Infrared Gas Sensor is shown on picture.

block diagram

Lamp drive. The infrared source should be switched at a low frequency with a 50% duty cycle. A switching frequency of 2 to 2.5Hz, derived from a crystal oscillator source is recommended. The source should be driven from a constant voltage source and care should be taken to ensure the supply does not contain low frequency ripple that would otherwise modulate the output. The nominal resistance of the source is approximately 9 to 10 Ohms at ambient temperatures and will draw approximately 50 to 60 mA at 5 V.

Detector Signal Amplification and Filtering. The raw active and reference signals are composed of a DC offset voltage (typically 0.7 V - 1.0 V) with a small (~20 - 50 mV peak-to-peak) superimposed response signal alternating in phase with the source drive voltage. The alternating signal should be extracted and amplified in order to obtain a measure of the peak-to-peak amplitude of this oscillating component. This peak-to-peak amplitude can then be used to determine the gas concentration. For more information read Application Note about this sensor.

A suitable circuit for driving an Alphasense IRC-A1 sensor is shown in following picture.

sch ndir electronics-base

There are two identical detector FET's inside the dual sensor pyro-electric detector. The CO2 detector will respond to changes in CO2 levels while the reference will be substantially unaffected by CO2 levels. Both detectors will be affected by ambient temperature and the IR source luminosity and appropriate processing of both channels will alleviate these unwanted effects.
The detector FET’s are arranged as source followers. The load resistors (R1 and R2 on picture) should be set to give approximately 30 µA bias current in the FET’s. The nominal output voltage on the FET sources is between 0.6 and 1.2 V.
The frequencies need not be exact, but both detectors (reference and active) should have matching characteristics. The detectors will have a typical output of 45 mV peak-to-peak so the circuit should provide sufficient gain to give a reasonable input to any ADC used. The circuit shown in Figure 2 will give approximately 3 V peak-to-peak. Next picture shows results after filtering and amplification. More about hardware realisation read HERE.

after filtering NDIR

Thermistor Output. The sensor includes an integral thermistor to monitor the internal temperature. Internally, the thermistor is connected to AGND. The thermistor output should be connected in series with a known resistor and reference voltage. The potential at the junction between the resistors can then be used to determine the thermistor resistance and the temperature. Some values are given in table. In our realization resistor R11 of 10kOhm (0.1%) is used.

thermistor table

Software realisation. We recommend you to read articles about UART and ADC of dsPIC30F4013 if you are unfamiliar with this microcontoller. Here are the important sourse files.


//global variables
extern unsigned int NDIR_CO2_TIMER_LAMP;   //timer for generating lamp signal
extern unsigned char NDIR_CO2_FLAG_LAMP;   //flag for generating lamp signal of 2Hz
extern unsigned int NDIR_CO2_TIMER_ADC;    //timer for ADC conversion in right moment
extern unsigned char NDIR_CO2_FLAG_ADC;    //flag for assuring that value is taken when lamp in ON
extern int NDIR_CO2_ADC_CO2_MIN; //minimum ADC value for CO2 channel
extern int NDIR_CO2_ADC_CO2_MAX; //maximum ADC value for CO2 channel
extern int NDIR_CO2_ADC_REF_MIN; //minimum ADC value for REF channel
extern int NDIR_CO2_ADC_REF_MAX; //maximum ADC value for REF channel
extern int NDIR_CO2_ADC_TERM;    //ADC value of Thermistor
void Init_NDIR_CO2 (void);
void NDIR_LAMP_ON (void); //enable that LAMP works at 2Hz
void NDIR_LAMP_OFF (void);
void NDIR_ADC_TO_GLOBAL_ON (void); //enable to copy value from ADC to global variables NDIR_CO2_ADC_CO2_MIN... etc

It is important to take value at the right time. Since signal is AC type, we need to calculate peak-to-peak value, or we take maximum and minimum value and just substruct them. There is a delay between the bulb switching point and the maximum or minimum of the signal response.

time delay ndir

This delay is typically around 25 ms but will depend on the model of gas sensor being used. In our example this delay is given as #define IR_CO2_ADC_DELAY 220 (highlight in main.c), so it is 220ms and this value is calculated using oscilloscop (see waveform picture). Note that we first take maximum than minimum value, that's why our delay is much bigger, but result is same.



#include "NDIR_CO2.h"
//INITIALIZATION of global variables
unsigned int NDIR_CO2_TIMER_LAMP = 0;   //timer for generating lamp signal
unsigned char NDIR_CO2_FLAG_LAMP = 0;   //flag for generating lamp signal of 2Hz
unsigned int NDIR_CO2_TIMER_ADC = 0;    //timer for ADC conversion in right moment
unsigned char NDIR_CO2_FLAG_ADC = 0;    //flag for assuring that value is taken when lamp in ON
int NDIR_CO2_ADC_CO2_MIN = 0; //minimum ADC value for CO2 channel
int NDIR_CO2_ADC_CO2_MAX = 0; //maximum ADC value for CO2 channel
int NDIR_CO2_ADC_REF_MIN = 0; //minimum ADC value for REF channel
int NDIR_CO2_ADC_REF_MAX = 0; //maximum ADC value for REF channel
int NDIR_CO2_ADC_TERM = 0;    //ADC value of Thermistor
void Init_NDIR_CO2 (void)
    TRISDbits.TRISD8 = 0; //RD8 is digital output gor LAMP
    LATDbits.LATD8 = 0;
    ADPCFGbits.PCFG10=0; //Pin RB10 is analogue CO2 channel
    TRISBbits.TRISB10=1; //PB10 is input
    ADPCFGbits.PCFG11=0; //Pin RB11 is analogue REF channel
    TRISBbits.TRISB11=1; //PB11 is input
    ADPCFGbits.PCFG12=0; //Pin RB12 is analogue for Thermistor
    TRISBbits.TRISB12=1; //PB12 is input
    NDIR_CO2_FLAG_ADC = 0; //flag initialization, if zero, lamp doesn't work
    NDIR_CO2_FLAG_LAMP = 0; //flag initialization, if zero, no value from ADC is taken into global values
void NDIR_LAMP_ON (void)
    LATDbits.LATD8 = 0;
void NDIR_LAMP_OFF (void)
    LATDbits.LATD8 = 0;
    NDIR_CO2_FLAG_ADC = 1;
    NDIR_CO2_FLAG_ADC = 0;

All important work is done in timer routine. When NDIR_CO2_FLAG_LAMP flag is active, lamp works at 2Hz. Other flag (NDIR_CO2_FLAG_ADC) is used for storing ADCs values in global variables at precise moments.


#include <string.h>
#include "uart.h"
#include "adc.h"
#include "NDIR_CO2.h"
_FOSC(CSW_FSCM_OFF & FRC_PLL4); //7.37 MHz Internal RC oscillator, 4x PLL enabled
_FWDT(WDT_OFF);                 //Watchdog disabled
#define IR_CO2_ADC_DELAY 220  //IMPORTANT this value is calculated as time difference between
                              //maximium and minimum output signal - use oscilloscop to calculate this
int tempRX, tempRX2;
char buf[10];
int data0, data1, data2;
unsigned int ms_counter;
void __attribute__((__interrupt__)) _U1RXInterrupt(void)
    IFS0bits.U1RXIF = 0;
    tempRX = U1RXREG;
void __attribute__((__interrupt__)) _U2RXInterrupt(void) {
    IFS1bits.U2RXIF = 0;
    tempRX2 = U2RXREG;
void __attribute__((__interrupt__)) _T1Interrupt(void) // svakih 1ms
// prekidna rutina Thajmera 1
    TMR1 = 0;
    ms_counter++; //used in Delay_ms() function
    if (NDIR_CO2_TIMER_LAMP == 250)
        if(NDIR_CO2_FLAG_LAMP == 1)
            LATDbits.LATD8 =~ LATDbits.LATD8;
        NDIR_CO2_TIMER_LAMP = 0;
        NDIR_CO2_ADC_TERM = data2;
        NDIR_CO2_ADC_CO2_MAX = data0;
        NDIR_CO2_ADC_REF_MAX = data1;
    if((NDIR_CO2_TIMER_ADC == (IR_CO2_ADC_DELAY+250)) && (NDIR_CO2_FLAG_ADC == 1))
        NDIR_CO2_ADC_TERM = data2;
        NDIR_CO2_ADC_CO2_MIN = data0;
        NDIR_CO2_ADC_REF_MIN = data1;
        NDIR_CO2_TIMER_ADC = 0;
    IFS0bits.T1IF = 0;
void __attribute__((__interrupt__)) _ADCInterrupt(void) {
    data0 = ADCBUF0; //RB10 CO2 channel
    data1 = ADCBUF1; //RB11 REF chanell
    data2 = ADCBUF2; //RB12 Thermistor channel
    IFS0bits.ADIF = 0;  //After conversion ADIF is set to 1 and must be cleared
void Delay_ms(unsigned int vreme) //For counting time in ms
    ms_counter = 0;
    while (ms_counter < vreme);
int main(void)
    ADCON1bits.ADON = 1; //start ADC conversion
    Init_NDIR_CO2(); //Don't forget to call initialization
    WriteStringUART2("NDIR CO2 Alphasense IRC-A1 gas sensor example\r");  // \r is ENTER
    Delay_ms(5000);//5s delay
    while (1)
        Delay_ms(1000);//1s delay
        NDIR_ADC_TO_GLOBAL_ON(); //now we enable to taking value from ADC and store it to globals
        Delay_ms(5000); //let lamp works 5s
        //write values to UART2
        WriteStringUART2("  TH: ");
        WriteStringUART2("  CO2: ");
        WriteStringUART2("  Ref: ");
        WriteUART2(13); //ENTER
    return 0;

Calculated values are send via UART to Terminal software like it shown on picture. When concentration of CO2 insreases, voltage output from CO2 channell will decrease. This variation is proportional to gas concentration. Whole MPLAB X IDE 1.5 project can be downloaded HERE

Terminal NDIR