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


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.


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.


spaqin (author)2017-10-15


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
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.

the_3d6 (author)Vidmo2017-06-14

Separate heating circuit definitely will work better. But I don't think that such sensor could be usable without calibration at all, other than to distinguish between really high and really low levels: you can more or less safely assume that when resistance drops 2 times comparing to clean air, CO concentration is unhealthy and you should leave the room, but if you want to make a decision whether you can withstand it for 15 minutes without serious risk - I really, really wouldn't recommend it without calibration ))

Vidmo made it! (author)the_3d62017-06-19

I made my version. In the end I used your equation and clean air value calibration method :)

My code is completely different, it's designed for attached circuit. Main features are:
* DC/DC buck converter for MQ7 heater with auto calibration,
* 12V supply voltage,
* TM1637 display for ppm values,
* active buzzer for alarm.

the_3d6 (author)Vidmo2017-06-20

Your schematics is very good, it should produce much cleaner results than my version.
But I didn't get some parts of your code, not sure if they are correct:
#define Rf 9.5 //reference voltage
why reference voltage is 9.5 when in schematics it seems to be 5?

float Rs = (vin * Rf) / ( 5000 - Rf);
here Rf is 9.5, presumably in volts? But 5000 is in millivolts, so (5000 - Rf) doesn't make sense.
Maybe you've meant Rf to be reference resistance? Then formula should be different:
Rs = Rf * 5000/vin - Rf, which is equivalent to Rs = Rf * (5000 - vin) / vin

Also, in cal14 and cal50 functions you are mapping voltage into 0-10000, not into 0-5000, so your actual heating voltage would be 2.5V, and measurement voltage would be 0.7V, it's best to fix it - but that's a minor problem. Calculations are what is really unclear there, and they seem to be wrong.

Vidmo (author)the_3d62017-06-20

Rf is reference resistance. Formula is for other connection: sensor (Rs) is connected to GND and Rf, which is connected to 5V.

I'm mapping voltages to 10000mV, because I used voltage divider for sensing higher voltages. This simple converter can supply voltages from 0 to Vcc-2.2V, so when 12V is applied It can go up to 9.8V and ATmega won't tolerate that.
Both issues are shown on schematic. I tested voltage on sensor and resistance (device powered down just after heating cycle) with multimetr, and they are very close to that Arduino reads.

Sensor shows something like 10000-30000ppm in jar where all air was burned out with a lighter. Alarm goes on when ALARM value has been reached and stays on at least for one heating cycle.

the_3d6 (author)Vidmo2017-06-20

Yes, I overlooked divider on A0, your cal14 and cal50 functions are fine.
But your formula for Rs is still wrong: you have (5000 - Rf) term, 5000 are in mV, Rf is in kOhms, you can't do this.
I also overlooked that you have Rs on the ground in your divider, not on the positive side, so let's write correct formula now:
I = 5000 / (Rs + Rf) (current vs resistance at 5V)
vin = I * Rs (voltage at divider relative to ground)
Rs * 5000 / (Rs + Rf) = vin (put first two together)
Rs = vin / 5000 * (Rs + Rf)
Rs - Rs * vin / 5000) = Rf * vin / 5000
Rs = Rf * (vin / 5000) / (1 - vin / 5000)
Rs = Rf * vin / (5000 - vin)

so that would be the correct one

SeiberGen5 (author)2017-05-05

Really great work here! Thank you so much for your efforts on this. I have a couple questions for you if you don't mind. The program boots up and appears to be running correctly. While it is measuring PWM the voltage value displayed in the serial monitor is inverse to what I am directly measuring at the sensor so that appears to be working. However it consistently takes around 170 pulse width for it to reach the desired 1.4v. Something about that seems off in my circuit but not sure what, maybe the capacitors I am using? They are 10 microfarad. I think this also is effecting the heating task. I don't see any issues in your code as its sending 255 into the PWM for timer2 however I only get a measurement of 1.4v during the heating cycle and only 1v during measurement cycle (Measurements taken directly off the sensor via multimeter.

If you have any ideas I would very much appreciate it and thank you again for this!

the_3d6 (author)SeiberGen52017-05-05

That seems strange, please double check transistor connection and write which exact model you've used (and which resistor you put on its base). I don't really see how that could be possible with proper transistor, it would be my first suspect

SeiberGen5 made it! (author)the_3d62017-05-05

I am using a 2N222 NPN transistor, I thought the datasheet said it could handle 600mA continuous (I could certainly be wrong) and doesn't seem to be malfunctioning to my knowledge. If you are looking at the transistor from the flat side I have on the very left (emitter) connecting to the ground bus for the arduino. center (base) is going through a 1k resistor (actual is 1.09...) then into D3 on the arduino. RIght (collector) is connected to the ground of the sensor, negative of the capacitor, and A1 pin. Hope that helps.

the_3d6 (author)SeiberGen52017-05-05

Oh, it's simple - you just mixed collector and emitter pins (they are marked clearly in this datasheet: ). Connect it backwards and it should work. With current connection your described behavior seems fine, I don't think you've burned anything

SeiberGen5 made it! (author)the_3d62017-05-05

I am also using a discrete sensor by the way and so I have it connected like shown below

the_3d6 (author)SeiberGen52017-05-05

If you haven't forgot 10k resistor from sensor output to the ground, then everything is correct

SeiberGen5 (author)the_3d62017-05-06

Cool thank you, yup I have a 10k (actual on this one is 10.0...) that runs from the ground to the output, negative pin on the capacitor and A0 on the arduino

SeiberGen5 (author)the_3d62017-05-05

Haha well that was silly of me I don't know what I was looking at. Thank you sure enough I just had to flip it around and started working more normal. I am only getting 4v currently when in heating mode but I know its nothing with your design and code so its very possible I damaged the sensor while attempting other experiments with it. It also was able to reach the 3.6v mark with a pulse width of 30 this time instead of 175 :).

the_3d6 (author)SeiberGen52017-05-05

If you are powering it from PC via usb cable, then it's ok not to reach 5v (4.0v seems a bit low, but 4.4 is perfectly normal, I'm typically getting 4.4...4.6 when running power consuming things via usb using standard cables).
You can't burn this sensor if you never applied more than 5v (it is basically a heating coil and a chemically active resistor, it can survive any polarity, and probably 6-7 volts)

