После покупки копеечного датчика утечки газа появилось желание разобрать все по полочкам и узнать, что происходит внутри. Информации и статей по датчикам очень много, но большинство ограничено распиновкой стандартного китайского модуля, иногда принципов работы. Про относительно точное определение абсолютных значений информации нет. Забегая наперед скажу, что мы попробуем выжать все из даташита, включая: точные функции определения «попугаев», температурно-влажностной коррекции, некоторых возможностей селекции.
Для примера взят датчик горючих газов (в первую очередь — метана) MQ-4. Если коротко, то чувствительный элемент датчика, в силу своих химических свойств, меняет сопротивление при разной концентрации газов, и выступает в качестве резистора делителя напряжения из которого мы получаем значение напряжения через АЦП. Свойства эти проявляются при определенной температуре элемента для чего датчик необходимо нагреть.
Выше — схематическое представление датчика и схема делителя, где Н – спираль нагрева (33 Ом – около 150 мА, токи великоваты для поделок с контроллерами, нужно учесть при проектировании схемы питания), АВ – выводы чувствительного элемента со сменным сопротивлением в зависимости от концентрации газа, RL – второй резистор делителя, рекомендуемый даташитом – 20 кОм.
Преобразование значений АЦП в ppm
На выходах делителя АЦП мы снимаем значение напряжения (Uadc) исходя из которого можем рассчитать сопротивление датчика Rs (зная номинал второго резистора делителя RL), т.е. определить, что именно нам передает датчик:
Имея значение Rs мы уже можем определить концентрацию газа по графику из даташита. Для определения концентрации используется нехитрое соотношение Rs/Ro. Ro в данном случае – сопротивление элемента датчика при концентрации детектируемого газа 1000 ppm.
«Ro: sensor resistance at 1000ppm of CH4 in the clean air»
означают, что в чистом воздухе содержится нормальная концентрация детектируемого газа в размере 1000 ppm. Однако речь идет о «чистом» воздухе от других газов. Убедиться в этом достаточно легко, поскольку в сети есть документальные отчеты о концентрации «атмосферной приземной концентрации» метана, согласно которым, концентрация на текущий момент составляет около 1800 ppb (что соответствует 1.8 ppm, а никак не 1000 ppm). Также на графике мы видим, что действительно чистый воздух соответствует значению около 4.4 Rs/Ro.
На данном этапе, благодаря АЦП и формуле, мы знаем только значение текущего сопротивления (Rs) от которого будем отталкиваться. Будем считать, что мы замеряли его в чистом (от детектируемых газов) воздухе, при калибровочной температуре и влажности (по даташиту 20С, 65%). Немного позже будет интересный комментарий по поводу влажности при которой проводится калибровка.
Таким образом опорное значение Ro для датчика MQ-4 считаем:
Расчет реальной концентрации газа немного осложняется кривизной графика, и отсутствием внятных контрольных точек, по которым этот график можно откорректировать. Также проблема в низком расширении изображения, из-за чего приходиться по-пиксельно определять контрольные точки.
Для уточнения расчетов наиболее наглядные значения разнесены на сетку координат. По контрольным точкам определена функция зависимости показателей ppm от Rs/Ro:
Построенный график соответствует функции:
Таким образом количество «попугаев» узнаем по формуле:
Немного о температурной компенсации
Исходя из следующего графика даташита известно, что в зависимости от среды, в которой используется датчик, показания отклоняются от действительных:
Для более точного определения зависимости показателей от окружающей среды, также был построен график функции, датчик ограничен температурным диапазоном -10 оС … +50 оС (x=TEMP/10; y=RsRo(error) * 100):
График соответствует функции:
За основу взят график с влажностью 33% (он же, судя по пересечению 1, является калибровочным). Если обратить внимание на влажность, то 1% влажности смещает график на 0.3 по Y (в реальных значениях корректировки RsRo будет разделен на 100 – в графике применен коэффициент для наглядности). «+25» смещает положение графика по Y для «нулевой» влажности, «0.3 х HUM» возвращает положение по Y для актуальной влажности. Некоторое изменение «веса» 1% влажности в крайних температурах малозначно и не учитывается.
Важное замечание: все это применяется, если калибровка проведена в чистом воздухе при влажности 33% и температуре 20 градусов.
Значение корректировки RsRo(error) которое нужно будет добавить к значениям RsRo для компенсации влияния среды, можно рассчитать по формуле:
В этом случае график смещается по Y на разницу влажности калибровки – тут все просто. Немного хуже обстоят дела со смещением по X: простое перемещение будет давать погрешность на кривизну. Если не проводить калибровку в крайних температура, а все же в приближенных к комнатной, эта погрешность не будет значительной.
Что касается реальной зависимости, то пробы датчика в разных условиях показали, что сопротивление действительно наглядно изменяется в зависимости от температуры, а вот влажность в некоторых случаях вовсе не оказывала влияния.
Учитывая точность и цену датчика, — этот блок излишний.
Для расчета уже компенсированного значения:
Переносим теорию в микроконтроллер
Для проверки датчика использован микроконтроллер STM32F407VET и библиотека HAL, значения для корректировки поступали с датчика BME280. В заголовочном файле определяем некоторые постоянные значения для нашего сетапа.
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; //влажность при которой проведена калибровка
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;
}
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;
}
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;
}
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;
}
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; //записываем влажность при которой проведена калибровка
}
}
Примеры использования
Определение значения ppm:
Работа функции расчета температурной компенсации (в данном случае при одинаковой влажности):
Коррекция значений при калибровке в нестандартных условиях:
Заключение
- Принципы, описанные в статье, подходят для работы и с другими датчиками. В том числе точными датчиками TGS2611 (стоимость превышает в 15-20 раз рассмотренный MQ-4). Для адаптации кода к другим датчикам необходимо внести изменения в header-файл и формулу степенной функции определения ppm (функция по контрольным точкам определена программой Graph 4.4.2).
- Требовать высокой точности от датчика стоимостью 1$ не приходиться, возможно для надежных устройств следует обратить внимание на датчики более дорогих серий.
- В среде, чистой от детектируемого газа, показатель RsRo может смещаться на 0,5…0,8, в зависимости от разных факторов (в перую очередь температуры). Таблица коррекции применима только в состоянии детектирования (наличия детектируемого газа около 1000 ppm), т.е. не применима для режима ожидания, где действуют совсем другие соотношения. Конечно же, можно проследить закономерность, но особого смысла в этом нет – в любом из случаев показатели 4…5 RsRo свидетельствуют о отсутствии газов.
- Температурная коррекция в рабочем режиме действительно необходима. Поправку на влажность можно либо исключить, либо снизить «вес» процента влажности в header-файле (и выровнять стартовую позицию по Y).
- Коррекция с поправкой на температуру, при которой проведена калибровка, сомнительна. Желательно калибровать датчик в условиях согласно даташиту (20 градусов Цельсия, 33% влажности (или 65% с со смещением графика зависимости влажности)).
- Селекция дыма действительно соответствует даташиту и определяет задымление начиная с 3.8 RsRo. При непосредственном контакте с дымом — почти стабильно 2.6, и иногда проваливалось до 1.2…1.5.
- При сборке делителя имеет смысл обратить внимание на качество пайки, фильтры и погрешность резистора RL (даташит рекомендует использовать 20 кОм, или в пределах 10…47 кОм). Выбирать по ключевому слову High Precision Resistor.
Полезные ссылки
- Даташит датчика MQ-4
- Ссылка на скачивание Graph 4.4.2 необходима для определения формулы зависимости Rs/Ro. Полностью бесплатна.
Автор: Олег Олейников