Чтобы окончательно решить исход вековечной вражды в офисе между «теми, кому дует» и «теми, кому душно» решил разориться на бюджетный датчик содержания CO2 в атмосферном воздухе
и прикрутить к нему сирену. Поскольку цена на такие датчики — совсем негуманная, выбрал вариант «MH-Z19B», который оказался самым бюджетным.
К сожалению, датчик подарил головоломку. Подробности — под катом.
(Внимание — в обзоре много «программизма», ругани в адрес китайских даташитов, присутствует шестнадцатеричная математика — так что если тема DIY вам не близка, проходите мимо, иначе будете разочарованы).
Датчик «MH-Z19B» сделан китайской компанией «Winsen» (
даташит, PDF) и
неоднократно упоминался на Habrahabr и Geektimes. Это
вторая ревизия, с буквой «b» в названии, по результатам китайской «работы над ошибками». Первую ревизию
одним неверным движением можно было ввести в режим калибровки, для которой требовалась атмосфера с нулевым содержанием CO2. Бедолагам, которые в это влетали, приходилось искать баллон с чистым азотом или кислородом, чтобы её организовать. В ревизии «b» китайцы сделали так, что модуль «эталонной» считает смесь с 400ppm углекислоты — то есть его можно, теоретически, перекалибровать просто в лесу или в парке.
Модуль пришёл в паре с небольшим шлейфом, основная плата имеет надпил, позволяющий отломать кусок с разъёмом и вместо этого припаять гребёнки. Модуль работает в двух режимах — UART (передавая показания по последовательному порту на 9600 бод) и PWM, контакты слева и справа, соответственно:
Для удобства я обрезал шлейф и насадил на провода дюпоновские наконечники. Правда, выяснилось, что часть проводов вообще ни к чему не подключена. Напротив, PWM оказался не выведен на шлейф, к контакту пришлось дополнительно подпаиваться, завернув из предосторожности датчик в плёнку поплотнее:
Датчик работает по следующему принципу — он получает по UART девятибайтовые команды (последний байт — CRC) и отвечает также девятибайтовыми пакетами. Замер концентрации СО2 выполняется командой с байтом 0x86:
Также показания можно прочитать, померяв ширину PWM-сигнала:
Тут подстерегала первая проблема — как узнать текущую размерность измерений? Даташит упоминает, что датчик может мерять в диапазаонах от нуля как до 2000, так и от нуля до 5000ppm:
Запросить текущее значение у датчика нельзя, поэтому остаётся только явно задавать размерность при каждом старте. Даташит описывает формат команды, которая скажет модулю, в какой шкале работать:
Почему-то ни одна инструкция в интернете этого вопроса не касается — никто толком не интересовался настройками датчика и просто принимают их как данность. Кряхтим и пишем код для Ардуино, который пошлёт модулю нужную команду:
- 2000 ppm: «2000» в десятичной системе это «0x07 d0» в шестнадцатеричной, получается — третий байт команды будет 0x07, четвёртый байт — 0xD0, CRC (девятый байт) 0x8F
- 5000 ppm: третий байт 0x13, четвёртый байт 0x88, CRC (девятый байт) 0xCB
(CRC вычисляем по формуле из того же даташита, (NOT(Byte1 + Byte2 + Byte3 + Byte4 + Byte5 + Byte6 + Byte7)) +1)
Пробуем и так, и эдак, но в результате получаем на выходе дикие неправдоподобные значения концентрации СО2, вылетающие за паспортные диапазоны показаний датчика в разы. Уже испугавшись, что запороли дорогой прибор, через какое-то время нагугливаем ссылку
revspace.nl/MHZ19 со словами
According to the MH-Z19B datasheet, you can configure the measurement range by putting the desired range in byte 3 and 4. However, unlike what the MH-Z19B datasheet says, you can set the range using the following command (in this case 0x07d0 = 2000 ppm in byte 6 and 7)
Замечательные китайцы ухитрились ошибиться в даташите! Материмся, и вместо третьего и четвёртого байта пишем в шестой и седьмой. Благодаря подсказке неизвестного голландца — модуль воскресает.
Поскольку теперь доверия модулю нет никакого, решил разобраться с его показаниями досконально и сравнить результаты по UART и PWM. Пишем код под Ардуино, который сначала, в блоке setup, даёт команду установки размерности, а потом в цикле loop делает замеры. Модуль располагаем на сквозняке у форточки.
Код (финальный, уже включающий все позднейшие *открытия*
#include <SoftwareSerial.h>
#define pwmPin 10
SoftwareSerial swSerial(A0, A1); // RX, TX
void setup() {
Serial.begin(9600);
swSerial.begin(9600);
pinMode(pwmPin, INPUT);
/*
Источник - https://revspace.nl/MHZ19
2000 ppm range: 0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x8F
5000 ppm range: 0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x13, 0x88, 0xCB
*/
// Этот вариант ("A") с записью команды в 6й и 7й байт - работает
// bytes: 3 4 6 7
byte setrangeA_cmd[9] = {0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x13, 0x88, 0xCB}; // задаёт диапазон 0 - 5000ppm
unsigned char setrangeA_response[9];
swSerial.write(setrangeA_cmd,9);
swSerial.readBytes(setrangeA_response, 9);
int setrangeA_i;
byte setrangeA_crc = 0;
for (setrangeA_i = 1; setrangeA_i < 8; setrangeA_i++) setrangeA_crc+=setrangeA_response[setrangeA_i];
setrangeA_crc = 255 - setrangeA_crc;
setrangeA_crc += 1;
if ( !(setrangeA_response[0] == 0xFF && setrangeA_response[1] == 0x99 && setrangeA_response[8] == setrangeA_crc) ) {
Serial.println("Range CRC error: " + String(setrangeA_crc) + " / "+ String(setrangeA_response[8]) + " (bytes 6 and 7)");
} else {
Serial.println("Range was set! (bytes 6 and 7)");
}
delay(1000);
/*
// Этот вариант ("B") с записью команды в 3й и 4й байт, согласно даташиту - НЕ работает и поэтому закомментирован
// bytes: 3 4 6 7
byte setrangeB_cmd[9] = {0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x13, 0x88, 0xCB};
unsigned char setrangeB_response[9];
swSerial.write(setrangeB_cmd,9);
swSerial.readBytes(setrangeB_response, 9);
int setrangeB_i;
byte setrangeB_crc = 0;
for (setrangeB_i = 1; setrangeB_i < 8; setrangeB_i++) setrangeB_crc+=setrangeB_response[setrangeB_i];
setrangeB_crc = 255 - setrangeB_crc;
setrangeB_crc += 1;
if ( !(setrangeB_response[0] == 0xFF && setrangeB_response[1] == 0x99 && setrangeB_response[8] == setrangeB_crc) ) {
Serial.println("Range CRC error: " + String(setrangeB_crc) + " / "+ String(setrangeB_response[8]) + " (bytes 3 and 4)");
} else {
Serial.println("Range was set! (bytes 3 and 4)");
}
delay(1000);
*/
}
void loop() {
byte measure_cmd[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};
unsigned char measure_response[9];
unsigned long th, tl, ppm = 0, ppm2 = 0, ppm3 = 0;
// ***** узнаём концентрацию CO2 через UART: *****
swSerial.write(measure_cmd,9);
swSerial.readBytes(measure_response, 9);
int i;
byte crc = 0;
for (i = 1; i < 8; i++) crc+=measure_response[i];
crc = 255 - crc;
crc += 1;
if ( !(measure_response[0] == 0xFF && measure_response[1] == 0x86 && measure_response[8] == crc) ) {
Serial.println("CRC error: " + String(crc) + " / "+ String(measure_response[8]));
}
unsigned int responseHigh = (unsigned int) measure_response[2];
unsigned int responseLow = (unsigned int) measure_response[3];
unsigned int ppm = (256*responseHigh) + responseLow;
// ***** узнаём концентрацию CO2 через PWM: *****
do {
th = pulseIn(pwmPin, HIGH, 1004000) / 1000;
tl = 1004 - th;
ppm2 = 2000 * (th-2)/(th+tl-4); // расчёт для диапазона от 0 до 2000ppm
ppm3 = 5000 * (th-2)/(th+tl-4); // расчёт для диапазона от 0 до 5000ppm
} while (th == 0);
Serial.print(ppm);
Serial.print(" <- ppm (UART) ");
Serial.print((ppm/5)*2);
Serial.println(" <- two fifths of it"); // Потом пришло озарение
Serial.print(th);
Serial.println(" <- Milliseconds PWM is HIGH");
Serial.print(ppm2);
Serial.println(" <- ppm2 (PWM) with 2000ppm as limit");
Serial.print(ppm3);
Serial.println(" <- ppm3 (PWM) with 5000ppm as limit");
Serial.println("-----------");
delay(5000);
}
Все замеры проводим, подключив модуль к питанию от 5 вольт; при 3.3 вольтах он выдаёт очевидно некорректные значения по верху диапазона.
В режиме PWM при заданном диапазоне значений от 0 до 2000ppm получаем, в условиях центра города, заполночь у форточки во двор, 1208ppm, что, безусловно, завышено. UART выдаёт нам близкое значение 1227ppm — различия вполне объяснимы ошибками оцифровки PWM-показаний.
Для сравнения, вот примерные дапазоны концентраций СО2, найденные в интернете:
— 350 — 450 ppm: Нормальный уровень на открытом воздухе.
— < 600 ppm: Приемлемые уровни. Уровень. рекомендованный для спален, детских садов и школ.
— 600 — 1000 ppm: Жалобы на несвежий воздух, возможно снижение концентрации внимания.
— 1000 ppm: Максимальный уровень стандартов ASHRAE (American Society of Heating, Refrigerating and Air-Conditioning Engineers) и OSHA (Occupational Safety & Health Administration).
— 1000 — 2500 ppm: Общая вялость, снижение концентрации внимания, возможна головная боль.
— 2500 — 5000 ppm: Возможны нежелательные эффекты на здоровье.
Переключаем датчик в диапазон 0 — 5000ppm. В режиме PWM у той же форточки во двор получаем 478ppm, что гораздо больше похоже на правду. Но вот в режиме UART наш датчик снова выдаёт совершенно неправдоподобное значение 1213ppm.
Десять раз перепроверив формулы, по близости показаний начинаю догадываться, что датчик считает с ошибками в арифметике. Модифицирую код, чтобы формула расчёта концентрации CO2 по данным PWM рассчитывалась с подстановкой всех вариантов верхнего предела значений. В момент какого-то озарения также дополнительно модифицирую код, чтобы значение, полученное по UART,
дополнительно выводилось домноженным на 2000/5000:
диапазон 0 — 2000ppm
Range was set! (bytes 6 and 7)
1227 <- ppm (UART) 490 <- two fifths of it
606 <- Milliseconds PWM is HIGH
1208 <- ppm2 (PWM) with 2000ppm as limit
3020 <- ppm3 (PWM) with 5000ppm as limit
диапазон 0 — 5000ppm
Range was set! (bytes 6 and 7)
1213 <- ppm (UART) 484 <- two fifths of it
241 <- Milliseconds PWM is HIGH
478 <- ppm2 (PWM) with 2000ppm as limit
1195 <- ppm3 (PWM) with 5000ppm as limit
Делаем выводы:
- в качестве рабочего диапазона работы датчика надо задавать 0 — 5000ppm
- несмотря на это, для расчёта значений, полученных через PWM, надо в формулу подставлять константу 2000, а не 5000
- для получения правдивых показаний от UART надо полученное значение умножать на 2/5
- китайским даташитам, даже на вид добротным, верить нельзя
- готовые скетчи для Ардуино из интернета брать нельзя
- показания всех китайских «показометров» надо проверять хотя бы на соответствие здравому смыслу и внутреннюю непротиворечивость
После этого расследования датчик поселится в приборе в офисе, в компании с барометром, датчиком влажности воздуха, содержания пыли и ESP8266 для управления всем этим добром. Хоть я и вдохновился изначально приборчиками в переговорках московского Google, мой вариант не будет иметь цифр и экрана, а вместо этого получит более простую цветовую индикацию, как светофор — а подробные логи будет выкладывать по WiFi на сервер. Впрочем, это уже отдельная история.
P.S. Товар куплен за свои кровные:
ну и было бы полезно указать принцип действия датчика. IR в даташите внушает оптимизм. Но после сказанного про дата в том шите…
Картинка из www.co2meter.com/blogs/news/6010192-how-does-an-ndir-co2-sensor-work — тут объясняется принцип работы. Вкратце — датчик считает поглощение света определённой длины волны и так определяет концентрацию CO2
Я лет 20-30 назад долго ругался матом на апликейшн от интела.
Два дня потреял, когда попытался для экономии времени стянуть кусок кода из апликейгена.
А можете посоветовать датчик pm 2.5? А то у нас в городе не всегда хороший воздух (из-за того, что есть много частных домов с печками, где топят чем попало).
Купил такой для самодельной станции где-то год назад.
Пришлось повозиться с переделкой электроники с софтом и калибровкой ЦАПа на ESP.
Я немного копнул этот вопрос и сделал вывод, что проще всё делать в мелкой ардуинке, а на ESP транслировать показания, мороки меньше.
www.letscontrolit.com/wiki/index.php/Official_plugin_list
(я для MH-Z19 и Sensair S8 использую именно эту прошивку для ESP, в случае необходимости и самому чего подправить можно)
www.letscontrolit.com/wiki/index.php/GP2Y10
На выходе датчика поставил резисторный делитель чтобы уложить вольтаж в границы АЦП ESP 1.024 вольт. Схема есть, если надо.
Для ESP я использую прошивку WiFi IoT и там уже задействую АЦП и один GPIO (15), скрипт написан на С подобном языке, необходимые тайминги выдерживаются.
Поправочные коэффициенты подобрал укутывая датчик в кучу слоев спец фильтровальной ткани и прокачивая воздух насосом. Верхний предел — перекрывая окно карандашом.
Но все равно показания плавают, надо добавить фильтр скользящего окна.
Код выполняется каждые 20 секунд в общем цикле, в конструкторе выглядит так:
Ну или ткнуть пальцем в ссылочку где это лежит?
Схема переделки самого датчика
Полный листинг кода (см по схеме — у меня дисплей 4х20)
opkg install coreutils-stty kmod-usb-serial-ftdi nano
nano /root/mh_z19.sh
chmod +x /root/mh_z19.sh
nano /etc/rc.local
/etc/init.d/cron start
/etc/init.d/cron enable
export EDITOR=nano
crontab -e
Вот так выглядит, когда ты ушёл из дома, и чистота воздуха плавно стремится к отметке 400ppm :-) Когда дома подышишь, и график пересечёт 700ppm, включается вытяжка, и значение примерно так же падает к 500ppm, вытяжка выключается
Не совсем из китая. И после того, как $ скаканул в 2 раза — разумнее стало отнести денег даджету.
А на али ищите по CO2 logger, но дешево всё-равно не будет.
cdn-shop.adafruit.com/product-files/3660/BME680.pdf — см. стр. 8 и цветную табличку на стр. 10
зато в нём барометр и датчик влажности встроен
BME280 5V Atmospheric Pressure Sensor Module for Arduino High Precision New
придётся подождать, что фактически получит chaloc (и, разумеется, это не даст следующему покупателю никаких гарантий)
Это в шестнадцатиричном виде если 16-битное слово — FFFF, то байты у него — FF и FF.
А в восьмеричном если слово 177777, то байты — 377 и 377.
Хде логика, блин?
Практически приходилось в уме частично переводить в двоичный вид…
sqrt(017)=03.., всё честно
и так же красиво с эквивалентным 12-битным словом 07777 :)
Именно потому, что основание натурального логарифмы выгодно в качестве основания системы счисления для ЭВМ, но затруднительно как то сделать цифровую машину с дробным основанием системы счисления (блин, сам уже запутался), была таки машинка с троичным основанием.
Сетунь называлась, на год младше меня… :)
Вот мой, без b, график за полсуток.
Разные показания по UART и PWM у датчика были «из коробки», что и сподвигло на расследование, собственно.
Качественное «запарывание» описано тут — geektimes.ru/post/285572/ — товарищ аж в недокументированный режим MODBUS прибор загнал и снёс калибровку, но для этого он просто грубой силой перебирал коды.
Еще нюансы: датчик выходит на режим через 3 минуты после включения, по UART часто нельзя запрашивать данные (не чаще раза в 10 секунд), UART и PWM могут иметь разные диапазоны, встречал что UART 5000ppm, а PWM 2000ppm, работа сенсора заявлена от 3.6V, 3.3V не подойдут.
Да, 3.3 вольта не подходит — сенсор начинает дико «тупить» и выдаёт значения по верху диапазона.
Оттого веселят другие обзоры на этот модуль, где авторы просто втыкают его и верят показаниям.
Играюсь как раз с этим датчиком достаточно давно (около года). Но недавно решил сравнить MH-Z19, MH-Z19B и Sensair S8 (0053)
1) Этап 1:
В конце прошлого года тестировал одновременно (стояли на расстоянии 2см друг от друга):
2 штуки MH-Z19
2 штуки MH-Z19B (один с отключенной ABC, второй с включенной)
Вывод: MH-Z19B «из коробки» работет вполне нормально (если помещение нормально проветривается). Если помещение проветривается плохо (к примеру раз в неделю) — то обязательно нужно отключать ABC (у MH-Z19B она реализована очень странно, период калибровки всего 1 день).
MH-Z19 можно выкинуть (свои убрал куда подальше). 400 показывает нормально, а вот все что выше — может врать на 200-400ppm легко.
2) Этап 2 (в процессе):
Все теже 2 штуки MH-Z19B (c включенной ABC калибровкой и с отключенной)
1 штука Sensair S8 (купленный за адекватные 36$ на тао (вместе с доставкой!))
Вывод (основанный пока только на 3 днях тестов, что само собой мало):
Нормально откалиброванный MH-Z19B (с отключенной ABC) практически полностью совпадает с S8.
В моем случае все 3 датчика стоят в хорошо прповетриваемой комнате (как минимум раз в сутки открываем окно) — в итоге все показания всех 3 датчиков совпадают (разброс максимум 100ppm, что укладывается в погрешность).
Для себя сделал вывод что вместо MH-Z19B все таки лучше предпочесть S8. Его 8 дней на калибровку выглядят куда адекватнее 1 дня у MH-Z19B.
Итого, за 40$ можно собрать миниатюрный анализатор CO2. Очень компактный, достаточно точный и дешевый.
Все что нужно — платка Wemos, 4 проводка и сам сенсор (картинка не моя) + готовая прошивка (EspEasy):
С термостабилизацией у него, кажется, всё грамотно — на сквозняке от форточки при минус пяти и дома при плюс 25 показания не разбегаются.
Про нагрев — да, есть такой момент. По этому себе буду собирать с ESPхой вниз (у Wemos Mini Pro одна стороная «голая», к ней и будет прижат датчик.
К слову о нагреве — MH-Z19B анализирует раза в 2 чаще (сужу визуально по морганию лампы) чем MH-Z19. И за счет этого греет существенно больше. При комнатной температуре 25, MH-Z19 нагревается до 30, а MH-Z19B аж до 36 (данные по их же внутренним датчикам температуры).
У меня еще есть mh-z14, правда его показания я ни с чем не сравнивал.
Накопал еще статейку geektimes.ru/post/285572/
Про реплику — нет, врядли. Общие у них только распиновка, внешние размеры и принцип действия.
MH-Z14 у меня нет. слишком громоздкий. Он кстати тоже бывает в версии B (думаю что изменения аналогичны MH-Z19 -> MH-Z19B)
На сколько я читал, S8 вполне себе промышленный датчик и используется более менее серьезных устройствах (тот же тионовский MagicAir)
У меня два «безб» лежат дома рядышком и показания совпадают в нижнем диапазоне до 50 единиц, а в верхнем до 200.
Днём при проветривании 'через щелочку' показания становятся 400, ночью поднимаются до 1500..2500. Без проветривания через неделю показывают какой-то бред.
Как итог — оба с B совпадают между собой, плюс совпадают с SenseAir S8.
А вот оба без B — могут показать 400 тогда, когда S8 и B показывают 600-700.
Для себя решил что без B однозначно в мусорку. Но это про мои датчики. Я не берусь утверждать что они все такие.
Когда выбирал, самый дешевый вариант был за 28$, приятно удивился. Но в описании увидел, что точность указана — 70ppm, хотя на официальном сайте указана точность — 40ppm. Похоже дело в версии платы — такая точность (70ppm) указана для версии Senseair S8 Article No. 004-0-0013, хотя продавец на тао указал что версия 053, что очевидно не так (там и фото говорит, что не 053). В итоге нашел современную версию платы (053), но самый дешевый вариант нашел за 44$, что тоже дешевле ebay/aliexpress, но дороже чем у вас.
Вы когда покупали, учитывали версию платы? Интерес вызван большим разбросом цен (28$, 36$, 44$) и честностью продавцов, может чего не учел.
Брал тут item.taobao.com/item.htm?id=536930055559
Но по-моему за 170-180 там все именно 0053
0013 дороже — около 210
Ищу всегда по «Senseair»
А как можно убедиться, что версия платы такая-то, когда прибор будет в наличии?
Мой выглядит в точности вот так
ae01.alicdn.com/kf/HTB10JgyPVXXXXc4XFXXq6xXFXXXv/SenseAir-Infrared-CO2-Carbon-Dioxide-Sensor-S8-0053.jpg
В том числе есть слегка смущающие меня 01.14. Надеюсь это не дата производства :)
Смотрю на статус покупки:
и не могу понять уже пора беспокоиться или все в порядке?
С одной стороны в таблице — статус «оплачено» (я рассчитывал на — «отправлено»). С другой стороны этот заказ находится в статусе «To be shipped». Как правильно это перевести? Будет оправленно? Уже отправлено?
Заранее спасибо!
(«to be continue» — «продолжение следует», но когда?)
«to be received» — «ожидает получения»
Внешний вид такой:
Никаких проблем с датчиком, пока питаешь его не менее 4в, как положено.
Прибор работает уже больше года, круглосуточно, всё штатно.
А то думаю K30 или CozIR LP взять, на taobao они примерно одинаково в районе 70 баксов стоят.
CozIR LP конечно нравится размерами и питанием от 3,3 В, как раз stm32 тоже от 3.3 работает. K30 насколько понимаю от 12 вольт можно запитать.
Датчик CO2 CCS811 ( CJMCU-811 )
homes-smart.ru/index.php/component/kunena/4-zhelezo/1333-datchik-co2-ccs811-cjmcu-811
он по форме не напоминает ход какого-нибудь реального показателя в/вблизи вашей локации?
版本号:1.3
实施日期:2017-12-08
例,2000ppm 量程命令:0xFF 0x01 0x99 0x00 0x00 0x00 0x07 0xD0 0x8F
Кстати, заметьте что в этом даташите нарисован датчик как у автора этого обзора — с разъемом под шлейф. А в даташите по ссылке данной автором обзора плата датчика без разъема. Вероятно версии (прошивки) датчиков изменяют со временем, а продавцы не указывают ее.
За ссылку большое спасибо!
«Третий Ангел вострубил, и упала с неба большая звезда, горящая подобно светильнику, и пала на третью часть рек и на источники вод»
гугл пока справляется:^
«Номер версии: 1.3
Дата реализации: 2017-12-08
Пример: команда диапазона 2000ppm: ...»
____
^ (с технической фигнёй:)
MH-Z19
www.banggood.com/MH-Z19-0-5000PPM-Infrared-CO2-Sensor-For-CO2-Indoor-Air-Quality-Monitor-UARTPWM-p-1094463.html
MH-Z19B
www.banggood.com/MH-Z19B-Infrared-CO2-Sensor-For-CO2-Monitor-NDIR-Gas-Sensor-CO2-Gas-Sensor-0-5000PPM-p-1248315.html
Но случайно наткнулся на espeasy — тоже готовая прошивка для ESP8266, но с поддержкой S8.
В итоге бОльшая часть девайсов у меня на wifi-iot, а там где используются CO2 датчики, там espeasy.
EspEasy кстати имеет более широкую поддержку в том числе и MH-Z19B — имеется возможность «читать» символ «U» по которому можно судить о том когда девайс самокалбируется, а так же есть возмоность эту самую автокалибровку отключить.
Кстати, имейте ввиду что MH-Z19B хорошо работет в помещениях которые хотя бы раз в сутки проветриваются до 400ppm. Если нет — автокалибровку обязательно нужно отключать.
На PWM, судя по всему, диапазон измерения фиксированный — до 2000.
И нигде в статьях не встречал упоминания, что можно снимать показания с V0 — аналогового выхода, где уровнь CO2 показывается напряжением на выходе.
Датчик MH-Z19B, использую UART. По итогу испытаний: датчик работает достоверно в обоих диапазонах (2000 и 5000) без каких-то корректирующих коэффициентов. Конечно, неплохо бы сверить с заведомо точным датчиком, но пока такой возможности нет.
Кое-кто пишет, что по UART нельзя часто опрашивать данные. А в чем проблема? Специально сравнивал графики с интервалом 5с и 60с — показания в целом совпадают (на 5c, конечно, заметнее выбросы типа «случайно выдохнул в сторону датчика»).
Автокалибровку отключил, при этом показания изменились не более 5 ppe (очевидно, датчик еще не успел перекалиброваться).
В целом датчик очень чувствительный и малоинерционный. Думаю, в готовом устройстве вентилятор для принудительного обдува не понадобится.
Свой MH-Z19B я в целях эксперимента опрашивал 10 раз в секунду, всё ок.
По результатам эксперимента сделал вывод что чаще чем 3 секунды нету смысла, ибо датчик меряет CO2 раз в 3 секунды, и до следующего измерения каждый раз выдаёт предыдущий результат измерений.
Посмотрев дорожки на просвет, разводка по цветам проводов:
Желтый — не распаян
Зеленый — RX (уровень сигнала 3.3В)
Синий — TX (уровень сигнала 3.3В)
Красный — Ground
Черный — V0 (выходное напряжение 3.3В, не более 10мА)
Белый — не распаян
Коричневый — ?
Последний распаян, но назначение непонятно. По логике это должен быть HD, но дорожка ведет не к нему, а куда-то внутрь.
http://style.winsensor.com/pro_pdf/MH-Z19B.pdf
Вооружившись переводчиком имеем:
Выходит, его и запитывать можно с этого разъема, а к контактам с другой стороны есть смысл лезть только если хочешь снимать результаты в ШИМ.
С датчиком играюсь уже около двух месяцев.
Автор всё супер написал, спасибо. Можно всё делать как он, и не париться, если бы не упоминание про мифический коэффициент.
Я в итоге показания своего датчика сравнивал с другими приборами. Совпадают 1 в 1.
Подскажите пожалуйста как решить проблему?
Использую датчик MH-Z19, данные собираю через PWM. На макетной плате все отлично работало.
Спаял проводами с ардуино, собрал во временный корпус, через час показания свалились к 400ppm.
Показывает только 395-404 ppm. После перезагрузки немного работал в нормальном режиме. Показывал похожие на правду значения, но снова стал показывать около 400.
Уже перепаивал все, возвращал на макетную плату, ничего не помогает.
Вот мой скетч, если интересно.
Я кучу скетчей перепробовал, и PWM и UART, ничего не показывает.
И наразных arduino и даже esp8266 на lua скрипт пробовал.
Вообще ничего не показывает.
Может мне китаец херню прислал?
Подключаю mh-z19b к arduino uno используя ваш скетч и столкнулся с двумя проблемами:
1) При попытке компиляции вашего кода возникает конфликт переменных:
Заменил переменную PPM на PPM1, однако не уверен, что это правильный путь.
2) Похоже, что отображаемые данные не вполне соответствуют действительности. Ниже показания датчика, находящегося у открытого окна:
Если я правильно расшифровываю данные, ppm = 784, что довольно много при открытом окне (датчик по сути на улице)
значение PWM выглядит гораздо убедительнее, хотя тоже есть сомнения, в сторону занижения значений.
Как думаете, почему может быть некорректная выдача? И как было бы правильно решить проблему с конфликтом переменных?
при покупке на Али я видел 2 релиза данного датчика на 2000 и на 5000, и заказал на 5000.
Не совсем понял, с какой целью реализовано подключение одновременно по UART и по PWM?
расшифруйте, пожалуйста.
Сабж может выдавать концентрацию одновременно по трём каналам. Непоняток по этому сильно интеллектуальному датчику хватает, и кто умеет все каналы свести к одинаковым показаниям — тот красавчик.
Мне не повезло, по UART полный молчок «CCR Error 0/0», если кто может подсказать — буду признателен.
#include <SoftwareSerial.h>;
//////////////////////////////////////////////////////////////////////////////////////////////
SoftwareSerial co2Serial(D1, D2); // RX- D2, TX — D1; //Wemos D1 mini
void setup() {
Serial.begin(9600);
co2Serial.begin(9600);
}
void loop() {
readCo2Sensor();
}
//////////////////////////////////////////////////////////////////////////////////
void readCo2Sensor() // Initialisiere CO2 Sensor MH-Z19
{
byte cmd[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};
unsigned char response[9];
co2Serial.write(cmd, 9);
memset(response, 0, 9);
co2Serial.readBytes(response, 9);
int i;
byte crc = 0;
for (i = 1; i < 8; i++) crc+=response[i];
crc = 255 — crc;
crc++;
if ( !(response[0] == 0xFF && response[1] == 0x86 && response[8] == crc) )
{
Serial.println(«CRC error: » + String(crc) + " / "+ String(response[8]));
}
unsigned int responseHigh = (unsigned int) response[2];
unsigned int responseLow = (unsigned int) response[3];
unsigned int ppm = (256*responseHigh) + responseLow;
Serial.println(ppm);
delay(10000);
}
/////////////////////////////////////////////////////////////////////////////////////////////
Добавил не задокументируемые функции, такие как сброс. Если чего, пишите на e-mail, в программе всё есть.
"…
unsigned long th, tl, ppm = 0, ppm2 = 0, ppm3 = 0;
unsigned int ppm = (256*responseHigh) + responseLow;
..."