SeiberGen5 (author)the_3d62017-05-05

That's true, I am currently powering it via USB from a docking station here at work. I have never applied more than 5v to it so it should be fine then. When I get home tonight I will plug it into a 5v power supply just to see what I can get and see about getting a few hours runtime on it. Great work on this again.

the_3d6 (author)SeiberGen52017-05-06

Thanks :) Hope you'll get it work well

veritek (author)2017-04-29

I love it when someone posts a project, you wire it up, download the program and it works first time!!!! I am using an Uno instead of a Nano but working fine from what I can tell so far.

I have a Fluke digital CO monitor so will post my calibration results.

My serial monitor is not working so debugging right now, then will be adapting dual 7 segment LED for digital readout. before calibrating.

the_3d6 (author)veritek2017-04-30

Great! Waiting for your data then! Also lately (when weather changed) I found out that humidity is really important in low-ppm area, so in some time I'll make an update which will include DHT11 sensor to compensate it. I have some code for displaying digits on 7-segment, if you want I can clean it up a bit and upload.
As for serial monitor, I can't think of any reason why it could be not working, except for baud rate - but I used default 9600.

veritek (author)the_3d62017-04-30

The monitor was actually working, I just needed to wait a minute!

Yes, if you would be willing to share the code and pinout, it would save me a bunch of time. Thanks!

the_3d6 (author)veritek2017-05-02

Here is an example of using 2 digits. They share the same pins for controlling segments (with different ground pins for each digit), so you can add more digits in the same way

AnD21 (author)2017-04-07


I downloaded your code and read through for some times. But I'm struggled to understand these lines. What exactly does the sensor_reading_clean_air stand for ? Is it the sensor's voltage or the analog value read from Arduino pin ( which ranges from 0 to 1023)?

And how could you come up with the highlighted formulas ?

Thanks in advance.

the_3d6 (author)AnD212017-04-08

Hi! Clean air reading requires value directly from analogRead, 0-1023 - we use it to divide 1023 on this value, keeping in mind that 1023 is 5V in analogRead scale.

This formula comes from the following: sensor is basically a resistor that changes its value according to CO concentration. I've attached this part of schematics and formulas as an image.
If you can measure 100ppm experimentally, then this value should be filled and sensor resistance at 100ppm will be calculated using this formula. If you don't have 100ppm sample, sensor resistance is assumed to be half of the reference (this is really far-fetched: datasheet doesn't even have data on sensor behavior in 0-30ppm area, this estimation seemed to work relatively well with my particular sensor, but might be quite wrong, up to +-50%, for any other particular sensor)

AnD21 (author)the_3d62017-04-09

Wow that's awesome !! It really enlightened me.

Thank you for your reply.

Junior'sK (author)2017-04-05

If I just want to calibrate the sensor, can I follow the steps and use the sensor on another detector?

the_3d6 (author)Junior'sK2017-04-06

Almost - curve will be the same anywhere after calibration, but zero point might be a bit shifted due to limited reference resistor precision. If you are using 1% precision resistors, it shouldn't be a problem - but for 10% it will be significant

Junior'sK (author)2017-04-05

Hello. What transistor model is it exactly?

the_3d6 (author)Junior'sK2017-04-06

I used BC817, but you really can take almost any model, as long as it is NPN and can handle 300ma

Shlok1229 (author)2017-04-04

By desolder, do you mean remove the resistor & capacitor and resolder it after removing it, or do you mean to break the connection?

About This Instructable



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: