Mh z19 crc error

Всем привет. Есть ли у кого опыт работы с датчиком? Никак не могу понять. В первом датчики ноги паял сам, и думал что перегрел, поэтому он показывал...
  1. Всем привет.
    Есть ли у кого опыт работы с датчиком?
    Никак не могу понять.
    В первом датчики ноги паял сам, и думал что перегрел, поэтому он показывал хрень.
    Через ШИМ удалось заставить работать(по найденным примерам)
    но пришлось вводить поправочные коэффициенты,
    (причем значительные) что бы добиться примерных показаний с «эталонным» датчиком
    (Работает в метеостанции за 10 штук(проверял работает в пределах погрешности)

    По UART я его вообще не смог завести, все примеры кода что я пробовал, всегда возвращают ошибку в контрольном числе.
    Плюнул, заказал новый, уже с припаянными ногами
    (пришло , припаяно супер аккуратно)
    Но он так же по UART возвращает ошибку CRC, а по шим работает с такими же коэффициент
    Вот я и думаю(точнее я уверен) что моих -0 знаний не хватает

    Кто то может помочь?
    Какие данные? предоставить?
    Может у кого есть простой код что бы проверить?

  2. Мошт, просто в UART-ах скоростя не совпадають?

  3. Спасибо. Я собственно этот код и использую.
    И у меня более менее похожее значение по ШИМ если я умножаю на 3800
    А по UART CRC ошибка всегда.

    И другой вопрос.
    Раз это все программным способом подгоняется, на сколько можно верить такому датчику?
    Я вот сравниваю с «эталонным» дак что бы подгонять под его показания, нужно целую таблицу держать.
    Т.к. при одном уровне(диапазоне) CO2 один коэффициент, при другом другой.
    (кстати такая же беда с bme280, тоже никак не могу подобрать коэффициент)

    И еще вопрос, не видели примеров на ардуино или есп для такого датчика t6703
    Он вроде даже i2C поддерживает. но дороже на «рубль»

    Последнее редактирование: 18 июн 2018

  4. Взял чистый код с этого сайта. Не работает.
    Вот что пишет
    CRC error: 225 / 122
    29432 <- ppm (UART) 11772 <- two fifths of it
    274 <- Milliseconds PWM is HIGH
    544 <- ppm2 (PWM) with 2000ppm as limit
    1360 <- ppm3 (PWM) with 5000ppm as limit

    Хотя эталонная метеостанция показывает 992
    При чем по ШИМ меняются показания а по UART всегда
    CRC error: 225 / 122

  5. Вряд ли чем помогу, кроме как советом читать документацию и писать свой драйвер, если чужие не работают.
    По моему опыту, не всегда стоит доверять чужим мнениям.
    Сам писал драйвер для PZEM-4T, который считают капризным, а он просто на разные вопросы отвечает с разной задержкой.
    Также получал данные от совсем нераспространенного датчика СО2.
    Документация и копать, копать…

  6. Спасибо. Я так понимаю это вы про датчик t6703 . Буду копать.

    А есть ли идеи почему оба датчика mh-z19b по UART не работают.
    Да и по ШИМ откровенно говоря хрень показывают при использовании стандартного кода.

  7. Вдруг кто увидит. В июне производитель датчика t67xx выложил мануал.
    проверил вроде работает.
    http://co2meters.com/Documentation/AppNotes/AN161-T6713-arduino-i2c.pdf

  8. убери функцию установки диапазона измерения вначале. не вижу смысла говорить датчику в каком диапазоне ему работать (зачем так делает автор на муське — не понятно).

Moderators: grovkillen, Stuntteam, TD-er

vincen

Normal user
Posts: 91
Joined: 26 Jun 2017, 07:15

Issue with MH-Z19 sensor !!

#1

Post

by vincen » 20 Aug 2017, 15:30

Hi,

Trying to use the MH-Z19 sensor on my ESP unit but encounters a problem. I have updated my ESP to ESP 2.0 dev 11 so to get MH-Z19 implemented in it.
I declare it this way:
Image
and list of all devices in my system (first one is disconnected right now so normal it has no value !):
Image
If I wire it same way as wiki I get these errors in log of ESP:

19535 : MHZ19: Read error : CRC = 81 / 33 bytes read => 255/255/255/255/255/255/40/140/33/
19538 : MHZ19: Shifted 2 bytes to attempt to fix buffer alignment

and if I reverse TX/RX lines from MHZ to ESP, I got that:

383777 : MHZ19: Error, timeout while trying to read
383778 : MHZ19: Unknown response: 0 0 0 0 0 0 0 0 0

so it looks like wiring of Wiki is correct (which makes sense) but what are these CRC errors ??

Vincèn


LisaM

Normal user
Posts: 513
Joined: 11 Apr 2017, 18:29

Re: Issue with MH-Z19 sensor !!

#2

Post

by LisaM » 20 Aug 2017, 20:25

Pics of the wiring?


LouiS22

Normal user
Posts: 2
Joined: 20 Aug 2017, 20:57

Re: Issue with MH-Z19 sensor !!

#3

Post

by LouiS22 » 20 Aug 2017, 21:03

I have the exact same problem :( Briefly I was able to make it work but all of a sudden it’s just not working anymore. I’m on dev11 as well.


LisaM

Normal user
Posts: 513
Joined: 11 Apr 2017, 18:29

Re: Issue with MH-Z19 sensor !!

#4

Post

by LisaM » 20 Aug 2017, 23:30

Code: Select all

718891021 : MHZ19: PPM value: 612 Temp/S/U values: 20/64/10360.00
718891022 : EVENT: MH-Z19#PPM=612.00
718891103 : EVENT: MH-Z19#Temperature=20.00
718891183 : EVENT: MH-Z19#U=10360.00

Working reliable for some time now…


vincen

Normal user
Posts: 91
Joined: 26 Jun 2017, 07:15

Re: Issue with MH-Z19 sensor !!

#5

Post

by vincen » 21 Aug 2017, 07:50

LisaM wrote: ↑20 Aug 2017, 20:25
Pics of the wiring?

Well I followed indication of Wiki:
3.3V from ESP -> Vin MH-Z19
GND -> GND
2 GPIO declared to RX and TX or reverse

Crossed and uncrossed TX/RX but not really much more luck out of error log different but not working !


User avatar

grovkillen

Core team member
Posts: 3621
Joined: 19 Jan 2017, 12:56
Location: Hudiksvall, Sweden
Contact:

Re: Issue with MH-Z19 sensor !!

#6

Post

by grovkillen » 21 Aug 2017, 08:29

And you are sure the sensor is not broken?


vincen

Normal user
Posts: 91
Joined: 26 Jun 2017, 07:15

Re: Issue with MH-Z19 sensor !!

#7

Post

by vincen » 21 Aug 2017, 08:33

grovkillen wrote: ↑21 Aug 2017, 08:29
And you are sure the sensor is not broken?

it’s brand new but I have only one so difficult to know if it’s working or broken :(


User avatar

grovkillen

Core team member
Posts: 3621
Joined: 19 Jan 2017, 12:56
Location: Hudiksvall, Sweden
Contact:

Re: Issue with MH-Z19 sensor !!

#8

Post

by grovkillen » 21 Aug 2017, 08:42

As it seems that you have wired it correctly and also the settings seems fine I’d like to try another sensor instead of starting to turn more stones.


LisaM

Normal user
Posts: 513
Joined: 11 Apr 2017, 18:29

Re: Issue with MH-Z19 sensor !!

#9

Post

by LisaM » 21 Aug 2017, 09:42

vincen wrote: ↑21 Aug 2017, 07:50

LisaM wrote: ↑20 Aug 2017, 20:25
Pics of the wiring?

Well I followed indication of Wiki:
3.3V from ESP -> Vin MH-Z19
GND -> GND
2 GPIO declared to RX and TX or reverse

Crossed and uncrossed TX/RX but not really much more luck out of error log different but not working !

How long are the wires?
CRC errors might point to a wiring problem.
Where is the 3.3v coming from?


vincen

Normal user
Posts: 91
Joined: 26 Jun 2017, 07:15

Re: Issue with MH-Z19 sensor !!

#10

Post

by vincen » 29 Aug 2017, 11:48

LisaM wrote: ↑21 Aug 2017, 09:42How long are the wires?

15cm approximatively ;)

LisaM wrote: ↑21 Aug 2017, 09:42CRC errors might point to a wiring problem.
Where is the 3.3v coming from?

3.3V is coming from the ESP board and I used it previously to power some pressure and temperature sensor without problems !


LisaM

Normal user
Posts: 513
Joined: 11 Apr 2017, 18:29

Re: Issue with MH-Z19 sensor !!

#11

Post

by LisaM » 29 Aug 2017, 20:36

vincen wrote: ↑29 Aug 2017, 11:48
3.3V is coming from the ESP board and I used it previously to power some pressure and temperature sensor without problems !

MH-Z19 sensor technical parameters:
Working voltage 4.5 V ~ 5.5V DC
Average current < 85 mA
Interface level 3.3 V

I have mine connected to 5V, yours is starving…
:ugeek:


User avatar

grovkillen

Core team member
Posts: 3621
Joined: 19 Jan 2017, 12:56
Location: Hudiksvall, Sweden
Contact:

Re: Issue with MH-Z19 sensor !!

#12

Post

by grovkillen » 29 Aug 2017, 22:18

The wiki started (wrongfully) 3.3V, I have now fixed it (5V).

The logics are 3.3V based though, no level converter is needed.

Thanks Lisa!


vincen

Normal user
Posts: 91
Joined: 26 Jun 2017, 07:15

Re: Issue with MH-Z19 sensor !!

#13

Post

by vincen » 29 Aug 2017, 23:47

grovkillen wrote: ↑29 Aug 2017, 22:18The logics are 3.3V based though, no level converter is needed.

Just to be sure it means I still need really 5V to power correctly the sensor right ? ;)


User avatar

grovkillen

Core team member
Posts: 3621
Joined: 19 Jan 2017, 12:56
Location: Hudiksvall, Sweden
Contact:

Re: Issue with MH-Z19 sensor !!

#14

Post

by grovkillen » 30 Aug 2017, 05:57

Yes, communication is 3.3V based.


Who is online

Users browsing this forum: No registered users and 0 guests

Вступление

В этой статье мы проведем простую функциональную проверку датчика CO 2 MH-Z19 , подключив его к raspberry pi 3 UART, и запустим простую программу на Python для регистратора данных, которая выводит результаты на экран и сохраняет результаты в файле. 

Позже файл может быть импортирован в Matlab или Excel для дальнейшего анализа или просто построить график собранных данных. 

Если вы хотите использовать ПК или Raspberry Pi или Beaglebone или любой другой SOC для измерения CO 2 Уровни, датчик с последовательным интерфейсом является хорошим выбором. MH-Z19 оснащен последовательным интерфейсом UART, источником питания 5 В и уровнями 3,3 В IO. 

Это позволяет легко подключить его непосредственно к Raspberry Pi или к ПК (если ПК, вам нужно использовать USB / последовательный преобразователь (уровни CMOS / TTL, а не уровни RS232)).

Он также имеет выход с широтно-импульсной модуляцией (ШИМ), где рабочий цикл изменяется с CO 2, концентрация, которого может быть отфильтрована нижними частотами, чтобы получить аналоговый сигнал, представляющий CO 2

Экономьте здоровье и энергию с CO 2 датчиками

При дыхании люди и животные увеличивают концентрацию СО 2 в выдыхаемом воздухе. Это нормальный биологический процесс. Для атмосферы, на открытом воздухе это не проблема, так как растения потребляют CO 2. Но все-таки сжигание ископаемого топлива увеличивает внешние уровни CO 2, и растения не когут, они просто не успевают обрабатывать такие огромные количества, которые создают очень негативные последствия для нашей спасительной оболочки вокруг планеты, но это не то, о чем мы сегодня поговорим. 

В закрытых жилых помещениях без достаточной вентиляции уровень CO 2 может значительно возрасти от начальных наружных уровней нормы а 400 промилле до внутренних уровней 2000-3000 промилле. Это высокая концентрация CO.

Особенно подверженны содержанию СО современные здания без хорошо спроектированной системы. Поэтому  плотность СО, превышающий 1000 частей на миллион, могут приводить к сонливости, плохой концентрации внимания, потере внимания или увеличению частоты сердечных сокращений.

Современная система вентиляции с регулированием кислорода и CO 2 может регулировать количество подачи свежего воздуха в здании в зависимости от количества людей и их активности. Люди являются основным источником CO2 в здании. Если их количество в комнате удвоится, уровень CO 2 соответственно удвоится. 

Большие здания, такие как школы и офисы, имеют огромные вентиляционные системы, которые используют большое количество электроэнергии только для того, чтобы гарантировать, что внутренний воздух охлаждается или нагревается и заменяется в течение определенного промежутка времени, чтобы обеспечить хорошее качество внутреннего воздуха 24 / 7. 

Много энергии можно сэкономить, управляя такой системой на основе стратегически размещенного CO 2.

О MH-Z19 CO 2 датчике

Датчик MH-Z19 изготовлен в Китае компанией Winsen Lt. Используемый метод измерения основан на принципе недисперсионного инфракрасного излучения (NDIR) для обнаружения присутствия CO 2 в воздухе. 

Основные характеристики по заявлению производителя:

  • хорошая чувствительность;

  • не зависит от кислорода;

  • долгая жизнь;

  • встроенная температурная компенсация;

  • Последовательный интерфейс UART и выход широтно-импульсной модуляции (ШИМ).

Недисперсный инфракрасный датчик (или датчик NDIR) представляет собой относительно простой спектроскопический датчик, часто используемый в качестве детектора газа. Он является недисперсионным в смысле оптического рассеяния, поскольку инфракрасная энергия может проходить через атмосферную камеру для отбора проб без деформации. 

Принцип действия

Основными компонентами датчика NDIR являются инфракрасный источник (лампа), камера для образцов или световая трубка, светофильтр и инфракрасный детектор. Инфракрасный свет направляется через камеру для образцов к детектору. Параллельно имеется еще одна камера с закрытым эталонным газом, обычно азотом. 

Газ в камере образца вызывает поглощение определенных длин волн в соответствии с законом Бера-Ламберта, и затухание этих длин волн измеряется детектором для определения концентрации газа. Перед детектором установлен оптический фильтр, который устраняет весь свет, кроме длины волны, которую могут поглощать выбранные молекулы газа.

Инфракрасный модуль обнаружения газа CO 2 MH-Z19B NDIR обычно используется в:

  • Климатическом оборудовании в школах, офисных зданиях и т. д. ;

  • Экологических домах;

  • Для мониторинга качества воздуха в помещении;

  • Умной бытовой технике.

Руководство пользователя можно найти на сайте //www.winsen-sensor.com 

Технические характеристики MH-Z19

Глядя на датчик снизу, вы увидите следующие выводы:

Штыри имеют шаг 2,54 мм (0,1 дюйма), что облегчает пайку простого однорядного колпачка штифта, как показано на рис. 1 выше.

Подключение к Raspberry Pi

Raspberry Pi 3 подключен к датчику MH-Z19

Расположение и определения контактов MH-Z19

MH-Z19 имеет внутренний аналоговый стабилизатор напряжения с низким падением напряжения от 5 до 3,3 В. Это делает логические сигналы на RX и TX совместимыми с логическими уровнями Raspberry Pi, которые являются CMOS 3.3V. Следовательно, преобразователи уровня не нужны.

Подготовка Raspberry Pi 3 для связи UART

Raspberry pi UART, присутствующий на GPIO (40-контактный разъем), требует некоторой подготовки перед использованием. 

Вы должны: 

  • Выключить консоль, если она использует UART в качестве оболочки для входа; 

  • Включите UART в файл /dev/config.txt. 

Программа тестирования регистратора данных Python MH-Z19

Простая тестовая программа открывает UART COM Port serial0 и пытается прочитать CO 2 измеренных значений от CO 2 датчика каждую минуту. 

Программа выводит каждое измерение на экран и записывает измерения с метками времени в файл в формате csv, которому в качестве имени файла присваиваются текущие дата и время.


#!/usr/bin/python

import serial, os, time, sys, datetime, csv

 

def logfilename():

    now = datetime.datetime.now()

    #Colon is not alowed in filenames so we have to include a lookalike char 

    return 'CO2LOG-%0.4d-%0.2d-%0.2d-%0.2d%s%0.2d%s%0.2d.csv' % 

            (now.year, now.month, now.day, now.hour,

            u'ua789',now.minute, u'ua789', now.second)

 

#Function to calculate MH-Z19 crc according to datasheet

def crc8(a):

    crc=0x00

    count=1

    b=bytearray(a)

    while count<8:

        crc+=b[count]

        count=count+1

    #Truncate to 8 bit

    crc%=256

    #Invert number with xor

    crc=~crc&0xFF

    crc+=1

    return crc

 

    # try to open serial port

    

port='/dev/serial0'

sys.stderr.write('Trying port %sn' % port)

            

try:

    # try to read a line of data from the serial port and parse    

    with serial.Serial(port, 9600, timeout=2.0) as ser:

        # 'warm up' with reading one input

        result=ser.write("xffx01x86x00x00x00x00x00x79")

        time.sleep(0.1)

        s=ser.read(9)

        z=bytearray(s)

        # Calculate crc

        crc=crc8(s) 

        if crc != z[8]:

            sys.stderr.write('CRC error calculated %d bytes= %d:%d:%d:%d:%d:%d:%d:%d crc= %dn' % (crc, z[0],z[1],z[2],z[3],z[4],z[5],z[6],z[7],z[8]))

        else:

            sys.stderr.write('Logging data on %s to %sn' % (port, logfilename()))

        # log data

        outfname = logfilename()

        with open(outfname, 'a') as f:

        # loop will exit with Ctrl-C, which raises a KeyboardInterrupt

            while True:

                #Send "read value" command to MH-Z19 sensor

                result=ser.write("xffx01x86x00x00x00x00x00x79")

                time.sleep(0.1)

                s=ser.read(9)

                z=bytearray(s)

                crc=crc8(s)

                #Calculate crc

                if crc != z[8]:

                    sys.stderr.write('CRC error calculated %d bytes= %d:%d:%d:%d:%d:%d:%d:%d crc= %dn' % (crc, z[0],z[1],z[2],z[3],z[4],z[5],z[6],z[7],z[8]))

                else:       

                    if s[0] == "xff" and s[1] == "x86":

                        print "co2=", ord(s[2])*256 + ord(s[3])

                co2value=ord(s[2])*256 + ord(s[3])

                now=time.ctime()

                parsed=time.strptime(now)

                lgtime=time.strftime("%Y %m %d %H:%M:%S")

                row=[lgtime,co2value]

                w=csv.writer(f)

                w.writerow(row)

                #Sample every minute, synced to local time

                t=datetime.datetime.now()

                sleeptime=60-t.second

                time.sleep(sleeptime)

except Exception as e:

    f.close()

    ser.close()

    sys.stderr.write('Error reading serial port %s: %sn' % (type(e).__name__, e))

except KeyboardInterrupt as e:

    f.close()

    ser.close()

    sys.stderr.write('nCtrl+C pressed, exiting log of %s to %sn' % (port, outfname))

Запуск тестовой программы

Сохраните код тестовой программы указанный выше как mhz19.py. 

Откройте окно терминала (Rasbian Lxterminal) и введите:

sudo python mhz10.py 

На рисунке ниже показан результат простой тестовой программы mhz19.py. Измерения CO 2 отбираются каждую минуту.

Это содержимое файла журнала в формате csv:

Этот формат файла CSV может быть легко импортирован в Excel и в виде графика:

Калибровка датчика CO 2 

Все датчики углекислого газа нуждаются в калибровке. В зависимости от применения это может быть выполнено путем калибровки датчика по известному газу или с использованием метода автоматической калибровки базовой линии (ABC). У обоих есть плюсы и минусы, которые вы должны знать.

Зачем калибровать?

В недисперсионных инфракрасных (NDIR) датчиках диоксида углерода используются инфракрасный источник света и детектор для измерения количества молекул CO 2 в пробном газе между ними. В течение многих лет и источник света, и детектор изнашиваются, что приводит к немного более низкому содержанию CO 2 молекул.

Чтобы бороться с неточными показаниями датчика, во время калибровки датчик нужно скажем так, подвергнуть воздействию известного источника газа, в последствии чего снимаются несколько показаний, вычисляется среднее значение, а разница между новым показанием и исходным показанием, когда датчик был первоначально откалиброван на заводе, сохраняется в Память EPROM. 

Это значение «смещения» затем автоматически добавляется или вычитается из любых последующих показаний, полученных датчиком во время использования.

Калибровка с использованием азота

Самый точный метод CO 2 калибровки датчика — подвергнуть его воздействию 100% азота, чтобы дублировать условия, при которых датчик был первоначально откалиброван на заводе. Калибровка азота также необходима, если будет измеряться уровень CO2 в диапазоне 0-400 промилле. 

Проблема с калибровкой с использованием азота заключается в расходах. Герметичный корпус для калибровки, резервуар с чистым азотом и программное обеспечение для калибровки требуется для соответствия исходной среде заводских испытаний. В противном случае точность калибровки не может быть обеспечена.

Калибровка с использованием свежего воздуха

Если максимальная точность менее важна, чем стоимость, датчик CO 2 можно откалибровать на свежем воздухе. Вместо калибровки при 0 ppm CO2 (азот) датчик калибруется при 400 ppm CO 2 (наружный воздух на самом деле очень близок к 400 ppm), затем из вновь рассчитанного значения смещения вычитается 400 ppm. 

Калибровка свежего воздуха лучше всего подходит для датчиков в производственных установках или теплицах, где он постоянно подвергается воздействию различных уровней CO 2 .

Автоматическая калибровка

Автоматическая калибровка основана на том факте, что в обычных условиях уровень CO 2 возвращается к норме (400 ppm CO2) периодически, по крайней мере, каждые несколько дней. Начиная с этого момента, вы можете заставить свое измерительное программное обеспечение постоянно контролировать самый низкий наблюдаемый уровень CO2 в течение нескольких дней. Если эти самые низкие значения отклоняются от нормы, программное обеспечение датчика может постепенно вносить поправки, чтобы компенсировать это изменение. 

Это эффективный и надежный метод для типичной среды, где уровень CO2 возвращается к нормальному, когда в течение нескольких часов не производится CO2.

AlexGyver


  • #1

Ветка обсуждения проекта Часы-метеостанция.
Страница проекта на AlexGyver.ru: https://alexgyver.ru/meteoclock/
Репозиторий на GitHub: https://github.com/AlexGyver/MeteoClock
Видео:

===========================================================
Здесь обсуждаем сложности с реализацией данного проекта.
Ваши готовые воплощения с фото и описанием выкладываем сюда.
Если вы считаете что проект несовершенен и точно знаете как его улучшить, но сами этим заниматься не собираетесь, попробуйте написать сюда.
Внимание! Если у вас не компилируется или не загружается скетч, значит вы совершили какую-то из типовых ошибок. Для разбора оных имеются специальные темы:
Проблемы с компиляцией скетча
Проблемы с загрузкой скетча
Читайте (ЧИТАЙТЕ, не пишите) эти темы, там на 146% уже есть решение вашего вопроса.

  • #2

Собрал метеостанцию, но показания с датчика СО2 постоянно 5000, при тесте датчики показывают все ОК. Отсоединяю датчик показания меняются на -1. Подскажите что не так ,может сам датчик?

Александр Симонов


  • #3

при тесте датчики показывают все ОК.

Что это значит? И чем отличаются условия «при тесте» от тех условий, когда датчик показывает 5000?

  • #4

При включении тестируются датчики, если с ними все ОК, показывает на экране. При переходе в основной экран, показания датчика СО постоянно 5000

При включении 430 ppm, далее падает до 410, а потом сразу 5000. Все происходит в течении 45 секунд. Что это может значит?

  • Тест.png

    950.7 KB
    Просмотры: 450

  • IMG_20190209_184822.jpg

    390.3 KB
    Просмотры: 250

  • IMG_20190209_184916.jpg

    363 KB
    Просмотры: 236

  • IMG_20190209_185016.jpg

    357.6 KB
    Просмотры: 195

Александр Симонов


  • #5

410-430 при включении это похоже нормально. У меня также. Пробовал мерять СО2 на улице, может у тебя правда дома 5000 ppm?

  • #6

На улице тоже самое 5000 ppm.

Александр Симонов


  • #7

В этих сенсорах есть автокалибровка, которая подстраивается каждые 24 часа. Попробуй оставить сенсор (или всю метеостанцию) включенной на день-два.

Дополню: либо поискать в даташите на сенсор комманду принудительной калибровки, вынести датчик на улицу и перекалибровать его.

  • #8

Всем доброго времени суток! Прошу помощи в дополнении проекта Алекса https://alexgyver.ru/meteoclock/ часы-метеостанция с контролем СО2. Нужно в скетч добавить выход на реле включения вентилятора при загорании на выбор либо желтого либо красного цвета светодиода.

Вот код по такой доработке. Нужно добавить инициализацию порта для управления реле. И заменить функцию setLED. Собственно в нее добавлено 3 строчки, включения и выключения реле, в зависимости от цвета диода.

// Пины
// Пин подключения реле
#define RELE_PIN 10


void setLED(byte color) {
  // сначала всё выключаем
  if (!LED_MODE) {
    analogWrite(LED_R, 0);
    analogWrite(LED_G, 0);
    analogWrite(LED_B, 0);
  } else {
    analogWrite(LED_R, 255);
    analogWrite(LED_G, 255);
    analogWrite(LED_B, 255);
  }
  switch (color) {    // 0 выкл, 1 красный, 2 зелёный, 3 синий (или жёлтый)
    case 0:
      break;
    case 1:
          analogWrite(LED_R, LED_ON);
          // Включаем реле
          digitalWrite(RELE_PIN, HIGH);
      break;
    case 2:
          analogWrite(LED_G, LED_ON);
          // Выключаем реле
          digitalWrite(RELE_PIN, LOW);
      break;
    case 3:
      if (!BLUE_YELLOW) analogWrite(LED_B, LED_ON);
      else {
        analogWrite(LED_R, LED_ON - 50);    // чутка уменьшаем красный
        analogWrite(LED_G, LED_ON);
      }
      // Включаем реле
      digitalWrite(RELE_PIN, HIGH);
      break;
  }
}

  • #9

Подскажите пожалуйста, как отключить автокалибровку Mh-z19b,

  • #10

Доработка прошивки для выключения подсветки на ночь.

// ------------------------- НАСТРОЙКИ --------------------
// Час включения и выключения подсветки
#define BL_START 7
#define BL_STOP 1


// И исправленная функция отрисовки часов
// в конце добавил управление подсветкой
void drawClock(byte hours, byte minutes, byte x, byte y, boolean dotState) {
  // чисти чисти!
  lcd.setCursor(x, y);
  lcd.print("               ");
  lcd.setCursor(x, y + 1);
  lcd.print("               ");

  //if (hours > 23 || minutes > 59) return;
  if (hours / 10 == 0)
    drawDig(10, x, y);
  else
    drawDig(hours / 10, x, y);

  drawDig(hours % 10, x + 4, y);
  // тут должны быть точки. Отдельной функцией
  drawDig(minutes / 10, x + 8, y);
  drawDig(minutes % 10, x + 12, y);

  // Управление подсветкой
  // Для сов, которые засыпают после полуночи
  #if (BL_STOP < BL_START)
    if (BL_STOP <= hours && hours < BL_START) lcd.noBacklight();
      else lcd.backlight();
  #else
    if (BL_START <= hours && hours < BL_STOP) lcd.backlight();
      else lcd.noBacklight();
  #endif

}

Еще думаю можно подтянуть дополнительное питание подсветки через резистор. Тогда она будет не выключаться а гаснуть до слабого свечения.

Изменено: 3 Мар 2019

  • #11

Есть вопросик, хочу сделать возможность корректировки времени без перепрошивки ардуины. Самый простой способ, на мой взгляд — это командами через монитор компорта. Типа H15 [Ентер] M33 [Ентер].

  if (Serial.available() > 0) {
      String buf_txt = Serial.readString();
      
      if (buf_txt.substring(0,1) == "H"){
        Serial.println("Set Hours -> "+buf_txt.substring(1,3));
      }

      if (buf_txt.substring(0,1) == "M"){
        Serial.println("Set Minute -> "+buf_txt.substring(1,3));
      }

  }

Собственно не смог найти, в каком формате надо подавать значения в функцию DateTime()?

Изменено: 5 Мар 2019

  • #12

Привет, нужна помощь) Экран дисплея ничего не показывает, тупо горит подсветка, адрес менял…
С чем это может быть связано?

  • #13

