Датчики газа серии MQ находят широкое применение в современной электронике. Они используются для измерения концентрации различных типов газов. Они могут применяться как в простейших детекторах дыма, так и в сложных промышленных системах проверки качества воздуха. В данной статье мы рассмотрим подключение датчика газа MQ6 к микроконтроллеру PIC и измерение с его помощью концентрации газа в единицах PPM (parts per million – частей на миллион). Измеренное значение PPM мы будем выводить на экран ЖК дисплея 16х2.
Модификации датчиков газа серии MQ представлены в таблице ниже. Как видите, их достаточно много и с их помощью можно измерять концентрации широкого спектра газов. В данной статье мы рассмотрим работу только с датчиком MQ6, который позволяет измерять концентрацию сжиженного нефтяного газа (LPG). Но используя тоже самое аппаратное обеспечение, вы по аналогии с материалом данной статьи сможете работать с другими датчиками газа серии MQ.
Датчик | Что измеряет |
MQ-2 | метан, бутан, сжиженный нефтяной газ, дым |
MQ-3 | алкоголь, этанол, дым |
MQ-4 | метан, СПГ |
MQ-5 | природный газ, сжиженный нефтяной газ |
MQ-6 | сжиженный нефтяной газ, бутан |
MQ-7 | окись углерода |
MQ-8 | газообразный водород |
MQ-9 | окись углерода, горючие газы |
MQ131 | озон |
MQ135 | качество воздуха (бензол, алкоголь, дым) |
MQ136 | сероводородный газ |
MQ137 | аммиак |
MQ138 | бензол, толуол, алкоголь, ацетон, пропан, газообразный формальдегид, водород |
MQ214 | метан, природный газ |
MQ216 | природный газ, угольный газ |
MQ303A | алкоголь, этанол, дым |
MQ306A | сжиженный природный газ, бутановый газ |
MQ307A | окись углерода |
MQ309A | окись углерода, горючие газы |
MG811 | двуокись углерода (CO2) |
AQ-104 | качество воздуха |
Также на нашем сайте мы рассматривали подключение различных датчиков газа к плате Arduino:
- анализатор качества воздуха с определением частиц PM2.5 и PM10 на Arduino и датчике SDS011;
- измерение TVOC (летучих соединений) и CO2 с помощью Arduino и датчика качества воздуха CCS811;
- детектор алкоголя (алкотестер) на Arduino;
- измерение уровня аммиака в воздухе с помощью датчика газа MQ-137 и Arduino;
- детектор дыма на Arduino и датчике газа MQ2.
Необходимые компоненты
- Микроконтроллер PIC16F877A (купить на AliExpress).
- Датчик газа MQ6 (купить на AliExpress).
- Программатор PICkit 3 (купить на AliExpress).
- ЖК дисплей 16х2 (купить на AliExpress).
- Кварцевый генератор 20 МГц (купить на AliExpress).
- Конденсаторы 33 пФ (2шт.) (купить на AliExpress).
- Резисторы 1 кОм и 4,7 кОм (купить на AliExpress).
- Источник питания 5V.
- Макетная плата.
- Соединительные провода.
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Датчик газа MQ6
На рисунках ниже показана распиновка датчика газа MQ6 и его внешний вид. На данных рисунках показан датчик газа MQ6 в виде модуля – подобное его исполнение облегчает его подключение к микроконтроллерам.
Контакт 1 датчика газа MQ6 – это VCC, контакт 2 – GND, контакт 3 – цифровой выход (уровень low при обнаружении газа), контакт 4 – аналоговый выход. Встроенный потенциометр (не RL) используется для регулировки чувствительности датчика. Резистор RL – это правый резистор выхода DOUT LED.
Все датчики газа серии MQ имеют в свое составе нагревательный элемент и чувствительное сопротивление (sensing resistance). Величина этого сопротивления изменяется в зависимости от концентрации обнаруживаемого газа, что и позволяет осуществлять измерение его концентрации. Во всех датчиках серии MQ используется логарифмический график для измерения концентрации газа в единицах PPM. Эти графики имеют различный вид в зависимости от соотношения сопротивлений RS и RO.
Как измерять концентрацию газа в PPM используя датчики газа серии MQ
RS – это значение чувствительного сопротивления в присутствии измеряемого газа, а RO – его значение в чистом воздухе, когда измеряемого газа в нем нет. На рисунке ниже представлен логарифмический график для определения концентрации измеряемого газа с помощью датчика MQ6. С помощью данного датчика можно измерять концентрацию сжиженного нефтяного газа (LPG) – он используется, к примеру, в зажигалках. При обнаружении датчиком MQ6 газа LPG значение его чувствительного сопротивления будет изменяться в зависимости от концентрации данного газа в воздухе.
Таким образом, нам необходимо в нашей программе построить этот график также, как мы делали в аналогичном проекте обнаружения газа на основе платы Arduino. Для построения графика нам необходимо будет 3 параметра: первые два – это координаты X и Y двух точек с кривой, а третий – коэффициент наклона нашей прямой.
На представленном выше рисунке кривая для газа LPG выделена темным синим цветом – нам необходимо будет построить именно ее. Координаты начальной точки этой кривой X и Y равны 200 и 2. Соответственно, для логарифмического масштаба (log200, log2) получаем (2.3, 0.30).
То есть в качестве первой необходимой нам точки выберем X1 и Y1 = (2.3, 0.30). Конец кривой это будет наша вторая точка. Аналогичным образом для логарифмического масштаба X2 и Y2 (log 10000, log0.4) получаем X2 и Y2 = (4, -0.40). Для определения коэффициента наклона используем следующую формулу:
1 2 3 4 |
=(Y2-Y1)/(X2-X1) =(-0.40 - 0.30) / (4 - 2.3) = (-0.70) / (1.7) = -0.41 |
В результате получим параметры для построения необходимой нам кривой в программе:
1 2 3 |
LPG_Curve = {starting X and starting Y, slope} LPG_Curve = {2.3, 0.30, -0.41} |
Для других датчиков газа серии MQ вид этих графиков будет отличаться от использованного нами – эту информацию необходимо смотреть в даташите на конкретный датчик. Также вид кривой будет отличаться в зависимости от вида измеряемого газа. Использованный нами датчик MQ6 имеет цифровой контакт, который обеспечивает информацию о том, присутствует ли в окружающем воздухе измеряемый газ или нет – в нашем проекте мы будем использовать данный контакт.
Схема проекта
Схема подключения датчика газа MQ6 к микроконтроллеру PIC представлена на следующем рисунке.
В нашей схеме аналоговый контакт датчика газа MQ6 подключен к контакту RA0 микроконтроллера PIC, а цифровой контакт датчика – к контакту RD5 микроконтроллера. Если вы не очень уверенно себя чувствуете в вопросах использования аналого-цифрового преобразования (АЦП) в микроконтроллерах PIC, то рекомендуем прочитать соответствующую статью на нашем сайте.
Внешний вид собранной на макетной плате конструкции проекта показан на следующем рисунке.
Объяснение программы для микроконтроллера PIC
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
В программе мы запрограммируем функцию SensorCalibration(), в которой мы будем находить значение чувствительного сопротивления датчика в чистом воздухе – эта операция необходима для калибровки датчика газа. Поскольку датчик газа подключен у нас к аналоговому контакту 0, то и показания мы будем считывать с этого контакта.
1 2 3 4 5 6 7 8 9 10 11 |
float SensorCalibration(){ int count; // This function will calibrate the sensor in free air float val=0; for (count=0;count<50;count++) { //take multiple samples and calculate the average value 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 return val; } |
В следующей функции мы будем считывать аналоговые значения с датчика газа MQ6 и усреднять их чтобы получить значение Rs.
1 2 3 4 5 6 7 8 9 10 11 12 |
float read_MQ() { int count; float rs=0; for (count=0;count<5;count++) { // take multiple readings and average it. rs += calculate_resistance(ADC_Read(0)); // rs changes according to gas concentration. __delay_ms(50); } rs = rs/5; return rs; } |
Следующая функция используется для расчета значения сопротивления из делителя напряжения и нагрузочного сопротивления.
1 2 3 4 |
float calculate_resistance(int adc_channel) { // sensor and load resistor forms a voltage divider. so using analog value and load value return ( ((float)RL_VALUE*(1023-adc_channel)/adc_channel)); // we will find sensor resistor. } |
В начале кода программы зададим значение нагрузочного сопротивления RL_VALUE.
1 |
#define RL_VALUE (10) //define the load resistance on the board, in kilo-ohms |
Для своего проекта вам необходимо изменить это значение после того как вы измерите значение нагрузочного сопротивления на плате своего датчика – оно может отличаться для различных датчиков газа серии MQ. Для построения необходимой нам кривой в логарифмическом масштабе будем использовать следующую функцию:
1 2 3 4 |
int gas_plot_log_scale(float rs_ro_ratio, float *curve) { return pow(10,(((log(rs_ro_ratio)-curve[1])/curve[2]) + curve[0])); } |
Для построения этой кривой зададим определенные нами ранее ее параметры:
1 |
float MQ6_curve[3] = {2.3,0.30,-0.41}; //Graph Plot, change this for particular sensor |
В основной функции нашей программы main мы будем измерять аналоговое значение на входе АЦП микроконтроллера PIC, рассчитывать PPM газа и выводить ее значение на экран ЖК дисплея.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
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 "); } } } |
Сначала мы будем рассчитывать значение RO для чистого воздуха. Затем на цифровом контакте датчика MQ6 мы будем проверять присутствует ли измеряемый газ в окружающем воздухе или нет.
Для тестирования работы датчика MQ6 в нашем проекте мы использовали зажигалку. В данной газовой зажигалке содержится газ LPG, при нажатии ее кнопки он высвобождается и попадает в окружающий воздух – его мы и обнаруживаем с помощью датчика.
Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи.
Исходный код программы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
#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 RO_VALUE_CLEAN_AIR (9.83) //(значение чувствительного сопротивления датчика в чистом воздухе)/RO, //определяется из даташита на датчик 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; // LCD pins set to out. gas_Detect_Pin_Direction = 1; //Configure RD0 as input lcd_init(); ADC_Init(); introduction_screen(); //dht11_init(); } /* Функция для очистки экрана ЖК дисплея */ void clear_screen(void){ lcd_com(FIRST_LINE); lcd_puts(" "); lcd_com(SECOND_LINE); lcd_puts(" "); } /* Функция для отображения приветственного сообщения на экране ЖК дисплея */ void introduction_screen(void){ lcd_com(FIRST_LINE); lcd_puts("Welcome to"); lcd_com(SECOND_LINE); lcd_puts("circuit Digest"); __delay_ms(1000); __delay_ms(1000); clear_screen(); lcd_com(FIRST_LINE); lcd_puts("MQ6 Sensor"); lcd_com(SECOND_LINE); lcd_puts("with PIC16F877A"); __delay_ms(1000); __delay_ms(1000); } /* * Sensor Related Functions */ float SensorCalibration(){ int count; // эта функция предполагает что датчик находится в чистом воздухе float val=0; for (count=0;count<50;count++) { //берем много отсчетов и вычисляем их среднее значение 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 //according to the chart in the datasheet return val; } float read_mq() { int count; float rs=0; for (count=0;count<5;count++) { // берем несколько отсчетов и усредняем их rs += calculate_resistance(ADC_Read(0)); // rs изменяется в зависимости от концентрации газа __delay_ms(50); } rs = rs/5; return rs; } float calculate_resistance(int adc_channel) { // датчик и нагрузочное сопротивление образуют делитель напряжения, поэтому, используя значение с выхода АЦП и значение нагрузочного сопротивления return ( ((float)RL_VALUE*(1023-adc_channel)/adc_channel)); // мы найдем значение чувствительного сопротивления } int gas_plot_log_scale(float rs_ro_ratio, float *curve) { return pow(10,(((log(rs_ro_ratio)-curve[1])/curve[2]) + curve[0])); } |