Introduction: Arduino CO Monitor Using MQ-7 Sensor

Picture of Arduino CO Monitor Using MQ-7 Sensor

A few words why this instructable was created: one day my girlfriend's mother phoned us at the middle of the night because she felt really sick - she had dizziness, tachycardia, nausea, high blood pressure, she even fainted for unknown time (probably ~5 minutes, but there is no way to tell), all without any apparent reason. She lives in a small village far away from hospitals (60 km from our place, 30 km to the closest hospital, 10 km without any normal road in between), so we rushed to her and got there soon after the ambulance. She got hospitalized and in the morning she felt almost well, but doctors weren't able to find the cause of it. The next day we had an idea: it could have been CO poisoning, since she has gas water boiler (on the photo), and was sitting close to it for the whole evening when it happened.
We recently bought MQ-7 CO sensor, but never had time to assemble a schematics for it, so this was the perfect time to do so. After an hour of searching internet for any instructions, I realized that I can't find any guide that at the same time follows sensor manufacturer's instructions provided in its datasheet and explains anything at all (one example seemed to have quite good code, but it wasn't clear how to apply it, others were oversimplified and wouldn't work well). So we spent about 12 hours for developing schematics, making and printing 3d case, testing and calibrating the sensor, and the next day went to the suspicious boiler. It turned out that CO levels there were extremely high, and could be fatal if CO exposure time were longer. So I believe anyone who has similar situation (like gas boiler or other combustion happening inside a living space) should get such sensor to prevent something bad from happening.

All that happened two weeks ago, since then I improved schematics and program quite a lot, and now it seems to be reasonably good and relatively simple (not 3-lines-of-code simple, but still). Although I hope that someone with precise CO meter will provide me some feedback on default calibration that I put in the sketch - I suspect it is far from good.
Here is a complete guide with some experimental data.

Step 1: Bill of Materials

Picture of Bill of Materials

You will need:

0. Arduino board. I prefer Chinese clone of Arduino Nano for its outstanding price of $3, but any 8-bit arduino will work here. Sketch uses some advanced timers operation, and was tested only on atmega328 microcontroller - although probably it will work well on others too.

1. MQ-7 CO sensor. Most commonly available with this Flying Fish sensor module, it has to run through a small modification, details in the next step, or you can use a separaten MQ-7sensor.

2. NPN bipolar transistor. Virtually any NPN transistor that can handle 300 mA or more will work here. PNP transistor won't work with a mentioned Flying Fish module (because it has heater pin soldered to sensor's output), but can be used with a discrete MQ-7 sensor.

3. Resistors: 2 x 1k (from 0.5k to 1.2k will work fine), and 1 x 10k (that one is best kept precise - although if you absolutely must use a different value, adjust reference_resistor_kOhm variable in the sketch accordingly).

4. Capacitors: 2 x 10uF or more. Tantalum or ceramic ones are required, electrolytic won't work well due to high ESR (they won't be able to provide enough current to smooth high-current ripple).

5. Green and red LEDs to indicate current CO level (you can also use a single dual-color LED with 3 terminals, as we used in our yellow box prototype).

6. Piezo buzzer to indicate high CO level.