Привет, нужна помощь) Экран дисплея ничего не показывает, тупо горит подсветка, адрес менял…
С чем это может быть связано?

Там с обратной стороны крутилка есть, ее надо покрутить потихоньку, пока не появятся циферки и станут максимально контрастными.

  • #14

вчера сделал. все здорово, спасибо., вопрос а можно сделать регулировку яркости дисплея? по времени а то ночью слишком яркий

  • #15

вчера сделал. все здорово, спасибо., вопрос а можно сделать регулировку яркости дисплея? по времени а то ночью слишком яркий

Можно, я сделал. Для управления подсветкой нужно добавить еще один проводок для управление с помощью ШИМ сигнала с ардуино.
Провод пускается со свободного пина с ШИМ (НАПРИМЕР 10) на верхний контакт перемычки на дисплее (перемычку снять).
Ну и прошивку подкорректировать.
Мой вариант прошивки на гитхабе — https://github.com/alex-anp/alexgyver_meteo_clock

  • #16

Мой вариант корпуса:

3.JPG
2.JPG

Датчики вынесены отдельно. Разъём питания использовал DC5.5×2.1mm, ну потому, что БП у меня халява с такими штекерами :)

STL для повторения или для основы своего варианта: https://yadi.sk/d/2JY00BJpWVtLKw

Ну или тут:
Зы. Рамку и подставку можно напечатать отличным от корпуса цветом, будет отлично смотреться ;)

  • 202.5 KB
    Просмотры: 9

  • 167.3 KB
    Просмотры: 6

  • 23.6 KB
    Просмотры: 7

  • 596.7 KB
    Просмотры: 4

  • 264.4 KB
    Просмотры: 4

  • 91.7 KB
    Просмотры: 6

  • 12.8 KB
    Просмотры: 6

  • #17

Приет. У меня возникли некоторые трудности и надеюсь тут мне помогут их решить.

В проекте меня в основном интересовал контроль уровня СО2 и я заказал MH-Z19, но когда он пришел мне не удалось получить с него данные.
Я заливал скетч из примеров библиотеки (пробовал и MHZ19_getppm и MHZ19_zerocalib ) но ардуина не могла получить с него ответ

error: can’t get MH-Z19 response.
MH-Z19 now warming up… status:error: can’t get MH-Z19 response.
-1

Думал может плохой контакт, прозванивал и все прозванивается.
Номера пинов не напутал. (const int rx_pin = 2; const int tx_pin = 3; )
Сам датчик подмигивает красным светодиодом через белую пленку.

Может кто-то знает в чем может быть проблема?

photo_2019-03-26_10-01-59.jpg

  • #18

tx -> rx и rx->tx

Это «приём» и «передача». Если приёмник соединить с приёмником, а передатчик с передатчиком, то какая будет связь? )

  • #19

tx -> rx и rx->tx

Это «приём» и «передача». Если приёмник соединить с приёмником, а передатчик с передатчиком, то какая будет связь? )

Понял, спасибо. Это выглядит для меня немного контринтуитивно но я только начинаю, буду знать)

Но теперь он застрял в состоянии

MH-Z19 now warming up… status:0

Висит в нем уже минут 20. Я опять делаю что-то не так?

  • #20

Проблема с питанием кажется. Как питаешь датчик? Попробуй дать внешнее 5В питание датчику. Или просто пересобери схему

  • #21

Проблема с питанием кажется. Как питаешь датчик? Попробуй дать внешнее 5В питание датчику. Или просто пересобери схему

Питал от ардуины, сейчас подал внещние 5в и теперь выдает

MH-Z19 now warming up… status:-1

Уже без can’t get MH-Z19 response.

photo_2019-03-27_19-56-16.jpg

  • #23

Какой-то странный скетч.
Непонятно зачем #include <ESP8266WiFi.h>,
#define MH_Z19_RX D4 такой синтаксис IDE вообще не принимает
после замены этого плюгуло варнингом про переполнение инта
Но я все равно его зашил но с тем же результатом. Зависает в Preheating

  • #24

