Project showcase

CO-CO2 Sensor v.2 © CC BY-NC-ND

Make an Arduino CO2 - CO sensor.

  • 2,860 views
  • 0 comments
  • 12 respects

Components and supplies

Necessary tools and machines

3drag
3D Printer (generic)

Apps and online services

About this project

Arduino CO2 - CO sensor

Have you ever felt tired, weak or asphyxiated? Maybe there are many people in a small place? If your answer is affirmative, the most probably cause is the Carbon Dioxide. This gas isn’t toxic but, at high concentrations, it makes you less productive (there are many studies and researches about this). I have noticed this problem when I was at school and I decided to solve it. This sensor can tell you when there is an excessive level of CO2 in your classroom, or in your office. At this point, to solve the problem, you can open the windows for a few minutes and change of air (ideal would be a ventilation system). In this article, I’m going to show you how to construct this sensor with Arduino for a minimal cost.

This is the second version of a my previous project. It’s more complex but it’s more complete than the first. The most important changes are: the add of an OLED display, the Carbon Monoxide Sensor (toxic gas that derives from incomplete combustions), the ventilation system and the possibility to record data. I have recorded the CO2 PPM in my classroom and this is the result. When we have opened the windows, the values have decreased until 400 PPM. Thanks to the RTC module, we know the time of a determined record.

What do we need?

  • 2 switches
  • 1 button
  • Fan 5V 30mm
  • Power bank (suggested)

In normal conditions, and outside, the level is nearly to 400 ppm (but, unfortunately, it is increasing rapidly as you can see on this website). The level of 1500 PPM can be considered a threshold value for work and concentration, then it is impossible to work to fullest potential (efficiency decrease about 50%) . Furthermore, the 3D printer is optional because you can make the case with another material. For those who want to print it, I suggest them to print with PLA.

Calibrating the sensor

To calibrate the CO sensor you can read the value near a car exhaust pipe (where there are about 60 PPM). Over this threshold value, a buzzer will sound acoustic signals.

For the code, you should download the library and replace the value with the current atmosphere ppm level (look up here). Then upload the code that I had shared, also changing here the current value. However, I added a mini-tutorial inside the code. If you are interested about how the MQ135 sensor works, you can visit the website of Davide Gironi.

Conclusions

You can download all the files from Thingiverse from the link in the list. Here is the first version!

I hope I was helpful and clear in the description, any clarification or suggestion is welcome. Thanks for reading the article!

Custom parts and enclosures

Thingiverse
https://www.thingiverse.com/thing:2422144

Schematics

Arduino schematics
Co2 sensor v2 bb 1 mkwuk7kg47

Code

Arduino codeArduino
//Sketch by Andrea Cescato
//Arduino CO2 Sensor - Bluetooth by AndriMaker98 is licensed under the Creative Commons - Attribution - Non-Commercial - Share Alike license.
#include "MQ135.h"    //Remember to modify the library with the current CO2 concentration (link: https://www.co2.earth/ )
#include "U8glib.h"
#include <SD.h>
#include <SPI.h>
#include <Wire.h>
#include "ds3231.h"
#include <stdio.h>
#define BUFF_MAX 128
#define BUFF2_MAX 128
#define BUFF3_MAX 128
#define BUFF4_MAX 128

//RTC module
uint8_t time[8];
char recv[BUFF_MAX];
unsigned int recv_size = 0;
unsigned long prev, interval = 5000;
float temperature;
void parse_cmd(char *cmd, int cmdsize);

//SD module
String stringOne;
String string="Data_";
int times=0;
int s;
File myFile;
int pinCS = 53;
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);

//Buzzer
int buzzer = 12;

//MQ135
int analogPin = 0;
MQ135 gasSensor = MQ135(A0);
#define RZERO 246 //Put your sensor outside and replace the value, here and in the library (230)
int i=0;
int a=0;
int x=0;
int val_co;
char tot;
int val=0;
double result;
int z=1;
double rzero;

void setup() {
  Serial.begin(9600);
  pinMode(8, OUTPUT);
  pinMode(buzzer,OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(5, INPUT);
  pinMode(pinCS, OUTPUT);

//Initialize SD card
  if (SD.begin()) {
    Serial.println("SD card is ready to use.");
  } 
  else {
    Serial.println("SD card initialization failed");
    x=2;
    return;
  }

//RTC setup
    Wire.begin();
    DS3231_init(DS3231_INTCN);
    memset(recv, 0, BUFF_MAX);
    memset(recv, 0, BUFF2_MAX);
    parse_cmd("T004715306072017", 16);  //SSMMHHNDDMMYYYY (EXAMPLE: Thursday 06.07.2017 15.24.30 = T302415406072017), N=Day of the week (Monday=1, Tuesday=2, etc...)                           
  
}
void loop() {
    
    char in;
    char buff[BUFF_MAX];
    char buff2[BUFF2_MAX];
    char buff3[BUFF3_MAX];
    char buff4[BUFF4_MAX];
    unsigned long now = millis();
    struct ts t;

if ((now - prev > interval) && (Serial.available() <= 0)) {
     DS3231_get(&t);

#ifdef CONFIG_UNIXTIME
        snprintf(buff, BUFF_MAX, "%d/%02d/%02d", t.mday, t.mon, t.year, t.unixtime);
#else
        snprintf(buff, BUFF_MAX, "%d/%02d/%02d", t.mday, t.mon, t.year);
#endif

#ifdef CONFIG_UNIXTIME
        snprintf(buff2, BUFF2_MAX, "%02d:%02d:%02d %ld", t.hour, t.min, t.sec, t.unixtime);
#else
        snprintf(buff2, BUFF2_MAX, "%02d:%02d:%02d", t.hour, t.min, t.sec);
#endif



#ifdef CONFIG_UNIXTIME
        snprintf(buff3, BUFF3_MAX, "%d%02d%02d", t.mday, t.mon, t.year, t.unixtime);
#else
        snprintf(buff3, BUFF3_MAX, "%d%02d%02d", t.mday, t.mon, t.year);
#endif

#ifdef CONFIG_UNIXTIME
        snprintf(buff4, BUFF4_MAX, "%02d%02d%02d %ld", t.hour, t.min, t.sec, t.unixtime);
#else
        snprintf(buff4, BUFF4_MAX, "%02d%02d%02d", t.hour, t.min, t.sec);
#endif

        temperature = DS3231_get_treg(); //Get temperature
        Serial.println("Air quality sensor");
        Serial.print("Temperature: ");
        Serial.println(temperature);
        Serial.print("Date: ");
        Serial.println(buff);
        Serial.print("Hour: ");
        Serial.println(buff2);
        prev = now;
    }

    if (Serial.available() > 0) {
        in = Serial.read();

        if ((in == 10 || in == 13) && (recv_size > 0)) {
            parse_cmd(recv, recv_size);
            recv_size = 0;
            recv[0] = 0;
        } else if (in < 48 || in > 122) {;       // ignore ~[0-9A-Za-z]
        } else if (recv_size > BUFF_MAX - 2) {   // drop lines that are too long
            // drop
            recv_size = 0;
            recv[0] = 0;
        } else if (recv_size < BUFF_MAX - 2) {
            recv[recv_size] = in;
            recv[recv_size + 1] = 0;
            recv_size += 1;
        }

    }

  
if(val_co>250) {
  tone(buzzer,500,1000);    
}
else {
}

  val = digitalRead(5);   
  if(x==2) {
    x=2;
  }
  else {
  if (val==HIGH) {  
    if (x==0) { 
    times=times+1;
    x=1;
    }
    else {
    x=0;
    z=z+1;
    }
  }  
  else {  
  x=x;
  }  
  }

 if (i==0) {
   rzero = gasSensor.getRZero(); 
 }
 if (i>0) {  
   result = gasSensor.getRZero();
   rzero = (rzero + result)/2;
  }
float ppm = gasSensor.getPPM();
Serial.print("CO2 RZERO Value: ");
Serial.println(rzero);
Serial.print("CO2 concentration: ");
Serial.print(ppm);
Serial.println(" PPM");
val_co=analogRead(1);
Serial.print("CO value: ");
Serial.println(val_co);
i++;

if (ppm>1000) {
    if (ppm>1500) {
      digitalWrite(7, HIGH);   //Red LED activated (PPM>1500)
      digitalWrite(8, LOW);
    }
    else {
      digitalWrite(8, HIGH);    //Yellow LED activated (PPM>1000)
      digitalWrite(7, LOW);
    }
  }
    else {
      digitalWrite(7, LOW);
      digitalWrite(8, LOW);
    }

a=ppm;
u8g.firstPage(); 
 do {
  if(x==1) {
    u8g.setFont(u8g_font_gdr9r);
    u8g.drawStr(80, 20, "REC");
  }
  else {
    if(x==2) {
    u8g.setFont(u8g_font_gdr9r);
    u8g.drawStr(80, 20, "NO SD");
  }
  else {
    
  }
  }

u8g.setFont(u8g_font_gdr9r);
u8g.drawStr(83, 44, "CO");
u8g.setFont(u8g_font_gdr9r);
u8g.drawStr(98, 44, " 2");
u8g.setFont(u8g_font_gdr14r);
u8g.drawStr(80, 57, " ppm");
char buf[9];
u8g.setFont(u8g_font_gdr25r);
sprintf (buf, "%d", a);
u8g.drawStr(0, 62, buf);
int b=temperature;
u8g.setFont(u8g_font_gdr14r);
sprintf (buf, "%d", b);
u8g.drawStr(0, 20, buf);
u8g.setFont(u8g_font_gdr9r);
u8g.drawStr(24, 8, "o");


  } while( u8g.nextPage() );
    
if(x==1) {
    stringOne = String(string + times + ".txt"); 
    Serial.println(stringOne);   
    myFile = SD.open(stringOne.c_str(), FILE_WRITE);  
    Serial.println("Record");
    myFile.print(buff2);
    myFile.print(",");    
    myFile.println(a);
    myFile.close(); // close the file
}
else {
  
}
Serial.println("------------------");

delay(5000);

}


void parse_cmd(char *cmd, int cmdsize)
{
    uint8_t i;
    uint8_t reg_val;
    char buff[BUFF_MAX];
    struct ts t;

    //snprintf(buff, BUFF_MAX, "cmd was '%s' %d\n", cmd, cmdsize);
    //Serial.print(buff);

    // TssmmhhWDDMMYYYY aka set time
    if (cmd[0] == 84 && cmdsize == 16) {
        //T355720619112011
        t.sec = inp2toi(cmd, 1);
        t.min = inp2toi(cmd, 3);
        t.hour = inp2toi(cmd, 5);
        t.wday = cmd[7] - 48;
        t.mday = inp2toi(cmd, 8);
        t.mon = inp2toi(cmd, 10);
        t.year = inp2toi(cmd, 12) * 100 + inp2toi(cmd, 14);
        DS3231_set(t);
        Serial.println("OK");
    } else if (cmd[0] == 49 && cmdsize == 1) {  // "1" get alarm 1
        DS3231_get_a1(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 50 && cmdsize == 1) {  // "2" get alarm 1
        DS3231_get_a2(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 51 && cmdsize == 1) {  // "3" get aging register
        Serial.print("aging reg is ");
        Serial.println(DS3231_get_aging(), DEC);
    } else if (cmd[0] == 65 && cmdsize == 9) {  // "A" set alarm 1
        DS3231_set_creg(DS3231_INTCN | DS3231_A1IE);
        //ASSMMHHDD
        for (i = 0; i < 4; i++) {
            time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // ss, mm, hh, dd
        }
        uint8_t flags[5] = { 0, 0, 0, 0, 0 };
        DS3231_set_a1(time[0], time[1], time[2], time[3], flags);
        DS3231_get_a1(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 66 && cmdsize == 7) {  // "B" Set Alarm 2
        DS3231_set_creg(DS3231_INTCN | DS3231_A2IE);
        //BMMHHDD
        for (i = 0; i < 4; i++) {
            time[i] = (cmd[2 * i + 1] - 48) * 10 + cmd[2 * i + 2] - 48; // mm, hh, dd
        }
        uint8_t flags[5] = { 0, 0, 0, 0 };
        DS3231_set_a2(time[0], time[1], time[2], flags);
        DS3231_get_a2(&buff[0], 59);
        Serial.println(buff);
    } else if (cmd[0] == 67 && cmdsize == 1) {  // "C" - get temperature register
        Serial.print("temperature reg is ");
        Serial.println(DS3231_get_treg(), DEC);
    } else if (cmd[0] == 68 && cmdsize == 1) {  // "D" - reset status register alarm flags
        reg_val = DS3231_get_sreg();
        reg_val &= B11111100;
        DS3231_set_sreg(reg_val);
    } else if (cmd[0] == 70 && cmdsize == 1) {  // "F" - custom fct
        reg_val = DS3231_get_addr(0x5);
        Serial.print("orig ");
        Serial.print(reg_val,DEC);
        Serial.print("month is ");
        Serial.println(bcdtodec(reg_val & 0x1F),DEC);
    } else if (cmd[0] == 71 && cmdsize == 1) {  // "G" - set aging status register
        DS3231_set_aging(0);
    } else if (cmd[0] == 83 && cmdsize == 1) {  // "S" - get status register
        Serial.print("status reg is ");
        Serial.println(DS3231_get_sreg(), DEC);
    } else {
        Serial.print("unknown command prefix ");
        Serial.println(cmd[0]);
        Serial.println(cmd[0], DEC);
    }
}

Comments

Similar projects you might like

Arduino Obstacle Avoidance Robot with Ultrasonic HC-SR04

Project tutorial by Jorge Rancé

  • 536 views
  • 1 comment
  • 9 respects

Using Finite State Machines

by Gustavo Gonnet

  • 6,381 views
  • 2 comments
  • 19 respects

Alexa: "Your Clothes Are Dry"

Project in progress by TNunnster

  • 1,537 views
  • 0 comments
  • 5 respects

How to Configure NeoPixels Using Vixen Lights and Arduino

Project tutorial by Victor Aguilar

  • 270 views
  • 0 comments
  • 3 respects

Temperature Streaming with Arduino + Big Data Tools

Project showcase by Gabriel Rodriguez

  • 1,485 views
  • 1 comment
  • 16 respects

Bluetooth Speaker w/ Music-Reactive LED Matrix

Project tutorial by Modustrial Maker

  • 3,423 views
  • 0 comments
  • 14 respects
Add projectSign up / Login