среда, 6 февраля 2019 г.

Датчик газа MQ-2 подключение к Arduino nano

В этой статье я расскажу как подключить датчик газа MQ-2 к Arduino nano.
Описание датчика MQ-2.



Датчик пришел в виде готового модуля, имеет четыре вывода, которые подписаны AO, DO, GND и Vcc. Назначение выводов: AO - это аналоговый выход, DO - это цифровой выход, GND - это земля (минус питания) и Vcc - это +5 вольт. Распиновка проста, но есть одно НО! - цифровой вывод имеет только два состояния - 0 и 1, никаких данных об концентрации регистрируемых датчиком газов с него не получить.
Так же на плате модуля присутствует подстроечный резистор для регулировки чувствительности датчика в случае получения данных с цифрового вывода, вернее порог срабатывания. Для этой цели тут стоит компаратор LM393.
В интернете рекомендуют прогреть новый только что купленный датчик на протяжении 24-рех часов, после чего время его прогрева будет около минуты с моменте включения. В даташите же я нашел Preheat time, время разогрева, и там указано больше 48 часов. Думаю, для домашнего использования вполне достаточно будет и 24-рех часов.

Итак, для начала давайте все же подключим его к ардуине дабы посмотреть что же он нам скажет в не прогретом состоянии. Для получения информации воспользуемся аналоговым выходом датчика, подключив его на аналоговый вход Arduino nano, соединив AO датчика с A0 ардуины. Разведем питание и напишем небольшой скетч, задача которого считывать показания с АЦП ножки A0 и отправки его по UART. Монтаж я сделал на макетной плате, должно получится как-то вот так.



Пример кода



После прошивки ардуины открываем монитор последовательного порта. Данные, что мы получаем, это вовсе не значение газа в PPM, это всего лишь содержание регистра АЦП микроконтроллера. Тем не мене, по этим данным уже можно о чем-то судить. Подождав около получаса и дождавшись, когда датчик немного прогреется, видим, что напряжение уже довольно сильно просело. Берем зажигалку и, не зажигая ее, пускаем газ в датчик. Видим, что датчик работает, так как показания сразу же изменяются. Таким образом можно проверить датчик MQ-2.
Теперь проведем несложный расчет для того, чтоб получить значение сопротивления нашего датчика. Для начала сырые данные АЦП переведем в вольты. Для этого замерим опорное напряжение, которым у нас выступает напряжение питания. У меня мультиметр показал 4,9 вольт. Ацп 10-ти битный, это значит что у него всего 1024 значения, тоесть при 4,9 вольтах он нам даст значение 1023. Делим 4,9 на 1024 и получаем 0,0047 вольта с округлением. Добавляем в наш код переменную float Vdat, равную 0.0047. Дальше попросту значение ацп умножаем на эту переменную и получаем напряжение на ноге A0 в вольтах. Переходим к сопротивлению датчика. На плате модуля у нас есть резистор, который подтягивает наш аналоговый выход на землю, номиналом 5 Ом. По сути весь модуль - это некий делитель напряжения. Прямо в даташите видим формулу:
Resistance of sensor(Rs): Rs=(Vc/VRL-1)×RL
Смотрим схему и таблицу в даташите, разбираем что к чему.



Подставляем то, что нам надо и получаем следующее:
Rs = (4.9/Vdat-1)*5
Займемся формулой расчета ppm. Для этого снова смотрим datasheet на MQ-2.