@Vedro401, на схеме с последнего фото, как мне кажется,
не хватает перемычки gnd arduino-минус внешнего питания

  • #25

@Vedro401, на схеме с последнего фото, как мне кажется,
не хватает перемычки gnd arduino-минус внешнего питания

Добавил, без эффекта, все так же возвращает нули.
Да и не понимаю как это должно было повлиять? Датчик питается и шлет сигнал, ардуина его замеряет и понимает, зачем им иметь общую землю?

Permalink

Cannot retrieve contributors at this time


This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters

Show hidden characters

/*
Every time communication is initiated, a code is subsequently
generated to represent the result of the attempt. This can
be used to monitor your program and pinpoint any difficulties
your program might be having.
The codes are as followed:
RESULT_NULL = 0, // This should not occur, and suggests a library logic error
RESULT_OK = 1, // Communication was successful
RESULT_TIMEOUT = 2, // Timed out waiting for a response
RESULT_MATCH = 3, // Received data does not match the usual syntax expected
RESULT_CRC = 4, // Received data does not match the CRC given
RESULT_FILTER = 5, // Filter was triggered (see FilterUsage example)
RESULT_FAILED = 6 // Not currently used
*/
#include <Arduino.h>
#include «MHZ19.h«
#define RX_PIN 10
#define TX_PIN 11
#define BAUDRATE 9600 // Native to the sensor (do not change)
MHZ19 myMHZ19;
#if defined(ESP32)
HardwareSerial mySerial(2); // On ESP32 we do not require the SoftwareSerial library, since we have 2 USARTS available
#else
#include <SoftwareSerial.h> // Remove if using HardwareSerial or non-uno compatible device
SoftwareSerial mySerial(RX_PIN, TX_PIN); // (Uno example) create device to MH-Z19 serial
#endif
unsigned long getDataTimer = 0;
void setRange(int range);
void setup()
{
Serial.begin(9600);
mySerial.begin(BAUDRATE); // Uno Example: Begin Stream with MHZ19 baudrate
myMHZ19.printCommunication(); // Error Codes are also included here if found (mainly for debugging/interest)
myMHZ19.begin(mySerial); // *Important, Pass your Stream reference
}
void loop()
{
if (millis() — getDataTimer >= 2000)
{
int CO2; // Buffer for CO2
CO2 = myMHZ19.getCO2(); // Request CO2 (as ppm)
if(myMHZ19.errorCode == RESULT_OK) // RESULT_OK is an alias for 1. Either can be used to confirm the response was OK.
{
Serial.print(«CO2 Value successfully Received: «);
Serial.println(CO2);
Serial.print(«Response Code: «);
Serial.println(myMHZ19.errorCode); // Get the Error Code value
}
else
{
Serial.println(«Failed to recieve CO2 value — Error«);
Serial.print(«Response Code: «);
Serial.println(myMHZ19.errorCode); // Get the Error Code value
}
getDataTimer = millis();
}
}

Время прочтения
4 мин

Просмотры 91K

Практически любая метеостанция, включая дешевые китайские модели за несколько долларов, умеет измерять основные параметры воздуха — температуру и влажность. С углекислым газом все сложнее: бытовых приборов, способных его измерять, практически нет в продаже. Усложняет ситуацию и то, что CO2 — газ без цвета и запаха, так что «носом» ощутить его концентрацию практически невозможно.

Подробности и измерения под катом.

Сам датчик MH-Z19 уже описывался здесь на сайте. За основу была взята статья «Обзор инфракрасного датчика CO2», а данный материал является его логическим продолжением. Про измерение концентрации CO2 на улице было написано здесь, однако данных о концентрации в квартире там не приводилось. Восполним этот пробел.

Железо

Первым делом на eBay были заказаны следующие компоненты:
Arduino Micro ATmega32U4 3.3V (цена вопроса 5$). Т.к. датчик имеет 3-вольтовую логику, обычные Arduino лучше не использовать.
OLED LCD-дисплей I2C 0.91«128×32 (цена вопроса 7$). Дисплей подключается к стандартным i2c-пинам Arduino.
— Собственно датчик MH-Z19 (цена вопроса 28$).
— Набор проводов с разъемами для штыревых контактов (цена вопроса 1-2$)
Таким образом, общая стоимость составила ~40$, или 2600р. Фирменный прибор от известной компании стоит примерно вдвое дороже, хотя здесь скорее вопрос не экономии, а технического интереса.

Код для Arduino был позаимствован из вышеприведенной статьи, в него был добавлен вывод данных на дисплей, а для более удобного анализа данных вывод был переделан в формат простой строки с разделителем. Также были добавлены метки времени, каждая соответствует 10 секундам.

Исходный код

#include <SoftwareSerial.h>
#include <Wire.h>

// I2C OLED
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
#define I2C_ADDRESS 0x3C
SSD1306AsciiWire oled;

// CO2 sensor:
SoftwareSerial mySerial(8,9); // RX,TX
byte cmd[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79}; 
unsigned char response[9];

void setup() {
  // Serial
  Serial.begin(9600);
  mySerial.begin(9600);

  // OLED
  Wire.begin();         
  oled.begin(&Adafruit128x32, I2C_ADDRESS);
  oled.set400kHz();  
  oled.setFont(ZevvPeep8x16);  

  oled.clear();  
  oled.println("setup::init()");
}

long t = 0;

void loop() 
{
  mySerial.write(cmd, 9);
  memset(response, 0, 9);
  mySerial.readBytes(response, 9);
  int i;
  byte crc = 0;
  for (i = 1; i < 8; i++) crc+=response[i];
  crc = 255 - crc;
  crc++;

  oled.clear();  
  if ( !(response[0] == 0xFF && response[1] == 0x86 && response[8] == crc) ) {
    Serial.println("CRC error: " + String(crc) + " / "+ String(response[8]));
    oled.println("Sensor CRC error");
  } else {
    unsigned int responseHigh = (unsigned int) response[2];
    unsigned int responseLow = (unsigned int) response[3];
    unsigned int ppm = (256*responseHigh) + responseLow;
    Serial.print(String(t)); Serial.print(","); Serial.print(ppm); Serial.println(";");
    if (ppm <= 400 || ppm > 4900) {
      oled.println("CO2: no data");          
    } else {
      oled.println("CO2: " + String(ppm) + " ppm"); 
      if (ppm < 450) {   
        oled.println("Very good");
      }
      else if (ppm < 600) {   
        oled.println("Good");
      }
      else if (ppm < 1000) {   
        oled.println("Acceptable");
      }
      else if (ppm < 2500) {   
        oled.println("Bad");
      }
     else {   
        oled.println("Health risk");
      }
    }
  }
  delay(10000);
  t += 10;
}

Все это было собрано вместе, скетч залит в ардуину, результат выглядит примерно так:
image

Конечно это не верх промышленного дизайна (в планах подыскать какой-то корпус), но для задачи показометра, способного работать как автономно, так и передавать данные по USB, устройство вполне справляется. Для получения данных по USB достаточно открыть в Arduino IDE монитор порта, в нем будут выводиться данные. Текст оттуда можно скопировать и открыть в любой программе, например в Excel.

Измерения

Следующий вопрос: что мы собственно измеряем? Устройство выдает данные в ppm (parts per million, частей на миллион). 1000 ppm = 0,1% содержания СО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: Возможны нежелательные эффекты на здоровье.

И наконец, результаты. Датчик был поставлен на кухне, окна металлопластиковые, время измерения около 8 часов.

Результаты оказались довольно-таки интересными. По горизонтали время в секундах, 3600 секунд соответствуют 1 часу.

Кривые на графике расшифровываются так:
0ч: показания около 420ppm (соответствуют уличным), дома никого не было, я пришел с работы и заодно включил датчик.
0-2 часа: я нахожусь на кухне, видно как в присутствии человека концентрация co2 медленно растет где-то до 900ppm.
2-4 часа: я ушел из помещения, видно как концентрация медленно спадает.
4-6 часов: я вернулся обратно, концентрация снова стала расти.
6й час: на плиту поставлена кастрюля с пельменями. Интересно видеть, как концентрация практически моментально увеличилась до 1700ppm, затем стала медленно спадать. Хотя газ горел недолго (минут 10-15) высокие уровни >1000 ppm держатся не менее часа.
Конец графика: было открыто окно, и уровень co2 упал практически сразу же.

