Dotting over MQ Series gas sensors - deep understanding of datasheet and tuning


After buying a penny gas leak detector, there was a desire to disassemble everything on the shelves and find out what is happening inside. There is a lot of information and articles on sensors, but most are limited to pinout of the standard Chinese module, sometimes the principles of operation. About relatively accurate determination of the absolute values ​​of the information there. Looking ahead, I’ll say that we will try to squeeze everything out of the datasheet, including: the exact functions of determining “parrots”, temperature and humidity correction, and some selection options.

For example, a combustible gas sensor (primarily methane) MQ-4. In short, the sensor element, due to its chemical properties, changes resistance at different gas concentrations, and acts as a resistor of the voltage divider from which we get the voltage value through the ADC. These properties are manifested at a certain temperature of the element for which the sensor must be heated.


Above is a schematic representation of a sensor and a divider circuit, where H is a heating coil (33 Ohms - about 150 mA, currents are too large for crafts with controllers, it must be taken into account when designing a power circuit), AV are the outputs of a sensitive element with interchangeable resistance depending on gas concentration , RL is the second divider resistor recommended by the datasheet - 20 kOhm.

Comment on choosing an ADC reference voltage (Vref)
Hanwei Vc = 5 , Winsen – Vc < 24 . , 3.3 , , . 5 .

Convert ADC to ppm


At the outputs of the ADC divider, we take the voltage value (Uadc) based on which we can calculate the sensor resistance Rs (knowing the value of the second resistor of the divider RL), i.e. determine what exactly the sensor transmits to us:

Rs=(Vref×RL)/UadcRL


With the value of Rs, we can already determine the gas concentration according to the graph from the datasheet. A simple Rs / Ro ratio is used to determine the concentration. Ro in this case is the resistance of the sensor element at a detection gas concentration of 1000 ppm.

Comment about starting points in the calculations
,
«Ro: sensor resistance at 1000ppm of CH4 in the clean air»
, 1000 ppm. «» . , « » , , 1800 ppb ( 1.8 ppm, 1000 ppm). , 4.4 Rs/Ro.


At this stage, thanks to the ADC and the formula, we only know the value of the current resistance (Rs) from which we will repel. We will assume that we measured it in clean (from detected gases) air, at calibration temperature and humidity (by 20 datasheet, 65%). A little later there will be an interesting comment about the humidity at which the calibration is carried out.

Thus, the reference value Ro for the MQ-4 sensor is:

Ro=Rs/4.4



Comment on smoke selection
, , Rs/Ro – 1.8…0.43, – 3.8…2.6. . , , «» . . RsRo 2.8, «» :



The calculation of the actual gas concentration is a little complicated by the curvature of the graph, and the lack of distinct control points by which this graph can be adjusted. Also, the problem is in the low expansion of the image, because of which it is necessary to determine the control points pixel by pixel.

To clarify the calculations, the most obvious values ​​are spaced on a grid of coordinates. The control points determined the function of the dependence of ppm on Rs / Ro:

Comment on measurement limits
400…10000 ppm. (Winsen/Hanwei) 200 400 ppm, 400. ppm Rs/Ro, x = ppm/1000; y= (Rs/Ro)*10:


The constructed graph corresponds to the function:



Thus, the number of "parrots" is recognized by the formula:

A bit about temperature compensation


Based on the following datasheet graph, it is known that, depending on the environment in which the sensor is used, the readings deviate from the actual ones:



Commentary on typical humidity of the measurement environment
, = 65%. RsRo/ppm ( ppm) RsRo/Temp ( ). Rs/Ro = 1 ppm=1000 20, : 33% 65%. . , , 33%. .

To more accurately determine the dependence of indicators on the environment, a function graph was also constructed, the sensor is limited to a temperature range of -10 ° C ... +50 ° C (x = TEMP / 10; y = RsRo (error) * 100):


The graph corresponds to the function:

f(x)=0.83x29.2x+25(0.3×HUM)



The basis is a graph with a humidity of 33% (it, judging by the intersection 1, is a calibration one). If you pay attention to humidity, then 1% humidity shifts the graph by 0.3 Y (in real values ​​of the adjustment RsRo will be divided by 100 - the coefficient is used in the graph for clarity). “+25” shifts the graph position in Y for “zero” humidity; “0.3 x HUM” returns the Y position for actual humidity. Some change in the “weight” of 1% humidity at extreme temperatures is of little significance and is not taken into account.