Из данного куска даташита можно сделать несколько выводов. Первый - с разными газами при одних и тех же показаниях датчика будет разная концентрация газа. Это переводит наш датчик из разряда "измерительный прибор" в разряд "показометр". Максимум, что можно посмотреть - это загрязненность воздуха. Для бытовых нужд этого вполне достаточно, но для чего-то серьезного - нет. Второй вывод: дабы получить точное значение в ppm, датчик нужно откалибровать на чистом воздухе. Это не проблема, открываем окно, суем на улицу датчик, делаем вид, что за окном чистый воздух и сохраняем показатели в переменную Rs_air.
Теперь можем высчитать R0, которое есть в соотношении Rs/R0. На чистом воздухе в графике Rs/R0 составляет примерно 9.5. Делим Rs_air на 9.5, получаем R0.
Вешаем прерывание на ногу микроконтроллера, цепляем туда тактовую кнопку и с помощью этого прерывания вызываем функцию калибровки
int calibr()
{
R0 = Rs_air/9.5;
}
Дальше упираемся в нелинейную функцию. Решать сию задачку для показометра мне влом, потому я попросту разобью данный график на несколько составляющих, в которых прослеживается хоть какая-то линейность. Например, с 200 до 500, с 500 до 1000, с 1000 до 2000, с 2000 до 5000, с 5000 до 10000. Упираемся в то, что это таки показометр, а значит для CO и для, например, пропана показатели будут совершенно разными. Для кого из них строить формулу? Для примера сделаем расчет для CO.
Для начала высчитаем первый угловой коэффициент. Первая точка - это 200 ppm с соотношением Rs/R0 примерно 5.1, вторая - 500 ppm с соотношением 4. Получаем уравнение
K = (4-5.1)/(500-200)= -0.003666

Высчитываем остальные коэффициенты и приступаем к формуле расчета, которая имеет вид y=kx+b, где b - это смещение прямой по оси Y. Для начала рассчитаем для первого отрезка b.
4=-0.003666*500+b
b = 5.8335
После чего высчитываем b для остальных отрезков и приступаем к формированию нашего кода для ардуино. Для каждого кусочка нам необходимы будут разные значения двух одних и тех же переменных. Например, b для первого кусочка и b для второго кусочка - это разные числовые значения. Будем передавать их через переменные в виде аргументов.
Получился вот такой кусок кода

int ppm_co(float k, float b)
{
float pp = 0;
pp = Rs_R0 - b;
ppm = pp/k;
Serial.println(ppm);
}


Rs_R0 = Rs/R0;
if (Rs_R0 > 5.1)
{
Serial.println("<100");
}
else if (4 < Rs_R0 < 5.1)
{
ppm_co(-0.003667, 5.8335);
}
else if (3.1 < Rs_R0 < 4)
{
ppm_co(-0.0018, 4.9);
}
else if (2.1 < Rs_R0 < 3.1)
{
ppm_co(-0.0005, 3.6);
}
else if (1.9 < Rs_R0 < 2.1)
{
ppm_co(-0.0001, 2.4);
}
else if (1.5 < Rs_R0 < 1.9)
{
ppm_co(-0.00008, 2.3);
}
else
{
Serial.println("you died");
}

Теперь несколько советов. Сенсор MQ-2 чувствителен к питанию, потому при отладке помните, что USB порт ПК может давать заниженное питание, мне пришлось использовать питание внешнее. Так же не стоит забывать о времени на прогрев - холодный датчик MQ-2 выдаст абракадабру вместо вменяемых данных. Ну и сам процесс калибровки должен быть в условиях с чистым воздухом. В коде используйте тип переменных, который способен вместить в себя большое число, ибо от этого зависит результат вычислений. Я использовал float для всех чисел, кроме данных с ацп - там мне хватило integer)
Данный код приведен как пример, кода вполне достаточно, дабы регистрировать уровень загрязненности воздуха и включать-выключать вытяжку на кухне, для более серьезных вещей надо считать все не для СО, а для LPG, чтоб добиться более низких порогов срабатывания. Так же из кода можно выкинуть калибровку, замерив и прописав как константу показатель датчика на чистом воздухе.
В интернете гуляет библиотека для датчика MQ-2, у меня чет с ней не сложилось, она просто-напросто отказалась выдавать какие-либо данные. Потому писал свой скетч. Вышеприведенный код написан на C, потому его с легкостью можно использовать на любом микроконтроллере, хоть STM32, хоть PIC, лишь бы был ацп. Выкинуть с него только Serial.print, ибо это ардуиновская библиотека Wire и в других средах разработки ее нет.
P.S. Если кто-то напишет код поинтересней - пишите в комментарии к статье, с радостью почитаю)))