Hi all,
I was looking for a library for MQ7 carbon monoxide gas sensor but I don't found somethings usefull for me. Perhaps I don't see it...
So, I've created a new library. Open to discussion and ameliorations.
The hardware :
I used MQ7 gas sensor v1.3 (see attachment), thinking it was ready to use. But not. Reverse engineering is necessary to found electronic plan (see attachment). The board must be modified to respect documentation of MQ7 like indicated on the plan and the photo.
Dual power supply (+5V and +1.4V) can be realised with LM317 regulator voltage (see attachment).
The output is connected to VCC of the MQ7 board. So, VRL will be powered by 5V AND 1.4 V. Like measures are done on just before the low heating phase, it's not important.
The library :
/*
MQ7_LG.h - Library for MQ7 Monoxide Gas Sensor v1.3 hardware.
Created by Laurent Gibergues, January 21, 2015
Released into the public domain.
Hardware v1.3 need modification : see documentation please
*/
#ifndef MQ7_LG_h
#define MQ7_LG_h
#include <inttypes.h>
class MQ7_LG {
public :
MQ7_LG(uint8_t VRLPin, uint8_t HeaterCtrlPin, int8_t DOutPin = -1, int8_t HeaterVoltagePin = -1);
void init();
void run();
int read();
float getVRL();
int getDOut();
float getHeaterVoltage();
typedef enum states {HIGH_HEATING = 0, LOW_HEATING} state_t;
private :
int _ppmCO;
uint8_t _VRLPin;
uint8_t _heaterCtrlPin;
int8_t _DOutPin;
int8_t _heaterVoltagePin;
bool _HeaterVoltageIsConnected;
bool _DOutIsConnected;
state_t _state;
unsigned long _prevTime;
//functions
int toPpm(float VRL);
// Specifics data
const static unsigned long HIGH_HEATING_TIME = 60 * 1000L; // ms
const static unsigned long LOW_HEATING_TIME = 90 * 1000L; // ms
const static unsigned RL = 10000; // Ohms
const static unsigned R0 = 2000; // Ohms
const static float VCC_HEATER = 5.29; // Volts
const static float COEF_A = -1.6; // See MQ7 documentation :
const static float CONSTANT_B = 100; // log(ppmCO) = COEF_A * log(Rs/R0) + log(CONSTANT_B)
};
#endif
And the implementation :
#include <Arduino.h>
#include "MQ7_LG.h"
MQ7_LG::MQ7_LG(uint8_t VRLPin, uint8_t HeaterCtrlPin, int8_t DOutPin, int8_t HeaterVoltagePin)
: _VRLPin(VRLPin), _heaterCtrlPin(HeaterCtrlPin), _DOutPin(DOutPin), _heaterVoltagePin(HeaterVoltagePin) {
}
void MQ7_LG::init() {
_ppmCO = -1;
pinMode(_heaterCtrlPin, OUTPUT);
if (_DOutPin != -1) {
pinMode(_DOutPin, INPUT);
_DOutIsConnected = true;
}
else
_DOutIsConnected = false;
if (_heaterVoltagePin != -1)
_HeaterVoltageIsConnected = true;
else
_HeaterVoltageIsConnected = false;
// Start High Heating
digitalWrite(_heaterCtrlPin, LOW);
_state = HIGH_HEATING;
_prevTime = millis();
}
void MQ7_LG::run() {
unsigned long time = millis();
if (_state == HIGH_HEATING) {
if (time - _prevTime >= HIGH_HEATING_TIME) {
_ppmCO = toPpm(getVRL());
_state = LOW_HEATING;
digitalWrite(_heaterCtrlPin, HIGH);
_prevTime = time;
}
}
else {
if (time - _prevTime >= LOW_HEATING_TIME) {
_state = HIGH_HEATING;
digitalWrite(_heaterCtrlPin, LOW);
_prevTime = time;
}
}
}
float MQ7_LG::getVRL() {
float v;
v = analogRead(_VRLPin);
v = map(v, 0, 1024, 0, (int)(VCC_HEATER * 1000));
return v / 1000;
}
int MQ7_LG::getDOut() {
if (_DOutIsConnected)
return digitalRead(_DOutPin);
else
return -1;
}
float MQ7_LG::getHeaterVoltage() {
float v;
if (_HeaterVoltageIsConnected) {
v = analogRead(_heaterVoltagePin);
v = map(v, 0, 1024, 0, 10000); // Heater voltage measure is divided by 2 by hardware
v /= 1000;
}
else
v = -1;
return v;
}
int MQ7_LG::read() {
return _ppmCO; // -1 if data not available (during 60s after initialisation)
}
int MQ7_LG::toPpm(float VRL) {
return (int)(CONSTANT_B * pow((((float)RL / R0) * ((VCC_HEATER / VRL) - 1)), COEF_A));
}
An example :
/*
MQ7_LG_test.ino
MQ7_LG test library
The circuit:
* MQ7 gas sensor v1.3 or other
* VRL at analog input A0
* digital controlled supply on output pin 4
Optionaly :
* 1/2 of VCC connected on A3 by a resistor divider
* DOUT on pin 5
Created 21 january 2015
By Laurent Gibergues (laurent.gibergues (at) free.fr
http://forum.arduino.cc
*/
#include <Arduino.h>
#include "MQ7_LG.h"
#define MQ7_VRL_PIN A0
#define MQ7_HEATER_CTRL_PIN 4
// Optional parameter
#define MQ7_DOUT_PIN 5
#define MQ7_VOLTAGE_HEATER_PIN A3
#define PRINT_PERIOD 2000
MQ7_LG mq7(MQ7_VRL_PIN, MQ7_HEATER_CTRL_PIN, MQ7_DOUT_PIN, MQ7_VOLTAGE_HEATER_PIN);
unsigned long startTime;
void setup() {
Serial.begin(57600);
Serial.println("MQ7 CO gas sensor test");
Serial.println("Time;VRL;ppm CO;Heater voltage;DOut;");
mq7.init();
startTime = millis();
}
void loop() {
delay(PRINT_PERIOD);
mq7.run();
Serial.print((millis() - startTime) / 1000);
Serial.print(';');
Serial.print(mq7.getVRL());
Serial.print(';');
Serial.print(mq7.read());
Serial.print(';');
Serial.print(mq7.getHeaterVoltage());
Serial.print(';');
Serial.print(mq7.getDOut());
Serial.println(';');
}
It was difficult for me to understand how to transform a tension (VRL) to a ppm value.
Here is my comprehension of the documentation :
Rs / Ro = (Vcc – VRL) / VRL
If X = Rs/Ro and Y = ppmCO
Sensitivity characteristics graph says :
| X | Y | log(X) | log(Y) |
| 1 | 100 | 0 | 2 |
| 0.1 | 4000 | -1 | 3.6 |
log(Y) = -1.6 log(X) + 2
= log(X^-1.6) + log(100)
= log (100 * X^-1.6)
Y = 100 * X^-1.6
ppmCO = 100 * (Rs/Ro)^-1.6
Rs = RL * (VCC / VRL – 1)
ppmCO = 100 * (RL/Ro * (VCC / VRL – 1))^-1.6
Ro needs calibration tests. It's could be 2kOhms.
The result :
See the two graphs attached.
At t = 256s, I've opened the gas in the kitchen... and the window at t=580 !
Thanks for return.
PS : sorry for my english, I've done the best !