Выводы

Устройство оказалось довольно-таки интересным, и особенно актуальным для работающих дома за компьютером. Так например, за время написания этой статьи уровень co2 вырос в помещении с 500 до 770ppm. Поглядывание на экран заставляет либо чаще открывать окно, либо наконец-таки задуматься об устройстве в доме нормальной вентиляции (наверное режим микропроветривания в окне был бы не лишним, а лучше какая-то вытяжка). Если бы я сейчас покупал новые окна, наверно задумался бы о более-менее качественной модели с нормальным проветриванием.

Также важно отметить актуальность хорошей вентиляции на кухне: как показывает график, даже за 10 минут одна газовая горелка может „выжечь“ весь запас кислорода, доведя концентрацию CO2 до весьма высокой. Измерения в спальне показали, что в плане вентиляции тоже все не очень хорошо: к утру концентрация co2 составляет более 1000ppm, а для умственного труда хороший сон это весьма актуально.

В общем, это нехитрое и недорогое устройство позволяет весьма эффективно проверить качество воздуха в квартире или офисе.
Автор желает всем хорошего здоровья и хорошего настроения. Ну и хорошего воздуха разумеется, тоже.

1. MH-Z14A — самый заслуженный, но вполне рабочий датчик. Отличается крупным размером.
2. MH-Z19 — «народный» датчик, бюджетный вариант.
3. MH-Z19В — Это исправленная и дополненная версия MH-Z19.
4. SenseAir S8 — самый дорогой и самый авторитетный.

Я уже делал обзор трех из четырёх сегодняшних датчиков. Там можно найти их технические характеристики. Все они более-менее одинаковы. Так что сегодня остановимся на невошедшим в тот отбор MH-Z19B.

Поставляется я антистатическом пакете:

Внутри сам датчик, ножки уже припаяны:

Корпус датчика такой же, как и у MH-Z19, но платы немного отличаются:

Наклейка сбоку позволяет их не перепутать:

Мое устройство выглядит как новогодняя елка:

В прошлом обзоре его уже довольно обсмеяли, так что я не буду на нем останавливаться подробно.Там просто ардуина, экран, часы, четыре датчика, логгер, записывающий на флешку и блютус адаптер.

Если кому интересен код — вот код:

при нажатии выпадет несколько экранов


/*
© Tykhon, 2019.

MH-Z19
TX: 3<->5 A0
RX: 3<->5 A1
Gnd:      Gnd
Vin:      +5v

MH-Z19b
TX: 3<->5 4
RX: 3<->5 A1
Gnd:      Gnd
Vin:      +5v


MH-Z14A
1_+5v:    +5v
2_Gnd:    Gnd
11_RX: 3<->5 7
10_TX: 3<->5 6


S8:
G+:       +5v
G0:       Gnd
Rx: 3<->5 A3
Tx: 3<->5 A2

DS3231
SCL:      A5
SDA:      A4
Gnd:      Gnd
VDD:      5v


TFT
Led: -> 150 Ohm -> 5v
SCK: -> 1 KOhm -> 13
SDA: -> 1 KOhm -> 11
A0:  -> 1 KOhm -> 8
Reset: -> 1 KOhm ->  9
CS:  -> 1 KOhm -> 10
Gnd:      Gnd
Vcc:      5v

*/

#include "Adafruit_GFX.h"                 // for LCD Core graphics library
#include <Adafruit_ST7735.h>              // for LCD  Hardware-specific library
#include <SoftwareSerial.h>
#include "Wire.h"

/////////////////////// for LCD //////////////////////////////

#define TFT_CS     10
#define TFT_RST    9  // you can also connect this to the Arduino reset in which case, set this #define pin to -1!
#define TFT_DC     8

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST);  //for LCD 

#define DS1307_ADDR 0x68                     // RTC address

int s8_co2;
int z14_co2;
int z19_co2;
int z19b_co2;
int z19_t;
int z19_ss;
int z19b_t;
int z19b_ss;
int s8_co2_last;
int z14_co2_last;
int z19_co2_last;
int z19b_co2_last;
int s8_co2_mean_last;
int z14_co2_mean_last;
int z19_co2_mean_last;
int z19b_co2_mean_last;
int s8_co2_mean;
int z14_co2_mean;
int z19_co2_mean;
int z19b_co2_mean;
int s8_co2_mean2;
int z14_co2_mean2;
int z19_co2_mean2;
int z19b_co2_mean2;


SoftwareSerial mySerial_z19(A0, A1);
SoftwareSerial mySerial_z19b(4, 5);
SoftwareSerial mySerial_s8(A2, A3);
SoftwareSerial mySerial_z14(7, 6);



byte cmd_z14[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79}; 
unsigned char response_z14[9]; 
String ppmString = " ";


byte cmd_z19[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79}; 
byte cmd_s8[7] = {0xFE,0x44,0x00,0x08,0x02,0x9F,0x25}; 
unsigned char response_z19[9];
unsigned char response_z19b[9];
byte response_s8[] = {0,0,0,0,0,0,0};

unsigned int current_minute, lastminute;
int second_delay = 30000;                     // delay between measurements, ms
int work_period = 2;                          // period for recording data, min
float smoothing_factor = 0.5;                 // coefficient for Kalman filter
float smoothing_factor2 = 0.15;               // coefficient for Kalman filter

////////////////////////////////////////   functions    //////////////////////////////////////////////


byte bcdToDec(byte val)  {
  return ( (val/16*10) + (val%16) );
}


String getdate(){
  Wire.beginTransmission(DS1307_ADDR);      // Reset the register pointer
  byte zero = 0x00;
  Wire.write(zero);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDR, 7);
  int secondint = bcdToDec(Wire.read());
  int minuteint = bcdToDec(Wire.read());
  current_minute = minuteint;
  int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
  int weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  int monthDay = bcdToDec(Wire.read());
  int month = bcdToDec(Wire.read());
  int year = bcdToDec(Wire.read());
  String second = String(secondint); if (secondint < 10) {second ="0"+second;};
  String minute = String(minuteint); if (minuteint < 10) {minute ="0"+minute;};
  return String(hour)+":"+minute+":"+second+" "+String(monthDay)+"/"+String(month)+"/"+String(year);
}



void sendRequest_s8(byte packet[]){ 
 mySerial_s8.begin(9600);
 while(!mySerial_s8.available()){                       //keep sending request until we start to get a response 
    mySerial_s8.write(cmd_s8,7); 
    delay(50); 
 }
 int timeout=0;                                         //set a timeout counter 
  while(mySerial_s8.available() < 7 ) {                 //Wait to get a 7 byte response 
    timeout++; 
    if(timeout > 10) {                                  //if it takes to long there was probably an error 
        while(mySerial_s8.available())                  //flush whatever we have 
        mySerial_s8.read(); 
        break;                                          //exit and try again 
    } 
    delay(50); 
  } 
 for (int i=0; i < 7; i++) { 
      response_s8[i] = mySerial_s8.read(); 
 }
  mySerial_s8.end();
}                      



unsigned long getValue_s8(byte packet[]) 
{ 
 int high = packet[3];                                   //high byte for value is 4th byte in packet in the packet 
 int low = packet[4];                                    //low byte for value is 5th byte in the packet 
 unsigned long val = high*256 + low;                     //Combine high byte and low byte with this formula to get value 
 return val; 
}


void sendRequest_z14(){
  mySerial_z14.begin(9600);
  mySerial_z14.write(cmd_z14, 9);
  memset(response_z14, 0, 9);
  mySerial_z14.readBytes(response_z14, 9);

  int i;
  byte crc = 0;
  for (i = 1; i < 8; i++) crc+=response_z14[i];
  crc = 255 - crc;
  crc++;
  if ( !(response_z14[0] == 0xFF && response_z14[1] == 0x86 && response_z14[8] == crc) ) {
    Serial.println("CRC error z14: " + String(crc) + " / "+ String(response_z14[8]));
  } else { 
    unsigned int responseHigh = (unsigned int) response_z14[2];
    unsigned int responseLow = (unsigned int) response_z14[3];
  z14_co2 = (256*responseHigh) + responseLow;
  };
  mySerial_z14.end();
}