7. Breadboard and wires (you also can solder everything to Nano pins or squeeze into Uno sockets, but it's easy to make a mistake this way).

Step 2: Module Modification or Discrete Sensor Wiring

Picture of Module Modification or Discrete Sensor Wiring

For module, you must desolder resistor and capacitor, as shown on the photo. You can desolder basically everything if you want - module electronics is totally useless, we use it only as holder for the sensor itself, but these two components will prevent you from getting correct readings,

If you are using discrete sensor, attach heater pins (H1 and H2) to 5V and transistor's collector correspondingly. Attach one sensing side (any of A pins) to 5V, another sensing side (any of B pins) to 10k resistor, just like the analog pin of the module in schematics.

Step 3: Operation Principle

Picture of Operation Principle

Why we need all these complications at all, why not to attach 5V, ground, and just get readings?
Well, you won't get anything useful this way, unfortunately.
According to MQ-7 datasheet, sensor has to run through high- and low-heating cycles in order to get proper measurements. During low temperature phase, CO is absorbed on the plate, producing meaningful data. During high temperature phase, absorbed CO and other compounds evaporate from the sensor plate, cleaning it for the next measurement.

So in general operation is simple:

1. Apply 5V for 60 seconds, don't use these readings for CO measurement.

2. Apply 1.4V for 90 seconds, use these readings for CO measurement.

3. Go to step 1.

But here's the problem: Arduino can't provide enough power to run this sensor from its pins - sensor's heater requires 150 mA, while Arduino pin can provide no more than 40 mA, so if attached directly, Arduino pin will burn and sensor still won't work. So we must use some kind of current amplifier that takes small input current to control large output current.
Another problem is getting 1.4V. The only way to reliably get this value without introducing a lot of analog components is to use PWM (Pulse Width Modulation) approach with feedback that will control output voltage.

NPN transistor solves both problems: when it is constantly turned on, voltage across the sensor is 5V and it is heating for high-temperature phase. When we apply PWM to its input, current is pulsing, then it is smoothed by the capacitor, and the average voltage is kept constant. If we use high frequency PWM (in the sketch it has frequency of 62.5KHz) and average a lot of analog readings (in the sketch we average over ~1000 readings), then the result is quite reliable.

It is critical to add capacitors according to schematics. Images here illustrate difference in signal with and without C2 capacitor: without it, PWM ripple is clearly visible and it significantly distorts readings.

Step 4: Schematics and Breadboard

Picture of Schematics and Breadboard

Here is the schematics and breadboard assembly.

WARNING! Modification of a standard breakout module is required! Without modification module is useless. Modification is described in the second step.

It is important to use pins D9 and D10 for LEDs, since there we have outputs of hardware Timer1, it will allow to smoothly change their colors.
Pins D5 and D6 are used for buzzer, because D5 and D6 are outputs of hardware Timer0. We will configure them to be inverse one to another, so they will switch between (5V, 0V) and (0V, 5V) states, thus producing sound on buzzer. Warning: this affects Arduino's main timing interrupt, so all time-dependent functions (like millis() ) won't produce correct results in this sketch (more on this later).
Pin D3 has hardware Timer2 output connected to it (as well as D11 - but it's less convenient to put wire on D11 than on D3) - so we are using it to provide PWM for voltage controlling transistor.
Resistor R1 is used to control brightness of LEDs. It can be anywhere from 300 to 3000 Ohm, 1k is rather optimal in brightness/power consumption.
Resistor R2 is used to limit transistor's base current. It shouldn't be lower than 300 Ohms (to not overload Arduino pin), and not higher than 1500 Ohms. 1k there is a safe choice.

Resistor R3 is used in series with sensor's plate in order to create a voltage divider. Voltage on sensor's output is equal to R3 / (R3 + Rs) * 5V, where Rs is current sensor's resistance. Sensor resistance depends on CO concentration, so voltage changes accordingly.
Capacitor C1 is used to smooth input PWM voltage on MQ-7 sensor, the higher is its capacitance the better, but also it has to have low ESR - so ceramic (or tantalum) capacitor is preferred here, electrolytic one won't perform well.

Capacitor C2 is used to smooth sensor's analog output (output voltage depends on input voltage - and we have quite a high current PWM here, that affects all schematics, so we need C2). The simplest solution is to use the same capacitor as C1.
NPN transistor either conducts current all the time to provide high current on sensor's heater, or works in PWM mode thus reducing heating current.

Step 5: Arduino Program

Picture of Arduino Program

WARNING: SENSOR REQUIRES MANUAL CALIBRATION FOR ANY PRACTICAL USE. WITHOUT CALIBRATION, DEPENDING ON PARAMETERS OF YOUR PARTICULAR SENSOR, THIS SKETCH MIGHT TURN ON ALARM IN CLEAN AIR OR NOT DETECT LETHAL CARBON MONOXIDE CONCENTRATION.

Calibration is described in the following steps. Rough calibration is very simple, precise is quite complex.

On the general level, program is rather simple:

First we calibrate our PWM in order to produce stable 1.4V required by sensor (proper PWM width depends on a lot of parameters like exact resistor values, this particular sensor's resistance, transistor's VA curve etc etc - so the best way is to try various values and use one that fits best).
Then, we continuously run through cycle of 60 seconds heating and 90 seconds measurement.
In implementation it gets somewhat complicated. We have to use hardware timers because everything that we have here needs high-frequency stable PWM in order to function properly.

The code is attached here and can be downloaded from our github, as well as schematics source in Fritzing.

In the program there are 3 functions that handle timers: setTimer0PWM, setTimer1PWM, setTimer2PWM.
Each of them sets timer in PWM mode with given parameters (commented in the code), and sets pulse width according to input values.
Measurement phases are switched using functions startMeasurementPhase and startHeatingPhase, they handle everything inside. and set proper timer values for switching between 5V and 1.4V heating.
LEDs state is set by function setLEDs which accepts green and red brightness on its input (in linear 1-100 scale) and converts it into corresponding timer setting.

Buzzer state is controlled using functions buzz_on, buzz_off, buzz_beep. On/off functions turn sound on and off, beep function produces specific beeping sequence with period of 1.5 seconds if it is periodically called (this function returns immediately so it doesn't pause the main program - but you have to call it again and again to produce beeping pattern).

Program first runs function pwm_adjust that finds out proper PWM cycle width in order to achieve 1.4V during measurement phase. Then it beeps a few times to indicate that sensor is ready, switches into measurement phase, and starts the main loop.

In the main loop, program checks if we spent enough time in current phase (90 seconds for measurement phase, 60 seconds for heating phase) and if yes, then changes current phase. Also it constantly updates sensor readings using exponential smoothing: new_value = 0.999*old_value + 0.001*new_reading. With such parameters and measuring cycle, it averages signal over approximately last 300 milliseconds.

WARNING: SENSOR REQUIRES MANUAL CALIBRATION FOR ANY PRACTICAL USE. WITHOUT CALIBRATION, DEPENDING ON PARAMETERS OF YOUR PARTICULAR SENSOR, THIS SKETCH MIGHT TURN ON ALARM IN CLEAN AIR OR NOT DETECT LETHAL CARBON MONOXIDE CONCENTRATION.

Step 6: First Run: What to Expect

Picture of First Run: What to Expect

If you assembled everything properly, after running sketch you will see something like this in Serial monitor:

adjusting PWM w=0, V=4.93

...

adjusting PWM w=17, V=3.57
PWM result: width 17, voltage 3.57

and then a series of numbers representing current sensor readings.
This part is adjusting PWM width in order to produce sensor's heater voltage as close to 1.4V as possible, measured voltage is deducted from 5V, so our ideal measured value is 3.6V. If this process never ends or ends after a single step (resulting in width equal to 0 or 254) - then something is wrong. Check if your transistor is really NPN and is properly connected (make sure you used base, collector, emitter pins right - base goes to D3, collector to MQ-7 and emitter to ground, don't count on Fritzing breadboard view - it is wrong for some transistors) and make sure that you connected sensor's input to Arduino's A1 input.

If everything is fine, you should see in Serial Plotter from Arduino IDE something similar to the image. Heating and measurement cycles of 60 and 90 seconds length are running one after another, with CO ppm measured and updated at the end of each cycle. You can take some open flame close to the sensor when measurement cycle is almost finished and see how it will affect readings (depending on flame type, it can produce up to 2000 ppm CO concentration in open air - so even though only a small portion of it actually goes into sensor, it still will turn on the alarm, and it won't go off until the end of the next cycle). I showed it on the image, as well as the response to fire from the lighter.

Step 7: Sensor Calibration

Picture of Sensor Calibration

According to manufacturer's datasheet, sensor should be running heating-cooling cycles for 48 hours in a row before it can be calibrated. And you should do it if you intend to use it for a long time: in my case, sensor reading in clean air changed for about 30% over 10 hours. If you won't take this into account, you can get 0 ppm result where there is actually 100 ppm of CO. If you don't want to wait for 48 hours, you can monitor sensor output at the end of measurement cycle. When over an hour it won't change for more than 1-2 points - you can stop heating there.

Rough calibration:

After running sketch for at least 10 hours in clean air, take raw sensor value in the end of the measurement cycle, 2-3 seconds before heating phase starts, and write it into sensor_reading_clean_air variable (line 100). That's it. Program will estimate other sensor parameters, they won't be precise, but should be enough to distinguish between 10 and 100 ppm concentration.

Precise calibration:

I highly recommend to find a calibrated CO meter, make 100 ppm CO sample (this can be done by taking some flue gas into syringe - CO concentration there can easily be in the range of several thousands ppm - and slowly putting it into closed jar with calibrated meter and MQ-7 sensor), take raw sensor reading at this concentration and put it into sensor_reading_100_ppm_CO variable. Without this step, your ppm measurement can be wrong several times in either direction (still ok if you need alarm for dangerous CO concentration at home, where normally there should be no CO at all, but not good for any industrial application).

As I didn't have any CO meter, I used a more sophisticated approach. First I prepared high concentration of CO using combustion in isolated volume (first photo). In this paper I found the most useful data, including CO yield for different flame types - it isn't in the photo, but the final experiment used propane gas combustion, with the same setup, resulting in ~5000 ppm CO concentration. Then it was diluted 1:50 in order to achieve 100 ppm, as illustrated in the second photo, and used to determine sensor's reference point.

Step 8: Some Experimental Data

Picture of Some Experimental Data

In my case, sensor worked quite well - it is not very sensitive for really low concentrations, but good enough for detecting anything higher than 50ppm. I tried to increase concentration gradually, taking measurements, and built a set of charts. There are two sets of 0ppm lines - pure green before CO exposure and yellow green after. Sensor seems to slightly change its clean air resistance after exposure, but this effect is small. It doesn't seem to be able to clearly distinguish between 8 and 15, 15 and 26, 26 and 45 ppm concentrations - but the trend is very clear, so it can tell whether concentration is in 0-20 or 40-60 ppm range. For higher concentrations dependence is much more distinctive - when exposed to exhaust of an open flame, curve goes up from the start without going down at all, and its dynamics is totally different. So for high concentrations there is no doubt that it works reliably, although I can't confirm its precision since I don't have any rated CO meter.
Also, this set of experiments was done using 20k load resistor - and after that I decided to recommend 10k as the default value, it should be more sensitive this way.

That's it. If you have a reliable CO meter and will have assembled this board, please share some feedback about sensor precision - it would be great to collect statistics over various sensors and improve default sketch assumptions.

Comments

Dionysus2 (author)2017-11-22

We have a project in school involving CO detector and we have to test it. Does anyone have any idea how we could produce carbon monoxide safely?

the_3d6 (author)Dionysus22017-11-22

The simplest way to produce a sample of CO is to cover an ordinary candle with a glass jar. Inside the jar flame will consume significant part of oxygen and will produce some CO. It's hard to say how much exactly, but probably it will be inside 3000...10000 ppm range. If you produce it in a jar with volume less than 1 liter, then even if it's opened in a small room, concentration won't get anywhere close to a dangerous level

RuiMonteiro (author)2017-11-16

Hi, nice instruction. The module works with a current of 150mA how do you manage to be able to work on batteries for such hungry power device? Thanks.

the_3d6 (author)RuiMonteiro2017-11-16

I don't see any way to use it for battery powered device while following manufacturer's datasheet.

It might be used in a different mode, with heating turned completely off most of the time. In this case we can monitor its resistance, and detect increase in CO concentration when it drops too fast. But in this scenario sensor surface will be covered with other substances over time, so probably no static threshold can be used at all, and once in a while you'll need to run 60-second heating cycle to clean the sensor.
Experiments are required to determine how often this is actually needed, if it will be enough to heat it for 60 seconds once in several hours, then it can be used with batteries. Measurement precision will be much worse in this mode, but probably still good enough to detect 50 ppm.
Any application of such sensor in this mode requires extensive experiments with multiple units (performed better than ones in manufacturer's datasheet)

PTuT (author)2017-11-10

Hi,

I would like to know if your procedure would work directly with Arduino Mega 2560. I am trying to replicate your board between the MQ-7 sensor board and Arduino Mega using BC334-40 transistor (max 40V and 0.8 A) but it seems not to work. When I start the program it goes through 'adjusting PWM w=0,1,2,...250,...' but the value 'V=4.99' all the time. As far as I can say there is no voltage going out to MQ-7 board from which I have removed capacitor and resistor per your instructions. I am quite new so your help would be really appreciated.

Thanks. BTW, great work!

PTuT (author)PTuT2017-11-10

Oh, even though the drawing says D2, it really is going to D3. Thanks.

the_3d6 (author)PTuT2017-11-11

Are both collector and emitter connected to GND? I'm not sure if I recognized your labels correctly

PTuT (author)the_3d62017-11-11

Collector is connected to negative of capacitor C1, A1 (Arduino), and ground of the MQ-7 Breakout board. Emmiter is connected to ground from Arduino and resistor R3 (10K). Is it correct? The label on the bottom of drawing (VCC, A0, GND, D3, A1) are connections to the Arduino board and connection in the top-right corner of drawing (A0, VCC, GND) are for MQ-7 board.

the_3d6 (author)PTuT2017-11-11

Everything seems to be correct (assuming that you never connected "gnd" of MQ-7 board to Arduino's GND). Are you sure that your "D2" actually is connected to D3 pin of Arduino? Are you 100% sure that you put transistor in a correct way, not swapped emitter and collector? In which way you are providing power to all components?

PTuT (author)the_3d62017-11-11

I am not sure about the question about the "gnd" of MQ-7 board never being connected to Arduino's GND. Before seeing your instructions, I may connected not-yet-modified MQ-7 board to Arduino (GND to GND, A0 to A0, and 5V to VIN). Yes, I have it connected to D3. About transistor, I downloaded couple of PDFs for BC334-40 and they show it the way I have it (when looking at the transistor's flat side with label, the collector is on the left and emitter on the right).

I am powering it through USB.

Can you, please, tell me what voltages should be observed on D3, A0 and A1 during the PWM calibration phase? Should the voltage on D3 change? How should it be see on A0 and/or A1?

the_3d6 (author)PTuT2017-11-11

I'm sorry - I never really looked in Arduino Mega datasheet and assumed that it has the same pins as others arduinos, based on atmega328p processor. But it's not like this!
Arduino Mega has different pins for timers 0, 1, 2. And since everything here is based on timers, pin connections must be different:
pins 5, 6 must be changed to 13, 4;
pin 3 must be changed to 9;
pins 9, 10 must be changed to 12, 11.

Please write if it will work - I can't confirm right now that my code will init/set timers for atmega2560 correctly, I briefly looked at datasheet and it seems ok, but I easily could have missed something

PTuT (author)the_3d62017-11-12

Bingo, sounds like the culprit of the problem ... I will check it out tomorrow. Thanks :). That's why I mentioned that it's Mega. These timers are hardware wired to particular pins, correct? I don't exactly understand the settings for TCCR2A ... where can I find the binary codes (0b10100011) and meaning for the values of chA and chB? That part of your code is enigma for me.

And yes, I will confirm if it does work or not. Thanks again.

the_3d6 (author)PTuT2017-11-12

In order to make it work with the same pins, all timers code must be rewritten. Here are timer pins: https://playground.arduino.cc/Main/TimerPWMCheatsh...

My code simply writes values into timer control registers (with names like TCCR1A), I got values from atmega328p datasheet (like pages 131-135 for TImer 1, it's easy to find them when you are looking for timer register description).
Timers are devices that are independent from microcontroller core, in this case I'm using them to generate PWM signals. Timer has cycle length which is defined in control registers (in this program it's 255), and threshold. When counter is below threshold, corresponding pin is low, when it's above threshold, corresponding pin is high. Counter is increased automatically with configurable rate.
PWM, in turn, is needed for 3 different purposes:
1. it controls heating coil, in order to provide low heat phase (according to MQ-7 datasheet, CO measurement must be performed not with heater turned off, but when it runs at lower power). This part is essential and PWM is the only reliable way to achieve it.
2. it's used to change intensity of green and red LEDs. It's not really important, but gives more visual information about detected concentration.
3. it's used to generate sound on piezo buzzer. Can be replaced with some kind of piezo generator that only requires power to produce sound.

PTuT (author)the_3d62017-11-12

So, only the pin 3 (of your original design) is really needed to control the high/low voltage heating of the MQ-7 sensor, correct? And, that is controlled by timer function 'setTimer2PWM', right? Pins 5,6,9,10 are used to let user know that device works and that CO concentration is higher than predefined value?

the_3d6 (author)PTuT2017-11-12

Yes, pin 3, controlled by timer2 - everything else is optional. AnalogWrite according to this page: https://www.arduino.cc/en/Reference/AnalogWrite produces PWM at 490Hz. This is very low frequency, power-related noise at such frequency won't be filtered by capacitors and, therefore, will distort readings. With direct timer setting, PWM frequency is 62.5KHz - more than 100 times higher - so capacitor filters it quite well

PTuT made it! (author)the_3d62017-11-13

I think I made it work.

However, it seems my sensor's performance is different from your sensor. During sensing cycle #1 I placed the sensor into the jar that was previously collecting CO from lighter's flame AND I didn't see any response right way. During the following heating cycle, all went up and then during the following sensing cycle #2 I could observe higher values too. Is that reasonable (see the attached graph)?

I have a question. Because of the Mega board I am using pinMode(9, OUTPUT); which works. However, if I try to use pinMode(10, OUTPUT); which based on documentations is also on the same timer (timer 2 (controls pin 10, 9)), it will not work (the PWM calibration will not show the voltage going down, it will stay around 4.98V). Is there anything else that would have to be changed in your code to make it work for pin D10?

Thanks.

the_3d6 (author)PTuT2017-11-13

Everything is correct: sensor signal isn't stable when we turn heat down, it stabilizes only at the end of the low heat cycle. So program makes decision about CO concentration a few seconds before turning on heating. Therefore, when placed in high-CO environment, you will see alarm approximately at the beginning of the next heating cycle.

For really high CO concentration decision can be made much faster (just a few seconds into cooling phase), but my program is optimized for scenario when concentration is changing slowly.

Pins 10 and 9 depend on timer channels - arduino timers often have 2 separate channels, they share the same counter and all settings, but have different threshold values (so you can make 2 PWM signals using a single timer). In order to switch between pin 9 and pin 10 in my program, in all places where function setTimer2PWM is called, you need to switch first and second parameters (now first is 0, second is some value, so one channel of this timer isn't used).

PTuT (author)the_3d62017-11-13

Thanks for confirmation all works correctly and explanation of PWM pins.

I have one more question. What determines the magnitude of the raw value? I see that in air during the sensing cycle, my values are about 600. But, in another example bellow, another user's values are closer to 400. Thank you.

the_3d6 (author)PTuT2017-11-13

It depends mostly on 2 parameters: reference resistor (10k in my schematics, but you can use different value) and sensor's manufacturing process - they are supposed to have the same clean air resistance, but I believe it actually varies quite significantly

PTuT (author)the_3d62017-11-14

Thanks for all your help and responses. I learned quite a lot.

PTuT (author)the_3d62017-11-12

Thank you for an excellent explanation. Make sence.

PTuT (author)the_3d62017-11-12

Why analogWrite(pin, dutyCycle) function cannot be implemented instead of using PWM registers directly? And, how much error this can introduce in measuring CO concentration?

the_3d6 (author)PTuT2017-11-12

...and also you need to add modification into code lines 212-216:
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(3, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
- change pins numbers to new ones

PTuT (author)the_3d62017-11-12

Thank you for pointing this out. First, I will incorporate changes to the code due to using Mega board and then try your code as is and see if it works.

videanuadrian (author)2017-11-13

At calibration side: "After running sketch for at least 10 hours in clean air,", does this mean that the sensor should be run outside ? or in the room that is supposed to have clean air ?

the_3d6 (author)videanuadrian2017-11-13

Room is fine, for this process it's not important to have exactly zero CO concentration. But when you'll measure clean air raw value to fill it into program, make sure that air is really clean - that value will be used as zero concentration point, if in reality it won't be zero, all further measurements will be wrong.

videanuadrian (author)2017-11-10

I wonder why do they sell this "brick" sensor with that resistor and capacitor there it this keeps you from having an accurate reading.... Any peticular reason ?

the_3d6 (author)videanuadrian2017-11-10

Because these modules are designed by people who are supposed to finish such PCBs within a couple of days (so their price stays really low). It's only natural that they have design mistakes

spaqin (author)2017-10-15

Hey,

First - great job on the writeup! Seems you were the only person to really read the documentation and think of something, and actually write it down as well :)

I'm working on a STM32-based implementation of this (F103C8T6 boards are literally 1.70$ on Ali, and in theory give better performance than AtMegas! although they're more complex to use), and while my electronics knowledge isn't great, I was thinking...

Why or why not can't we use a DAC (or in Arduino terms, Analog Out), paired with the transistor? With known transistor and base resistor parameters we could even skip calibration, no?

spaqin (author)spaqin2017-10-15

Some research later it seems the Arduino doesn't even have a DAC, that's why you didn't include one (one more reason to get a STM32F103! lol), and outputs are 3.3V, so a simple current amplifier wouldn't work, but a common emitter seems an option.

the_3d6 (author)spaqin2017-10-15

Thanks :)
STM32F103 is superior to atmega328 by all means (except for power consumption, but here it isn't important - sensor heating consumes much more power than any MCU). In our team we use it whenever we need more processing power, programming isn't that complicated ))
But as far as I know, F103 doesn't have hardware DAC either.
My approach with PWM that is smoothed by capacitor is actually a rough DAC version - pulse width translates into more or less stable voltage level.
You can skip PWM calibration for production unit - when transistor and resistor parameters are known. But that process is fully automated so it's not that important. Calibrating sensor is much more problematic and I don't see any reliable way around it - at least without knowing production process and some statistical data of variations between sensors

DhaniB (author)2017-10-04

where can i get the source code? thankyouu

the_3d6 (author)DhaniB2017-10-05

Link is at the end of chapter 5 of this instructable :)

