Saturday, March 29, 2014

CO (Carbon Monoxide) Gas Sensor Using the Arduino Uno

This simple project uses the Arduino Uno and the MQ7 Gas Sensor to sense the concentration of CO (Carbon Monoxide) in the air. The MQ7 requires a heater voltage that cycles between 5v (60s) and 1.4v (90s), drawing approximately 150mA at 5v which exceeds the power capacity of the Uno, so I use the KA278RA05C adjustable voltage regulator to drive this. The default voltage of the KA278RA05C with Vadj (pin 4) disconnected is 5v which serves for the heater high voltage part of the cycle. I use a 50k potentiometer to adjust the voltage down to 1.4v for the heater high voltage part of the cycle. I use an LH1546 optical solid state relay to switch the adjustable voltage of the potentiometer on for the 1.4v heater low voltage. Pin 8 on the Arduino Uno drives the optical solid state relay and when high turns the relay on, adjusting the voltage of the regulator down to 1.4v. When this pin is low it turns off the relay causing the regulator to go back up to 5v. Analog pin 0 on the Arduino Uno is used to sense the voltage level out of the MQ7 which serves to measure the concentration of CO (Carbon Monoxide) in the air. Below is the diagram of the circuit on Fritzing.

Below is the actual circuit:

Below is the Arduino Uno sketch used:

#define VOLTAGE_REGULATOR_DIGITAL_OUT_PIN 8
#define MQ7_ANALOG_IN_PIN 0

#define MQ7_HEATER_5_V_TIME_MILLIS 60000
#define MQ7_HEATER_1_4_V_TIME_MILLIS 90000

#define GAS_LEVEL_READING_PERIOD_MILLIS 1000

unsigned long startMillis;
unsigned long switchTimeMillis;
boolean heaterInHighPhase;

void setup(){
  Serial.begin(19200);
  
  pinMode(VOLTAGE_REGULATOR_DIGITAL_OUT_PIN, OUTPUT);
  
  startMillis = millis();
  
  turnHeaterHigh();
  
  Serial.println("Elapsed Time (s), Gas Level");
}

void loop(){
  if(heaterInHighPhase){
    // 5v phase of cycle. see if need to switch low yet
    if(millis() > switchTimeMillis) {
      turnHeaterLow();
    }
  }
  else {
    // 1.4v phase of cycle. see if need to switch high yet
    if(millis() > switchTimeMillis) {
      turnHeaterHigh();
    }
  }
  
  readGasLevel();
  delay(GAS_LEVEL_READING_PERIOD_MILLIS);
}

void turnHeaterHigh(){
  // 5v phase
  digitalWrite(VOLTAGE_REGULATOR_DIGITAL_OUT_PIN, LOW);
  heaterInHighPhase = true;
  switchTimeMillis = millis() + MQ7_HEATER_5_V_TIME_MILLIS;
}

void turnHeaterLow(){
  // 1.4v phase
  digitalWrite(VOLTAGE_REGULATOR_DIGITAL_OUT_PIN, HIGH);
  heaterInHighPhase = false;
  switchTimeMillis = millis() + MQ7_HEATER_1_4_V_TIME_MILLIS;
}

void readGasLevel(){
  unsigned int gasLevel = analogRead(MQ7_ANALOG_IN_PIN);
  unsigned int time = (millis() - startMillis) / 1000;
  
  Serial.print(time);
  Serial.print(",");
  Serial.println(gasLevel);
}



The screenshot below shows the CSV data points of time in seconds against the MQ7 output voltage graphed into Excel.

The point at which to read the MQ7 level is at the end of the high 5v heating phase just before transitioning to the low 1.4v heating voltage. I found mine stabilized in an indoor home environment around 211 after the second heating cycle, corresponding to an analog voltage out of the MQ7 of (211/2013) * 5v = 1.03v. To calibrate I'll need a CO gas meter. Next item on the purchase list :-) Enjoy. Feel free to post below if you build some additional cool stuff on this.

If you are interested in how this type of sensor can be integrated into a broader solution that includes notification of carbon monoxide on a users Android phone see Receive Alert of High Carbon Monoxide Level