void sendRequest_z19(){
  mySerial_z19.begin(9600);
  mySerial_z19.write(cmd_z19, 9);
  memset(response_z19, 0, 9);
  mySerial_z19.readBytes(response_z19, 9);
  int i;
  byte crc = 0;
  for (i = 1; i < 8; i++) crc+=response_z19[i];
  crc = 255 - crc;
  crc++;
  if (response_z19[0] != 0xFF) {Serial.println("CRC error z19: response_z19[0] != 0xFF: " + String(response_z19[0]));};
  if (response_z19[1] != 0x86) {Serial.println("CRC error z19: response_z19[1] != 0x86: " + String(response_z19[1]));};
  if (response_z19[8] != crc) {Serial.println("CRC error z19: response_z19[8] != crc: " + String(response_z19[8]) + " / "+ String(crc));};
  
  if ( !(response_z19[0] == 0xFF && response_z19[1] == 0x86 && response_z19[8] == crc) ) {
    Serial.println("CRC error z19: " + String(crc) + " / "+ String(response_z19[8]));
  } else { 
    unsigned int responseHigh = (unsigned int) response_z19[2];
    unsigned int responseLow = (unsigned int) response_z19[3];
    unsigned int responseTT = (unsigned int) response_z19[4];
    unsigned int responseSS = (unsigned int) response_z19[5];
    z19_t = responseTT-40;
    z19_ss =  responseSS;
    z19_co2 = (256*responseHigh) + responseLow;
   };
  mySerial_z19.end();
}

void sendRequest_z19b(){
  mySerial_z19b.begin(9600);
  mySerial_z19b.write(cmd_z19, 9);
  memset(response_z19b, 0, 9);
  mySerial_z19b.readBytes(response_z19b, 9);
  int i;
  byte crc = 0;
  for (i = 1; i < 8; i++) crc+=response_z19b[i];
  crc = 255 - crc;
  crc++;
  if (response_z19b[0] != 0xFF) {Serial.println("CRC error z19b: response_z19b[0] != 0xFF: " + String(response_z19b[0]));};
  if (response_z19b[1] != 0x86) {Serial.println("CRC error z19b: response_z19b[1] != 0x86: " + String(response_z19b[1]));};
  if (response_z19b[8] != crc) {Serial.println("CRC error z19b: response_z19b[8] != crc: " + String(response_z19b[8]) + " / "+ String(crc));};
  
  if ( !(response_z19b[0] == 0xFF && response_z19b[1] == 0x86 && response_z19b[8] == crc) ) {
    Serial.println("CRC error z19b: " + String(crc) + " / "+ String(response_z19b[8]));
  } else { 
    unsigned int responseHigh = (unsigned int) response_z19b[2];
    unsigned int responseLow = (unsigned int) response_z19b[3];
    unsigned int responseTT = (unsigned int) response_z19b[4];
    unsigned int responseSS = (unsigned int) response_z19b[5];
    z19b_t = responseTT-40;
    z19b_ss =  responseSS;
    z19b_co2 = (256*responseHigh) + responseLow;
   };
  mySerial_z19b.end();
}


void tft_form(){
  tft.setTextSize(2);
  tft.setTextColor(0x177F);

  tft.setCursor(2, 4);
  tft.print("z14");
  tft.setCursor(2, 33);
  tft.print("z19");
  tft.setCursor(2, 62);
  tft.print("z19b");
  tft.setCursor(2, 91);
  tft.print("s8");
  
}


void tft_output(){

  tft.setTextSize(2);

  tft.setCursor(56, 4);
  tft.setTextColor(ST7735_BLACK);
  tft.print(String(z14_co2_mean_last));

  tft.setCursor(56, 4);
  tft.setTextColor(ST7735_WHITE);
  tft.print(String(z14_co2_mean));
  z14_co2_mean_last = z14_co2_mean;

  tft.setCursor(56, 33);
  tft.setTextColor(ST7735_BLACK);
  tft.print(String(z19_co2_mean_last));

  tft.setCursor(56, 33);
  tft.setTextColor(ST7735_WHITE);
  tft.print(String(z19_co2_mean));
  z19_co2_mean_last = z19_co2_mean;

  tft.setCursor(56, 62);
  tft.setTextColor(ST7735_BLACK);
  tft.print(String(z19b_co2_mean_last));

  tft.setCursor(56, 62);
  tft.setTextColor(ST7735_WHITE);
  tft.print(String(z19b_co2_mean));
  z19b_co2_mean_last = z19b_co2_mean;

  tft.setCursor(56, 91);
  tft.setTextColor(ST7735_BLACK);
  tft.print(String(s8_co2_mean_last));

  tft.setCursor(56, 91);
  tft.setTextColor(ST7735_WHITE);
  tft.print(String(s8_co2_mean));
  s8_co2_mean_last = s8_co2_mean;


  
  tft.setTextSize(1);
  tft.setCursor(110, 4);
  tft.setTextColor(ST7735_BLACK);
  tft.print(String(z14_co2_last));

  tft.setCursor(110, 4);
  tft.setTextColor(ST7735_WHITE);
  tft.print(String(z14_co2));
  z14_co2_last = z14_co2;

  tft.setCursor(110, 33);
  tft.setTextColor(ST7735_BLACK);
  tft.print(String(z19_co2_last));

  tft.setCursor(110, 33);
  tft.setTextColor(ST7735_WHITE);
  tft.print(String(z19_co2));
  z19_co2_last = z19_co2;

  tft.setCursor(110, 62);
  tft.setTextColor(ST7735_BLACK);
  tft.print(String(z19b_co2_last));

  tft.setCursor(110, 62);
  tft.setTextColor(ST7735_WHITE);
  tft.print(String(z19b_co2));
  z19b_co2_last = z19b_co2;

  tft.setCursor(110, 91);
  tft.setTextColor(ST7735_BLACK);
  tft.print(String(s8_co2_last));

  tft.setCursor(110, 91);
  tft.setTextColor(ST7735_WHITE);
  tft.print(String(s8_co2));
  s8_co2_last = s8_co2;


  
  tft.setTextSize(1);
  tft.fillRect(0, 117, 160, 120, ST7735_BLACK);
  tft.setCursor(0, 117);
  tft.print(String(getdate()));

}



void z19setup() {

/*  2     3    6    7
  {0x86,0x00,0x00,0x00},   // mhz_cmnd_read_ppm
  {0x79,0xA0,0x00,0x00},   // mhz_cmnd_abc_enable
  {0x79,0x00,0x00,0x00},   // mhz_cmnd_abc_disable
  {0x87,0x00,0x00,0x00},   // mhz_cmnd_zeropoint
  {0x8D,0x00,0x00,0x00},   // mhz_cmnd_reset
  {0x99,0x00,0x03,0xE8},   // mhz_cmnd_set_range_1000
  {0x99,0x00,0x07,0xD0},   // mhz_cmnd_set_range_2000
  {0x99,0x00,0x0B,0xB8},   // mhz_cmnd_set_range_3000
  {0x99,0x00,0x13,0x88}};  // mhz_cmnd_set_range_5000
*/

//  byte setrangeA_cmd[9] = {0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x8F};     // set range 0 - 2000ppm
  byte setrangeA_cmd[9] = {0xFF, 0x01, 0x99, 0x00, 0x00, 0x00, 0x13, 0x88, 0xCB};     // set range 0 - 5000ppm
//  byte setrangeA_cmd[9] = {0xFF, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86},     // mhz_cmnd_abc_disable
//  byte setrangeA_cmd[9] = {0xFF, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xE6};     // mhz_cmnd_abc_enable
//  byte setrangeA_cmd[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};     // data request
  unsigned char setrangeA_response[9]; 

  mySerial_z19.begin(9600);

  mySerial_z19.write(setrangeA_cmd,9);
  mySerial_z19.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);
  mySerial_z19.end();
}

///////////////////////////////////////  setup   /////////////////////////////////////////

void setup(void) {
  Serial.begin(38400);
  Wire.begin();
//  z19setup();
  tft.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab
  Serial.println("init");
    
  tft.setTextWrap(false); // Allow text to run off right edge
  tft.setRotation(3);
  tft.fillScreen(ST7735_BLACK);
  tft_form();
 
}

////////////////////////////////////////////////   loop    /////////////////////////////////////////////////////

void loop() {

  sendRequest_z14();
  sendRequest_z19();
  sendRequest_z19b();
  sendRequest_s8(cmd_s8); 
  s8_co2 = getValue_s8(response_s8); 

  if (!s8_co2_mean) s8_co2_mean = s8_co2;
  if (!z14_co2_mean) z14_co2_mean = z14_co2;
  if (!z19_co2_mean) z19_co2_mean = z19_co2;
  if (!z19b_co2_mean) z19b_co2_mean = z19b_co2;

  s8_co2_mean = s8_co2_mean - smoothing_factor*(s8_co2_mean - s8_co2);
  z14_co2_mean = z14_co2_mean - smoothing_factor*(z14_co2_mean - z14_co2);
  z19_co2_mean = z19_co2_mean - smoothing_factor*(z19_co2_mean - z19_co2);
  z19b_co2_mean = z19b_co2_mean - smoothing_factor*(z19b_co2_mean - z19b_co2);

  if (!s8_co2_mean2) s8_co2_mean2 = s8_co2;
  if (!z14_co2_mean2) z14_co2_mean2 = z14_co2;
  if (!z19_co2_mean2) z19_co2_mean2 = z19_co2;
  if (!z19b_co2_mean2) z19b_co2_mean2 = z19b_co2;

  s8_co2_mean2 = s8_co2_mean2 - smoothing_factor2*(s8_co2_mean2 - s8_co2);
  z14_co2_mean2 = z14_co2_mean2 - smoothing_factor2*(z14_co2_mean2 - z14_co2);
  z19_co2_mean2 = z19_co2_mean2 - smoothing_factor2*(z19_co2_mean2 - z19_co2);
  z19b_co2_mean2 = z19b_co2_mean2 - smoothing_factor2*(z19b_co2_mean2 - z19b_co2);

  
  getdate();
  tft_output();
//  if (((current_minute)%work_period == 0)&&(lastminute != current_minute)) {

String dataString = getdate()+"  s8~~:  "+String(s8_co2_mean2)+"  s8~:  "+String(s8_co2_mean)+"  s8:  "+String(s8_co2)+"  z14~~:  "+String(z14_co2_mean2)+"  z14~:  "+String(z14_co2_mean)+"  z14:  "+String(z14_co2)+"  z19~~:  "+String(z19_co2_mean2)+"  z19~:  "+String(z19_co2_mean)+"  z19:  "+String(z19_co2)+"  z19b~~:  "+String(z19b_co2_mean2)+"  z19b~:  "+String(z19b_co2_mean)+"  z19b:  "+String(z19b_co2);
// +"  z19_t:  "+String(z19_t)+"  z19b_t:  "+String(z19b_t);
    dataString.replace(".",",");
    dataString.replace("  ","t");
    Serial.println(dataString);
  lastminute = current_minute;
//  };

  delay(second_delay);
}

Что же я увидел как только подключил датчик и показания прибора устаканились? Датчик завышал уровень CO2 примерно на 200-250 ppm. Это много, этого нельзя не заметить. Я выставил свою елку на улицу и она там простояла ночь.

На улице должно быть порядка 400 ppm, а никак не 650.

И я решил откалибровать датчик. В этом одно из главных преимуществ этой модели датчика относительно Z19 без «B»: она калибруется не по 0ppm, а по 400ppm. Т.е. вместо азотной камеры этот датчик для калибровки достаточно просто вынести на улицу.

Вообще, в датчике предусмотрена автоматическая калибровка. Время от времени датчик смотрит на свои показания за несколько прошедших дней и находит в них минимальное значение. Исходя из презумпции, что периодически помещение с датчиком проветривается и там оказывается 400 ppm CO2, датчик меняет свои внутренние коэффициенты с тем, чтобы отснятый минимум соответствовал как раз этому уровню. Так что самый простой вариант — подождать, пока калибровка произойдет автоматически.

Второй вариант — использовать специальную команду. Подать ее в порт и все произойдет.
Третий вариант — замкнуть один из выводов датчика на землю и продержать 7 секунд. Именно такой способ я и выбрал.

Показания сразу стали равны 400 ppm и вскоре я внес датчик домой.

Как говорится, «взяли вилку». Был перелет, теперь недолет. На те же 250 ppm теперь меньше. Ну что ж, придется ждать, пока сработает автокорректировка.
А пока посмотрим на совпадение показаний других датчиков. MH-Z14A все больше завышает. MH-Z19 путается в показаниях и график выглядит как кардиограмма инфарктника. Но она все-таки больше совпадает с S8, нежели график MH-Z14A. В прошлом тесте все было наоборот. Так что некоторый дрейф присутствует у всех.
Для сглаживания локальных всплесков и провалов снятых значений я применил фильтр Кальмана. Это простой и эффективный способ отбросить лишнее и сконцентрироваться на важном в показаниях приборов. Для настройки фильтра требуется определить его коэффициент, для чего я добавил в выводимую программой таблицу несколько колонок, а потом построил по ним графики.

Как по мне, 0,15 — отличный выбор.Если прибор нужен в основном для принятия решений уровня «открывать форточку или нет» — то такая точность вполне достаточна, а визуально такой график воспринимается легче.

Еще я захотел сравнить показания встроенных в датчики термометров.

Нельзя однозначно сказать, что рассматриваемый датчик завышает температуру. Термометр — недокументированная фича, и используется он только для выстраивания внутренних коэффициентов датчика. Так что он измеряет свою температуру, а не окружающую.

Пожалуй, надо проверить работу ШИМ- выхода датчика. В некоторых случаях неудобно опрашивать датчик, посылая байты в компорт. Тогда есть альтернатива: на pwm выходе присутствует прямоугольный сигнал с частотой порядка 1 Гц и со скважностью, пропорциональной концентрации СО2. Его довольно легко анализировать и такой способ весьма защищен от помех.

Работает. Впрочем, pwm выход есть и на старой версии этого датчика.

А вот аналоговый выход есть только на «B». Напряжение на нем пропорционально концентрации углекислого газа. Проверим:

Тоже работает. Такой выход позволяет мастерить совсем простые устройства. Буквально из транзистора, пары резисторов и светодиода можно собрать устройство уровня «загорелся красный светодиод — открой окно». Так что это очень полезное новшество.

Конечно, все подробности отличий MH-Z19B и MH-Z19 можно изучить по pdf.Мои же впечатления такие:
Калибровка по 400 ppm — штука работающая и полезная. Датчик выдает более гладкий сигнал, чем его собрат. Вероятно, внутри показания фильтруются. Датчик при запуске не выдает в порт техническую информацию о себе — предел измерений, точность, что-то еще. Так пожалуй лучше, а то если устройство, которое принимает сигнал, настроено что-то там запускать при превышении СО2, то при приходе «2000» может сработать запуск, а датчик просто информировал о своем пределе измерений.
Что еще сказать. Отслеживается зависимость показаний от качества питания. У MH-Z19B — в меньшей степени, у MH-Z19 — в чуть большей. Но больше всего дуреет S8 при недостаточном питании, тому вообще крышу сносит.

Пока я все это изучал, кажется сработала автокалибровка.

Причем сразу у двух датчиков: MH-Z14А, который завышал, стал слегка занижать. А MH-Z19B, который занижал, стал завышать.

В этом датчике калибровку можно определить по обнулению 6-го байта в ответе датчика на запрос данных. В первый час после запуска датчика у него нулевое значение, потом оно постепенно возрастает и за 24 часа дрходит до 142. На этой отметке происходит автокалибровка, байт сбрасывается на 0 и все начинается сначала. Выглядит это так:

Со временем они наверняка придут к почти совпадающим показаниям. У меня так уже было с тремя датчиками из прошлого обзора.

За неделю тогда они практически спелись в унисон.

Итог: все датчики работают. Все показывают более-менее адекватные цифры. Выбирать я бы стал по удобству применения в конкретном приборе.

Товар для написания обзора предоставлен магазином. Обзор опубликован в соответствии с п.18 Правил сайта.

Понравилась статья? Поделить с друзьями:
  • Mgsvtpp exe ошибка приложения
  • Mgl fatal error gta 1 что делать
  • Mgk 25u как изменить подсветку
  • Mge xe serious error condition check mgexe log for details
  • Mge error морровинд