Gas Sensor MQ-2 with ATmega32 and LCD

Gas sensor MQ-2 is used here with ATmega32 microcontroller to detect gas presence and display the level of the gas on LCD. MQ-2 gas sensor can detect LPG, smoke and hydrogen gas, butane, CO2, alcohol etc so you can use it in many projects. Here we will simply display the level of LPG gas and Smoke in PPM(Parts Per Million) on LCD.

Download the project Proteus File

You can download the project Proteus File from the free download link below.

Dwnload Gas Sensor MQ-2 with ATmega32 and LCD project files

Shown below is picture of what it looks like when the circuit is completed on a breadboard.

MQ-2 Gas Sensor with ATmega32 and LCD on breadboard

MQ-2 Gas Sensor Module

The MQ-2 module contains the MQ-2 gas sensor, some chip that performs signal conditioning, resistors, potentiometer for adjusting the sensitivity. The MQ-2 gas sensor itself contains gas sensitive conductive Tin Dioxide (SnO2) layer whose conductivity increases, that is, resistivity decreases when the gas concentration near it increases. This increase in conductivity or decrease in resistivity is translated into output voltage via the voltage divider that is formed by the internal SnO2 and the potentiometer. We have explained how the MQ2 gas sensor works in more details in our earlier blog post MQ-2 Gas Sensor with Arduino and LCD.
As shown in the accompanied picture, the MQ2 sensor module has three pins- an analog pin(A0), a digital Pin(D0), the ground pin(GND) and the positive power supply pin(Vcc).

Also in the picture you can see a potentiometer knob which is used to adjust the sensitivity of the sensor. Clockwise rotation will increase the sensitivity and counter clockwise rotation will decrease the sensitivity.

Circuit Diagram of Interfacing MQ-2 Gas Sensor with ATmega32 and LCD

Below is the wiring diagram for interfacing MQ2 gas sensor with ATmega32 and LCD. The MQ2 analog output pin is connected to the ADC0 pin which is on PORT A pin 0. From this pin we acquire the sensor signal and convert it to PPM value according the Datasheet of MQ2 sensor. For how to do this see the code provided below. The 16x2 LCD is connected to the Port.D of ATmega32. For this pin PD7 to pin PD2 are used.

Circuit Diagram of Interfacing MQ-2 Gas Sensor with ATmega32 and LCD

Code of MQ-2 gas sensor with ATmega32 and LCD

The following are the codes used for this project. There is main.c file and c and header files for LCD, ADC module and MQ2 sensor.


#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include "lcd.h"
#include "adc.h"
#include "mq2.h"

float Ro=10;                 //Ro is initialized to 10 kilo ohms

int main(){ 
	unsigned char Res[16], lpg[16], smoke[16];
	Ro = SensorCalibration();                       //Please make sure the sensor is in clean air when you perform the calibration       
	dtostrf(Ro, 6, 2, Res); 
	_delay_ms(2);	//clearing takes around 1.64ms to execute
	lcdstr("Calibration done..."); 
	lcdstr("KOhm ");
	_delay_ms(2);	//clearing takes around 1.64ms to execute
   while (1){
		itoa(GetGasPercentage(ReadSensor()/Ro,LPG), lpg, 10);
		itoa(GetGasPercentage(ReadSensor()/Ro,SMOKE), smoke, 10);
		lcdstr("        ");
		lcdstr("      ");
   return 0;


void lcdinit();
void lcdcmd(uint8_t);
void lcdchar(uint8_t);
void lcdstr(unsigned char *);
void latch(void);
void lcdgoto(uint8_t , uint8_t );


#include <avr/io.h>
#include  <util/delay.h>
#include "lcd.h"

#define E (1<<PD3)
#define RS (1<<PD2)

void lcdinit(){
	//initialize PORT D for LCD
	DDRD |= (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6) | (1<<PD7); 


	PORTD &= ~E;		//send low
	_delay_ms(50);  		//delay for stable power
	lcdcmd(0x28);		// for using 4 pins
    lcdcmd(0x0C);  	// display ON, Cursor OFF
	lcdcmd(0x01);		//clear LCD
	lcdcmd(0x06);		//shift cursor to right
void lcdcmd(unsigned char cmd){
    PORTD = (PORTD & 0x0F) | (cmd & 0xF0);  // send high nibble
    PORTD &= ~RS;	//send 0 to select command register
    PORTD |= E;		//send high
    _delay_ms(50);	//wait
    PORTD &= ~E;	//send low
    PORTD = (PORTD & 0x0F) | (cmd<<4);	//send low nibble 
	PORTD |= E;		//send high
    _delay_ms(50);	//wait
	PORTD &= ~E;	//send low
void lcdchar(unsigned char data){
    PORTD = (PORTD & 0x0F) | (data & 0xF0);  // send high nibble
	PORTD |= RS;	//send 1 to select data register
	PORTD |= E;		//send high
	_delay_ms(50);	//wait
	PORTD &= ~E;	//send low

    PORTD = (PORTD & 0x0F) | (data<<4);  // send low nibble
	PORTD |= E;		//send high
	_delay_ms(50);	//wait
	PORTD &= ~E;	//send low
void lcdstr(unsigned char *str){
    unsigned char k=0;
    while(str[k] != 0){

void lcdgoto(unsigned char x, unsigned char y){
      unsigned char firstcharadr[] = {0x80, 0xC0, 0x94, 0xD4};
      lcdcmd(firstcharadr[y-1] + x-1);

void lcdclear(){


void adcinit();
int adcread(char);


#include <avr/io.h>
#include <util/delay.h>
#include "adc.h"

void adcinit(){	
	//make PA0 an analog input
	DDRA &= ~(1<<PA0);	  
	//enable ADC module, set prescalar of 128 which gives CLK/128 	
	ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
	//set the voltage reference using REFS1 and REFS0 bits and select the ADC channel using the MUX bits
	ADMUX = 0b01000000;      // set REFS1 = 0 |REFS0 = 1 (Vref as AVCC pin) | ADLAR = 0(right adjusted) |  MUX4 to MUX0 is 0000 for ADC0

int adcread(char channel){
	/* set input channel to read */
	ADMUX = 0x40 | (channel & 0x07);   // 0100 0000 | (channel & 0000 0100)
	/* Start ADC conversion */
	ADCSRA |= (1<<ADSC);      
    /* Wait until end of conversion by polling ADC interrupt flag */
	while (!(ADCSRA & (1<<ADIF)));    
   /* Clear interrupt flag */
	ADCSRA |= (1<<ADIF);               
	_delay_ms(1);                      /* Wait a little bit */
    /* Return ADC word */
	return ADCW;                      


#define RL_VALUE (10)     //define the load resistance on the board, in kilo ohms
#define RO_CLEAN_AIR_FACTOR (9.83)  //(Sensor resistance in clean air)/RO,which is derived from the chart in datasheet
#define LPG (0)         // Gas identity no.
#define SMOKE (1)
int  GetPercentage(float, float *);
int GetGasPercentage(float , int);
float ReadSensor();
float ResistanceCalculation(int);
float SensorCalibration();


#include <util/delay.h>
#include "adc.h"
#include "mq2.h"

float LPGCurve[3] = {2.3,0.20,-0.45};   //two points from LPG curve are taken point1:(200,1.6) point2(10000,0.26)
                                        //take log of each point (lg200, lg 1.6)=(2.3,0.20)  (lg10000,lg0.26)=(4,-0.58)
                                        //find the slope using these points. take point1 as reference   
                                        //data format:{ x, y, slope};  

float SmokeCurve[3] ={2.3,0.53,-0.43};  //two points from smoke curve are taken point1:(200,3.4) point2(10000,0.62) 
                                        //take log of each point (lg200, lg3.4)=(2.3,0.53)  (lg10000,lg0.63)=(4,-0.20)
                                        //find the slope using these points. take point1 as reference   
                                        //data format:{ x, y, slope};

// sensor and load resistor forms a voltage divider. so using analog value and load value
// we will find sensor resistor.

float ResistanceCalculation(int raw_adc){ 
  return ( ((float)RL_VALUE*(1023-raw_adc)/raw_adc));   // we will find sensor resistor.

float SensorCalibration(){

  int i;                                   // This function assumes that sensor is in clean air.
  float val=0;
  for (i=0;i<50;i++){                   //take multiple samples and calculate the average value
    val += ResistanceCalculation(adcread(0));

  val = val/50;                  
  val = val/RO_CLEAN_AIR_FACTOR;           //divided by RO_CLEAN_AIR_FACTOR yields the Ro according to the chart in the datasheet 
  return val;

float ReadSensor(){
  int i;
  float rs=0;

  for (i=0;i<5;i++) {                                 // take multiple readings and average it.
    rs += ResistanceCalculation(adcread(0));   // rs changes according to gas concentration.

  rs = rs/5;
  return rs;  

int GetGasPercentage(float rs_ro_ratio, int gas_id){
  if ( gas_id == LPG ) {
     return GetPercentage(rs_ro_ratio,LPGCurve);
  else if( gas_id == SMOKE ) {
     return GetPercentage(rs_ro_ratio,SmokeCurve);

  return 0;

//Using slope,ratio(y2) and another point(x1,y1) on line we will find
// gas concentration(x2) using x2 = [((y2-y1)/slope)+x1]
// as in curves are on logarithmic coordinate, power of 10 is taken to convert result to non-logarithmic.

int  GetPercentage(float rs_ro_ratio, float *curve){                                                                          
  return (pow(10,( ((log(rs_ro_ratio)-curve[1])/curve[2]) + curve[0]))); 

Result & Conclusion

Thus we have successfully used MQ-2 sensor with ATmega32 to display LPG and Smoke level on an LCD. By bringing butane gas near the sensor, the MQ-2 sensor has detected the gas and using the above code, we have displayed the gas and smoke level on the LCD. The following video demonstrates the working of MQ-2 gas sensor with ATmega32 microcontroller and LCD.


Further Work

 One can easily modify the code to take action if certain level of gas is reached. For example, you can use DC Motor Control using ATmega32 to run a fan or you can use servo motor or Stepper Motor using ATmega32 to turn on/off supply regulator or open/close window to adjust the gas in the surrounding.

Recommended Tutorial

-  MQ3 Alcohol Analyzer with Arduino


Previous Post Next Post