drawiggle (author)2017-09-22

can i use an arduino uno r3 with this project?

the_3d6 (author)drawiggle2017-09-23

Sure, arduino uno will work in exactly the same way. Most arduino models have the same chip in their core - atmega328p - so schematics and software will be 100% compatible

drawiggle (author)2017-09-22

hello sir, can I use arduino uno r3 with this project?

Julionf (author)2017-08-13

First, thanks for all effort you have put into this!

My sensor seems to be working fine, but my leds not. The red leds keeps blinking every second and my green led never turns on, do you know what it might be?

Thanks again

the_3d6 (author)Julionf2017-08-13

That means that detected CO level is too high. This, in turn, could be caused by problem in calibration. Have you left it on for 10 hours before measuring calibration value? How you performed calibration?

Julionf (author)the_3d62017-08-14

In the serial the CO levels seems right (0 in clean air). Yesterday I put a lighter next to the sensor and the CO levels rose and the green light came on, as in the photo, but as soon as the level lowered the red light turned on again.

The sensor is on for more than 48 hours and I did the "rough calibration" method, picking a value 3 seconds before the heating phase and putting it into "sensor_reading_clean_air".

Thanks again for the help!

the_3d6 (author)Julionf2017-08-14

It seems you did everything correctly, maybe you just put red led on a place of a green one? Because if you'll switch red and green, it works like it should - normally blinks green, and when there is CO, blinks red.
Is buzzer working when you put lighter there, or you haven't attached one?

Julionf (author)the_3d62017-08-15

I think that switching leds solved the problem (omg i'm so dumb hahaha)... No, the buzzer didn't work, but I think it's because I didn't reach the 100 ppm minimum for it to buzz. I'll try again today.

EDIT: I tried again and everything worked perfectly! Thank you very much!!

IgorC47 (author)2017-06-25

Great job! Thanks!

Did you check, whether it is applicable to the other sensors on the market with the same boards?

the_3d6 (author)IgorC472017-06-26

In the second step here we are breaking connection on the module, which turns it into clean MQ7 sensor plus reference resistor, totally ignoring all other parts on the module. So if you do similar operation with any other module utilizing the same sensor, it will work.
If you will use different sensor, but one that also uses heating-cooling cycles and similar sensitive layer, I think it will work just fine (if you will calibrate it with 100 ppm sample).

IgorC47 (author)the_3d62017-06-26

Yes, certainly I'm going to use this board just as a convenient carrier board.
By the way, Why did not you use CMOS transistor? Just because NPN was easy to find?

the_3d6 (author)IgorC472017-06-26

Only because I had one at hand, and didn't have any mosfets with gate voltage below 5V. Low voltage mosfet would definitely be better there

IgorC47 (author)2017-06-25

Why the C1, C2 capacitors connected between power and PWM output (the transistor collector), AO .This connection looks very strange to me.

Would not it be more logical to connect between outputs and ground?

the_3d6 (author)IgorC472017-06-26

You are right. They are connected this way because in my schematics I started with unmodified module, and later realized that it can't be done without breaking connection on it - but capacitors were already there, and I never thought that it would be actually more logical to connect them to ground

Vidmo made it! (author)2017-06-13

Hi, great instructable, it's helping me a lot with designing similar device, but I'm not sure about function you use for ppm calculation. I've got my equation from Matlab curve fitting toolbox which I used on datasheet's points:

ppm(Rs/Ro) = 3894*exp(-8.065*Rs/Ro) + 383.6*exp(-1.45*Rs/Ro).

On attached figure I plotted datasheet's points - blue; my function - red; your function - green.

Also I've tested supplying power with BC337 transistor, and there's 0,7V drop(which will be there for every silicon transistor), which lowers 5V into 4.3V. Best way would be to use higher voltage source for powering MQ-7 and Arduino through VIN pin. Arduino would have to find 1,4V and 5V PWM values for powering MQ-7.. I would also add 5.1V Zener diode for protection. This would also assure, that Arduino and sensor are running on exactly 5V (Arduino's LDO is quite precise) which is very important for analog sensing.

the_3d6 (author)Vidmo2017-06-14

You are right about my formula, it deviates from the datasheet very much. There are two reasons behind this:
1. My real concern was achieving good results in 0-300 ppm area, in my experiments I mostly ignored 500+ppm concentrations.
2. When I exposed sensor to ~5000ppm sample, its Rs/Ro ratio was about 0.25, nothing close to 0.08 from the datasheet.
So I ignored datasheet data and made a formula that works with my particular sensor, my main concern was to make it follow real data.
Even if my CO measurements are off two times in either side, datasheet still is very wrong about Rs/Ro relation at high concentrations. Still, it would be great if someone with rate CO meter could confirm this or prove me wrong.

As for your analysis - your formula is wrong in high-ppm area, and you plotted datasheet data incorrectly: when Rs/Ro is equal 0.05 then according to the datasheet we should reach 10000 ppm, and at 0.01 we should reach ~100000ppm (it's not there, but if we assume straight line on log scale - which seems physically feasible - we can estimate it). But on your chart Rs/Ro = 0.01 is depicted as 4000 ppm, thus giving you really wrong approximation formula: according to your approximation, absolute maximum PPM that this sensor can give is 4277.6 (when Rs/Ro = 0).

About 4.3V supply left after transistor: you are absolutely right about that, but I doubt it does matter that much - the only goal of 5V phase is to heat sensor, so it will become more or less free of absorbed substances. With 4.3 instead of 5 we achieve somewhat lower temperature, but from my experiments it seems still high enough to reliably clean sensor plate - at least I wasn't getting any traces of ~5000ppm concentration after 2 cycles in clean air

Vidmo (author)the_3d62017-06-14

Thanks fot your comment. I assume, that I'll have to find somebody with CO meter for calibration :)
As for formula - I assumed that anything higher than 4000ppm is lethal...
I just found "manual" for it which gives ppm relation to clean air resistance https://cdn.sparkfun.com/datasheets/Sensors/Biometric/MQ-7%20Ver1.3%20-%20Manual.pdf
And I'm getting more unsure about this sensor...
You might be right about voltages, but I thing I'll check that with scope, just to be sure.
Also I'm thinking about cutting traces (I have module similar to yours) and making separate circuits for sensor and heater. I desoldered opamp, so DO pin is free to use as separate supply for heater, this should improve output voltage stability.

About This Instructable

11,778views

41favorites

Bio: I love cyberpunk and work as an electronics engineer, not much to add here
More by the_3d6:Arduino CO monitor using MQ-7 sensor
Add instructable to: