Detecção de gás e medição de PPM usando microcontrolador PIC e sensores de gás MQ

Tempo de leitura: 8 minutes

Série MQ Os sensores de gás são tipos muito comuns de sensores usados nos detectores de gás para detectar ou medir certos tipos de gases. Esses sensores são amplamente utilizados em todos os dispositivos relacionados ao gás, como de simples Detectores de fumaça para Industrial Monitores de qualidade do ar. Nós já os usamos Sensores de gás MQ com Arduino para medir alguns gases nocivos como a amônia. Neste artigo, aprenderemos como usá-los sensores de gás com microcontroladores PIC, para medir o valor PPM do gás e exibi-lo em a LCD 16×2.

Como mencionado anteriormente, existem diferentes tipos de sensores da série MQ disponíveis no mercado e cada sensor pode medir diferentes tipos de gases, conforme mostrado na tabela abaixo. Para o bem deste artigo, usaremos o Sensor de gás MQ6 com PIC que pode ser usado para detectar a presença e concentração de gás GPL. No entanto, usando o mesmo hardware e firmware, outros sensores da série MQ também podem ser usados sem grandes modificações na parte de código e hardware.

SensorDetecta
MQ-2Metano, Butano, GLP, fumaça
MQ-3Álcool, etanol, fumaça
MQ-4Metano, gás GNV
MQ-5Gás natural, GPL
MQ-6GPL, gás butano
MQ-7Monóxido de carbono
MQ-8Gás de hidrogênio
MQ-9Monóxido de carbono, gases inflamáveis.
MQ131Ozônio
MQ135Qualidade do ar (benzeno, álcool, fumaça)
MQ136Gás sulfeto de hidrogênio
MQ137Amônia
MQ138Benzeno, Tolueno, Álcool, Acetona, Propano, Gás formaldeído, Hidrogênio
MQ214Metano, gás natural
MQ216Gás natural, gás de carvão
MQ303AÁlcool, etanol, fumaça
MQ306AGPL, gás butano
MQ307AMonóxido de carbono
MQ309AMonóxido de carbono, gases inflamáveis
MG811Dióxido de carbono (CO2)
AQ-104Qualidade do ar

Sensor de gás MQ6

A imagem abaixo mostra o Diagrama de pinos do sensor MQ6 No entanto, a imagem esquerda é um sensor MQ6 baseado em módulo para interagir com a unidade de microcontrolador, o diagrama de pinos do módulo também é mostrado nessa imagem.

O pino 1 é VCC, o pino 2 é o GND, o pino 3 é o desligamento digital (lógica baixa quando o gás é detectado.) e Pin 4 é a saída analógica. O pote é usado para ajustar a sensibilidade. Não é RL. O resistor RL é o resistor certo do LED DOUT

Cada sensor da série MQ possui um elemento de aquecimento e um sentindo resistência. Dependendo da concentração do gás, a resistência à detecção é alterada e, ao detectar a resistência variável, a concentração de gás pode ser medida. Para. meça a concentração de gás em PPM todos os sensores MQ fornecem um gráfico logarítmico que é muito importante. O gráfico fornece uma visão geral da concentração de gás com a razão de RS e RO

Como medir PPM usando sensores de gás MQ?

O RS é a resistência dos sentidos durante a presença de um gás específico, enquanto o RO é a resistência dos sentidos no ar limpo, sem nenhum gás específico. O gráfico logarítmico abaixo retirado da folha de dados fornece uma visão geral da concentração de gás com a resistência à sensação do sensor MQ6. O sensor MQ6 está acostumado detectar a concentração de gás GPL Portanto, o sensor MQ6 fornecerá uma resistência específica durante o ar limpo, onde o gás GPL não está disponível. Além disso, a resistência mudará sempre que o gás GPL for detectado pelo sensor MQ6.

Portanto, precisamos plotar esse gráfico em nosso firmware semelhante ao que fizemos em nosso Detector de gás Arduino Projeto. A fórmula é ter 3 pontos de dados diferentes. Os dois primeiros pontos de dados são o início da curva de GPL, nas coordenadas X e Y. O terceiro dado é a inclinação.

Portanto, se selecionarmos a curva azul profunda que é a curva de GPL, o início da curva nas coordenadas X e Y será o 200 e o 2. Portanto, o primeiro ponto de dados da escala logarítmica é (log200, log2), que é (2,3, 0,30).

Vamos fazer isso como X1 e Y1 = (2,3, 0,30). O final da curva é o segundo ponto de dados. Pelo mesmo processo descrito acima, X2 e Y2 são (log 10000, log0.4). Assim, X2 e Y2 = (4, -0,40). Para obter a inclinação da curva, a fórmula é

=(Y2-Y1)/(X2-X1)
=(-0.40 - 0.30) / (4 - 2.3)
= (-0.70) / (1.7)
= -0.41

O gráfico de que precisamos pode ser dado como

LPG_Curve = {starting X and starting Y, slope}

 LPG_Curve = {2.3, 0.30, -0.41}