Important note: all this applies if calibration is carried out in clean air at a humidity of 33% and a temperature of 20 degrees.

The correction value RsRo (error), which will need to be added to the RsRo values ​​to compensate for the environmental impact, can be calculated by the formula:


The task "with an asterisk" is to clarify the compensation during calibration in a non-standard environment
, (20/33%), RsRo(error) :


Y – . X: . , , .

, , , .

, — .

To calculate an already compensated value:


We transfer the theory to the microcontroller


To test the sensor, the STM32F407VET microcontroller and the HAL library were used, the values ​​for correction came from the BME280 sensor. In the header file, we define some constant values ​​for our setup.

mq4.h


#ifndef MQ4_H_
#define MQ4_H_

int mq4_default_work (void); //   
int mq4_advanced_work (float temp, float hum); //   
int mq4_full_work (float temp, float hum, float temp_cal, float hum_cal); //      
int mq4_calib_Ro(void); // 
int mq4_get_adc (void); //   ,   

#define MQ4_ADC hadc1 //    
#define MQ4_ADC_PRECISION 4096 //     (4096 = 12 bit)
#define MQ4_REFERENCE_VOLTAGE 3.3f //  
#define MQ4_STATIC_RESISTOR 20000 //RL -     
#define MQ4_RO_DEF 13600 //Ro -   1000 ppm (RsRo=1),   
#define MQ4_HUM_WEIGHT 0.3f //     (  ) 
#define MQ4_AIR_RSRO 4.4f // RsRo    (   )
#endif /* MQ4_H_ */

mq4.c


mq4.c
#include "mq4.h"
#include "adc.h"
#include "math.h"

int mq4_Rs; //  
int mq4_adc_value; // 
float mq4_volts; // 
float mq4_RsRo; //  .  . 1000 ppm
float mq4_calib_value;  //   RsRo
float mq4_calib_value2; //   RsRo (    )

extern int mq4_Ro; //   1000ppm 
extern int mq4_temp_cal; //     
extern int mq4_hum_cal; //     

Ppm calculation function (no corrections)
int mq4_default_work (void)
{
int ppm; 
int mq4_adc;
float volts;
int Rs;
float RsRo;
//  : 
mq4_adc = mq4_get_adc(); 
//   :
volts = mq4_adc/(MQ4_ADC_PRECISION/MQ4_REFERENCE_VOLTAGE); 
//    :
Rs = ((MQ4_REFERENCE_VOLTAGE * MQ4_STATIC_RESISTOR)/volts)- MQ4_STATIC_RESISTOR; 
//    :
RsRo = (float)Rs / (float)mq4_Ro; 

//   ( ,  ):
mq4_RsRo = RsRo; 
mq4_adc_value = mq4_adc; 
mq4_volts = volts; 
 
if (RsRo>0.437) //    (  )
 //     :
 {ppm = (pow((10/(RsRo*10)),(1/0.36152689)))*1000;} 
 //     -  9999 :
 else {ppm=9999;} 
 
 return (int)ppm;
}


Ppm calculation function with compensation for current temperature and humidity
int mq4_advanced_work (float temp, float hum)
{
int ppm; 
int mq4_adc;
float volts;
int Rs;
float RsRo;
float K; // 

//   :
mq4_adc = mq4_get_adc(); 
//    :
volts = mq4_adc/(MQ4_ADC_PRECISION/MQ4_REFERENCE_VOLTAGE); 

//    
Rs = ((MQ4_REFERENCE_VOLTAGE * MQ4_STATIC_RESISTOR)/volts)- MQ4_STATIC_RESISTOR; 
//    :
RsRo = (float)Rs / (float)mq4_Ro;  
// :
K = ((0.83*(pow((temp/10),2)))-(9.2*(temp/10))+ 25 - (hum*MQ4_HUM_WEIGHT))/100; 
//  
RsRo = RsRo - K; 

//    (  )
if (RsRo>0.437) 
//     :
{ppm = (pow((10/(RsRo*10)),(1/0.36152689)))*1000;} 
//     -  9999ppm:
else {ppm=9999;}
 
//    ( ,  ):
mq4_RsRo = RsRo; 
mq4_calib_value = K; 
mq4_adc_value = mq4_adc; 
mq4_Rs = Rs; 

    return ppm;
 }


Ppm calculation function (with temperature / humidity compensation and correction for calibration medium)
int mq4_full_work (float temp, float hum, float temp_cal, float hum_cal) 
//:    ,       
{
int ppm; 
int mq4_adc;
float volts;
int Rs;
float RsRo;
float K;
//  :
temp = temp + (20 - temp_cal);  

//   : 
mq4_adc = mq4_get_adc(); 
//    :
volts = mq4_adc/(MQ4_ADC_PRECISION/MQ4_REFERENCE_VOLTAGE); 

//     :
Rs = ((MQ4_REFERENCE_VOLTAGE * MQ4_STATIC_RESISTOR)/volts)- MQ4_STATIC_RESISTOR; 
//  :
RsRo = (float)Rs / (float)mq4_Ro;  
//  (   - MQ4_HUM_WEIGHT*(hum_cal-33)          ): 
K = ((0.83*(pow((temp/10),2)))-(9.2*(temp/10))+ 25 - (hum*MQ4_HUM_WEIGHT)+(MQ4_HUM_WEIGHT*(hum_cal-33)))/100; //
//   RsRo:
RsRo = RsRo - K; 

if (RsRo>0.437) ppm = (pow((10/(RsRo*10)),(1/0.36152689)))*1000; 
else {ppm=9999;}

//    ( ,  ) 
mq4_RsRo = RsRo; 
mq4_calib_value2 = K; 
mq4_adc_value = mq4_adc; 
mq4_Rs = Rs; 

   return ppm;
 }


ADC value
int mq4_get_adc (void)
 {
 int mq4_adc_bits; 
 HAL_ADC_Start(&MQ4_ADC);
 HAL_ADC_PollForConversion(&MQ4_ADC,100);
 mq4_adc_bits = HAL_ADC_GetValue(&MQ4_ADC);
 HAL_ADC_Stop(&MQ4_ADC);
    return mq4_adc_bits;
 }


Calibration
int mq4_calib_Ro(void)
{
float mq4_adc_volts;
int Rs;
int Ro;
int mq4_adc;
mq4_adc = mq4_get_adc(); 
mq4_adc_volts = (float)mq4_adc/((float)MQ4_ADC_PRECISION/MQ4_REFERENCE_VOLTAGE); 
//     
Rs = (((float)MQ4_REFERENCE_VOLTAGE * (float)MQ4_STATIC_RESISTOR)/mq4_adc_volts)- (float)MQ4_STATIC_RESISTOR;
//    1000 ppm (      RsRo 4.4  MQ-4):
Ro = Rs/MQ4_AIR_RSRO;
   return Ro;
 }


main.c


#include "main.h"
#include "adc.h"
#include "gpio.h"
#include "mq4.h"

int ppm_def;  //ppm  
int ppm_adv;  //ppm     
int ppm_full;  //ppm        

float mq4_temp_cal = 20; //    
float mq4_hum_cal = 33; //    
extern float mq4_calib_value; //   RsRo
extern float mq4_calib_value2; //   RsRo c   

int mq4_Ro = MQ4_RO_DEF; //   1000ppm   
extern int mq4_Rs;   //    
extern int mq4_adc_value; // 
extern float mq4_volts; //   
extern float  mq4_RsRo; //   .  . 1000 ppm

//  :
float tf = 0.0f, hf = 0.0f; //     

int main(void)
{
 HAL_Init();
 MX_GPIO_Init();
 MX_ADC1_Init();
}

while (1)
{
 //    :
 ppm_def = mq4_default_work();              
 ppm_adv = mq4_advanced_work(tf,hf);
 ppm_full= mq4_full_work(tf,hf,mq4_temp_cal,mq4_hum_cal);
 //   : 
  if(HAL_GPIO_ReadPin(KEY_1_GPIO_Port, KEY_1_Pin)==GPIO_PIN_RESET) 
   {
   mq4_Ro = mq4_calib_Ro(); // 
   mq4_temp_cal = tf;   //     
   mq4_hum_cal = hf;   //     
   }
}

Examples of using


Determining the ppm value:


The function of the calculation of temperature compensation (in this case, at the same humidity):


Correction of values ​​during calibration in non-standard conditions:


Conclusion


  1. , , . TGS2611 ( 15-20 MQ-4). header- ppm ( Graph 4.4.2).
  2. 1$ , .
  3. , , RsRo 0,5…0,8, ( ). ( 1000 ppm), .. , . , , – 4…5 RsRo .
  4. . , «» header- ( Y).
  5. , , . (20 , 33% ( 65% )).
  6. 3.8 RsRo. — 2.6, 1.2…1.5.
  7. , RL ( 20 , 10…47 ). High Precision Resistor.



All Articles