Para outros sensores MQ, obtenha os dados acima da folha de dados e do gráfico logarítmico. O valor será diferente com base no sensor e no gás medido. Para este módulo em particular, ele possui um pino digital que fornece apenas informações sobre o gás presente ou não. Para este projeto, ele também é usado.

Componentes necessários

Os componentes necessários para a interface do sensor MQ com o Microcontrolador PIC são fornecidos abaixo

  1. Fonte de alimentação de 5V
  2. ProtoBoard
  3. Resistor de 4,7k
  4. LCD 16×2
  5. Resistor de 1k
  6. Cristal de 20Mhz
  7. Capacitor 33pF – 2pcs
  8. Microcontrolador PIC16F877A
  9. Sensor da série MQ (2, 3 ou 4)
  10. Berg e outros fios de conexão.

 

Esquemático

O esquema para isso Sensor de gás com um projeto PIC é bem direto. O pino analógico é conectado ao RA0 e o digital ao RD5 para medir a tensão analógica fornecida pelo módulo do sensor de gás. Se você é completamente novo no PIC, convém investigar Tutorial do PIC ADC e Tutorial LCD PIC para entender melhor este projeto.

O circuito é construído em uma placa de pão. Depois que as conexões foram concluídas, minha configuração fica assim, mostrada abaixo.

Sensor MQ com programação PIC

A parte principal deste código é a função principal e outras funções periféricas associadas. O programa Completo pode ser encontrado na parte inferior desta página, os trechos importantes do código são explicados da seguinte maneira

A função abaixo é usada para obter o valor de resistência do sensor no ar livre. À medida que o canal analógico 0 é usado, ele está obtendo dados do canal analógico 0. Isto é para calibrando o sensor de gás MQ.

float SensorCalibration(){
  int count;                                              // Esta função irá calibrar o sensor ao ar livre
  float val=0;
  for (count=0;count<50;count++) {                   // pegue várias amostras e calcule o valor médio
                val += calculate_resistance(ADC_Read(0));
                __delay_ms(500);
  }
  val = val/50;                         
  val = val/RO_VALUE_CLEAN_AIR;                              //dividido por RO_CLEAN_AIR_FACTOR resulta em Ro                                                                  
  return val;
}

A função abaixo é usada para ler os valores analógicos do sensor MQ e fazer a média para calcular o valor Rs

float read_MQ()
{
  int count;
  float rs=0;
  for (count=0;count<5;count++) { // faça várias leituras e calcule a média.
      rs += calculate_resistance(ADC_Read(0));   // rs muda de acordo com a concentração do gás.
      __delay_ms(50);
  }
  rs = rs/5;

  return rs;  
}

A função abaixo é usada para calcular a resistência do resistor divisor de tensão e a resistência da carga.

float calculate_resistance(int adc_channel)
{                                                               // o sensor e o resistor de carga formam um divisor de tensão. então, usando o valor analógico e o valor de carga
  return ( ((float)RL_VALUE*(1023-adc_channel)/adc_channel));            // vamos encontrar o resistor do sensor.
}

O RL_VALUE é definido no início do código como mostrado abaixo

#define RL_VALUE (10)    //define a resistência de carga na placa, em quilo-ohms

Altere este valor após verificar a resistência de carga a bordo. Pode ser diferente em outras placas de sensores MQ. Para plotar os dados disponíveis na escala logarítmica, a função abaixo é usada.

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

A curva é a curva de GLP definida acima do código que foi calculado anteriormente em nosso artigo acima.

float ​MQ6_curve[3]  = {2.3,0.30,-0.41};   //Graph Plot, altere isso para um sensor específico

Finalmente, a função principal dentro da qual medimos o valor analógico, calculamos o PPM e o exibimos no LCD é fornecida abaixo

void main() {  
                system_init();
                clear_screen();
                lcd_com(FIRST_LINE);
                lcd_puts("Calibrating....");
                Ro = SensorCalibration();
                //clear_screen();
                lcd_com(FIRST_LINE);      
                lcd_puts("Done!                   ");
                //clear_screen();
                lcd_com(FIRST_LINE);
                lcd_print_number(Ro);
                lcd_puts(" K Ohms");
                __delay_ms(1500);
                gas_detect = 0;
 while(1){
                if(gas_detect == 0){              
                lcd_com(FIRST_LINE);
                lcd_puts("Gas is present  ");
                lcd_com(SECOND_LINE);
                lcd_puts ("Gas ppm = ");
                float rs = read_MQ();
                float ratio = rs/Ro;
                lcd_print_number(gas_plot_log_scale(ratio, MQ6_curve));
                __delay_ms(1500);
                clear_screen();
                }
                else{
                lcd_com(FIRST_LINE);
                lcd_puts("Gas not present  ");
                }
                }
}

Primeiro, o RO do sensor é medido em ar limpo. Em seguida, o pino digital é lido para verificar se o gás está presente ou não. Se o gás estiver presente, o gás é medido pela curva de GPL fornecida.

Usei um isqueiro para verificar se o valor do PPM está mudando quando o gás é detectado. Esses isqueiros de charuto têm gás GLP dentro deles, que quando liberados no ar serão lidos pelo nosso sensor e o valor do PPM nas trocas de LCD, como mostrado abaixo.

 

Código

#include <xc.h>
#include <stdint.h>
#include <math.h>
#include "supporing_cfile/lcd.h"
#include "supporing_cfile/adc.h"
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)
/*
 Program Flow related definition
 */
#define gas_detect   PORTDbits.RD5
#define gas_Detect_Pin_Direction  TRISDbits.TRISD5
#define FIRST_LINE 0x80
#define SECOND_LINE 0xC0
#define RL_VALUE (10)     //define the load resistance on the board, in kilo ohms
#define RO_VALUE_CLEAN_AIR (9.83)  //(Sensor resistance in clean air)/RO,
                                    //which is derived from the chart in datasheet
float MQ6_curve[3]  = {2.3,0.30,-0.41};   //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 Ro =  0;                 //Ro is initialized to 10 kilo ohms
#define _XTAL_FREQ 20000000 //20 Mhz
// System related definitions
void system_init(void);
void introduction_screen(void);
void clear_screen(void);
//int   GetPercentage(float rs_ro_ratio, float *pcurve);
int   gas_plot_log_scale(float rs_ro_ratio, float *curve);
float read_mq();
float calculate_resistance(int raw_adc);
float SensorCalibration();
void main() {  
     system_init();
     clear_screen();
     lcd_com(FIRST_LINE);
     lcd_puts("Calibrating....");
     Ro = SensorCalibration();
     //clear_screen();
     lcd_com(FIRST_LINE);     
     lcd_puts("Done!          ");
     //clear_screen();
     lcd_com(FIRST_LINE);
     lcd_print_number(Ro);
     lcd_puts(" K Ohms");
     __delay_ms(1500);
     gas_detect = 0;
 while(1){
     if(gas_detect == 0){         
         lcd_com(FIRST_LINE);
         lcd_puts("Gas is present  ");
         lcd_com(SECOND_LINE);
         lcd_puts ("Gas ppm = ");
         float rs = read_mq();
         float ratio = rs/Ro;
        lcd_print_number(gas_plot_log_scale(ratio, MQ6_curve));
         __delay_ms(1500);
        clear_screen();
     }
     else{
         lcd_com(FIRST_LINE);
         lcd_puts("Gas not present  ");
         //lcd_com(SECOND_LINE);
        // lcd_print_number(gas_plot_log_scale(read_mq()/Ro, MQ6_curve));
     }
    }
}
 void system_init(){
     TRISB = 0; // Pinos do LCD definidos para fora.
     gas_Detect_Pin_Direction = 1; //Configure RD0 como entrada
     lcd_init();
     ADC_Init();
     introduction_screen();
     //dht11_init();
 } 
 /*
Esta função é para limpar a tela sem comando.
 */
void clear_screen(void){
    lcd_com(FIRST_LINE);
    lcd_puts("                ");
    lcd_com(SECOND_LINE);
    lcd_puts("                "); 
}
 /*
 Esta função é para jogar a introdução.
 */
void introduction_screen(void){
    lcd_com(FIRST_LINE);
    lcd_puts("Bem Vindo");
    lcd_com(SECOND_LINE);
    lcd_puts("CapSistema");
    __delay_ms(1000);
    __delay_ms(1000);
    clear_screen();
    lcd_com(FIRST_LINE);
    lcd_puts("MQ6 Sensor");
    lcd_com(SECOND_LINE);
    lcd_puts("com PIC16F877A");
    __delay_ms(1000);
    __delay_ms(1000);
}
/*
 * Sensor Related Functions
 */
float SensorCalibration(){
  int count;                                   // Esta função assume que o sensor está em ar limpo.
  float val=0;
  for (count=0;count<50;count++) {                   //pegue várias amostras e calcule o valor médio
    val += calculate_resistance(ADC_Read(0));
    __delay_ms(500);
  }
  val = val/50;                  
  val = val/RO_VALUE_CLEAN_AIR;                         //divided by RO_CLEAN_AIR_FACTOR yields the Ro 
                                                        //de acordo com o gráfico na folha de dados
  return val; 
}
float read_mq()
{
  int count;
  float rs=0;
  for (count=0;count<5;count++) {                                 // faça várias leituras e calcule a média.
    rs += calculate_resistance(ADC_Read(0));                      // rs muda de acordo com a concentração do gás.
    __delay_ms(50);
  } 
  rs = rs/5;
  return rs;  
}
float calculate_resistance(int adc_channel)
{                                                                 // o sensor e o resistor de carga formam um divisor de tensão. então, usando o valor analógico e o valor de carga
  return ( ((float)RL_VALUE*(1023-adc_channel)/adc_channel));     // vamos encontrar o resistor do sensor.
}
int gas_plot_log_scale(float rs_ro_ratio, float *curve)
{
    return pow(10,(((log(rs_ro_ratio)-curve[1])/curve[2]) + curve[0]));  
}

Código completo para estudo ( Link )