• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Нужна помощь ESP8266+MH-Z19, проблемы

Cadil

New member
С помощью Arduino IDE заливаю в модуль CP2102 Node MCU скетч (под спойлером) для датчика углекислого газа MH-Z19.
#include <SoftwareSerial.h>;

//SoftwareSerial mySerial(2, 3); // RX, TX
//SoftwareSerial mySerial(13, 15, false, 256); // GPIO15 (TX) and GPIO13 (RX)
SoftwareSerial mySerial(13, 15); // GPIO15 (TX) and GPIO13 (RX)
byte request[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};
unsigned char response[9];

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

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

if ( !(response[0] == 0xFF && response[1] == 0x86 && response[8] == crc) ) {
Serial.println("CRC error");
} else {
unsigned int HLconcentration = (unsigned int) response[2];
unsigned int LLconcentration = (unsigned int) response[3];
unsigned int co2 = (256*HLconcentration) + LLconcentration;

Serial.println(co2);
for (i = 0; i < 9; i++) {
Serial.print("0x");
Serial.print(response,HEX);
Serial.print(" ");
}
Serial.println(" ");

}
delay(5000);
}
Подключаю датчик, перезапускаю, но на мониторе Arduino IDE - тишина, если не считать нечитаемой абракадабры при включении. В окнах датчика мигают инфракрасные нагреватели с периодом около 5 сек.
Помогите прояснить ситуацию: Некондиционный датчик? Ошибки в скрипте? Что-то не то делаю? Другая версия?
 

Вложения

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

Cadil

New member
Для просмотра установите скорость 78 тыс с хвостиком. Точнее не помню. Посмотрите - сообщите что выдает
Спасибо! Выдает примерно такое:
ets Jan 8 2013,rst cause:1, boot mode:(3,6)

load 0x4010f000, len 1384, room 16
tail 8
chksum 0x2d
csum 0x2d
v09f0c112
~ld
 

Cadil

New member
В поисках решения описанной проблемы перешел с цифрового интерфейса датчика MH-Z19 на ШИМ (у него есть и такой выход!).
Залил в ESP8266 скрипт, который один из магазинов использует для предпродажной проверки этих сенсоров.
Схема задышала. К сожалению, на мониторе редактора Arduino IDE отображается не реальный ppm в пределах 400-800, а значение 5000 (см. картинку mh-z19_2.png). При этом ESP находится в режиме записи. Если уйти от режима записи, то иногда на мониторе можно увидеть картинку, как во вложении - mh-z19_3.png.
При разрыве цепи "выход датчика - контроллер" обновление информации на мониторе останавливается, мигание светодиода 13 прекращается.
На основании этой информации можно однозначно утверждать, что датчик MH-Z19 - некондиционный?
 

Вложения

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

Cadil

New member
Работая со скриптами для MH-Z19, одна из моих попыток оказалась удачной - я увидел на мониторе редактора далекие от реальности показатели концентрации СО2 (около 1400), но, самое главное, реакцию датчика на мое дыхание (2100-2600). Скрипт под спойлером.
//#define BLYNK_PRINT Serial
#include <ESP8266WiFi.h>
//#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
#include <Wire.h>
#include <SoftwareSerial.h>;


// MH-Z19, power - 5v
// D8 - TX sensor, D7 - RX sensor
#define CO2_TX D8
#define CO2_RX D7

SoftwareSerial co2Serial(CO2_TX, CO2_RX);

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
//char auth[] = “redacted”; // Put your Auth Token here. (see Step 3 above)

SimpleTimer timer;

void setup()
{
Serial.begin(9600); // See the connection status in Serial Monitor
// Blynk.begin(auth, “xx”, “xx”); //insert here your SSID and password

// Setup a function to be called every second
timer.setInterval(10000L, sendUptime);

co2Serial.begin(9600);
co2Serial.flush();
}

int readCO2()
{
byte cmd[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
char response[9];

co2Serial.write(cmd, 9); //request PPM CO2
co2Serial.readBytes(response, 9);

byte crc = 0;
for (int i = 1; i < 8; i++)
{
crc += response;
}
crc = 255 - crc;
crc++;

if (response[8] != crc)
{
Serial.println("Wrong crc from co2 sensor!");
return -1;
}
if (response[0] != 0xFF)
{
Serial.println("Wrong starting byte from co2 sensor!");
return -1;
}
if (response[1] != 0x86)
{
Serial.println("Wrong command from co2 sensor!");
return -1;
}

int responseHigh = (int) response[2];
int responseLow = (int) response[3];
int ppm = (256 * responseHigh) + responseLow;
// Serial.println(ppm);
return ppm;
}

void sendUptime()
{
int co2_ppm = readCO2();
// Blynk.virtualWrite(3, co2_ppm); // virtual pin
Serial.println(co2_ppm);
}
void loop()
{
// Blynk.run();
timer.run();
}

К сожалению, это событие произошло только один раз.

Ниже - типичные сообщения с модуля ср2102:
ets Jan августа 2013, rst cause: 1, boot mode: (5,7)
waiting for host

Wrong crc from co2 sensor!
(Линии Rx, Tx - разорванные)

В нете нашел информацию, что для чипов ESP8266 нужна своя, особая библиотека SoftwareSerial для MH-Z19. Заменил ранее установленную библиотеку SoftwareSerial на указанную в ссылке, но положительного результата - нет.
Где копать?
 
Последнее редактирование:

shuraf

Member
MH-Z19 и MH-Z19B в плане опроса идентичны, и в плане подключения совпадают. Они отличаются только новыми командами, в частности автокалибровки.
MH-Z19
MH-Z19 Infrared CO2 Sensor For CO2 Indoor Air Quality Monitor UART/PWM 0-5000PPM | eBay
MH-Z19B
MH-Z19B DIP Infrared CO2 Sensor for CO2 Monitor NDIR Gas Sensor | eBay
Обрати внимание снизу маленький разьемчик, вот это различие внешнего вида.
Сейчас стали появляться MH-Z19 с другим разьемом
MH-Z19B Infrared CO2 Sensor for CO2 Monitor NDIR Gas Sensor (MH-Z19 Updated) | eBay

Рабочий код. С ним пяток датчиков стоит и работает.
Код:
void setup() {
  Serial.begin(9600);
  Serial1.begin(115200);
}

void loop () {
  ppmCO2 = readCO2();
  Serial1.println (ppmCO2);
}


int readCO2() {
  while (Serial.available() > 0) {
    Serial.read();
  }
  byte cmd[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
  char response[9]; // for answer
  Serial.write(cmd, 9); //request PPM CO2
  memset(response, 0, 9);
  Serial.readBytes(response, 9);
  int CRC = getCheckSum(response);
  if (response[0] != 0xFF  || response[1] != 0x86 || CRC != response[8]) {
    return -1;
  }
  int responseHigh = (int) response[2];
  int responseLow = (int) response[3];
  return (256 * responseHigh) + responseLow;
}

int getCheckSum(char *packet) {
  byte checksum = 0;
  for ( int i = 1; i < 8; i++) {
    checksum += packet[i];
  }
  checksum = 0xff - checksum;
  checksum ++;
  return checksum;
}
Обрати внимание. Что датчик подключен к Serial (для ESP12 это TXD и RXD), а получаем цифирки с Serial1 (GPIO2).
Если захочешь все перевести на первый порт, то при прошивке снимай питания с датчика CO2. Иначе можно случайно "переконфигурировать" его, "откалибровать" или перевести в режим ModBus
 

Cadil

New member
Обрати внимание. Что датчик подключен к Serial (для ESP12 это TXD и RXD), а получаем цифирки с Serial1 (GPIO2).
Спасибо за код.
В этом коде нашел одну неточность: ppmCO2 = readCO2(); вместо int ppmCO2 = readCO2();
Хотя код компилируется, я не могу понять - где в нем обращение к портам UARTa: TXD и RXD? Или обращение не требуется, раз на этих пинах организован UART? Таймера не видно. Как цикл организован? Поясни!
Или я неправильно подключаю датчик к модую: Rx (cp2102) - Tx (mh-z19), Tx (cp2102) - Rx (mh-z19)? (распиновка во вложении)
 

Вложения

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

shuraf

Member
Serial.write () - это записывает команду в порт
Seril.readBytes ()) - чтение из порта
Выдернул этот кусок по этому забыл в лупе поставить delay(), иначе датчик загнется. Не помню какой минимальный цикл у опроса можно поставить
Rx-Tx - это gpio1 и gpio3 у тебя. Сюда датчик и цепляй. Но только перекрестно rx-датчика -> tx esp, tx -> rx.
А данные тебе 'посиотреть' будут прилетать в gpio2 (serial1).
Скорости на портах разные
 
Последнее редактирование:

Cadil

New member
Serial.write () - это записывает команду в порт
Seril.readBytes ()) - чтение из порта
Выдернул этот кусок по этому забыл в лупе поставить delay(), иначе датчик загнется. Не помню какой минимальный цикл у опроса можно поставить
Rx-Tx - это gpio1 и gpio3 у тебя. Сюда датчик и цепляй. Но только перекрестно rx-датчика -> tx esp, tx -> rx.
А данные тебе 'посиотреть' будут прилетать в gpio2 (serial1).
Скорости на портах разные
Поставил период опроса 10 сек (В нете встречал и 5). Датчик подключал правильно. Функции "посмотреть" для разных скоростей записаны так:
Serial1.println(String(ppmCO2) + "ppm");
Serial.println("CO2: " + String(ppm) + "ppm");

Посмотри, пожалуйста, код - не хотелось бы угробить датчик.
Код:
void setup() {
  Serial.begin(9600);
  Serial1.begin(115200);
}


void loop () {
  int ppmCO2 = readCO2();
// Serial1.println (ppmCO2);
Serial1.println(String(ppmCO2) + "ppm");
  delay(10000);
}
 
int readCO2() {
  while (Serial.available() > 0) {
    Serial.read();
  }
  byte cmd[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
  char response[9]; // for answer
  Serial.write(cmd, 9); //request PPM CO2
  memset(response, 0, 9);
  Serial.readBytes(response, 9);
  int CRC = getCheckSum(response);
  if (response[0] != 0xFF  || response[1] != 0x86 || CRC != response[8]) {
    return -1;
  }
  int responseHigh = (int) response[2];
  int responseLow = (int) response[3];
  int ppm = (256 * responseHigh) + responseLow;
// return (256 * responseHigh) + responseLow;
Serial.println("CO2: " + String(ppm) + "ppm");
  return ppm;
}
int getCheckSum(char *packet) {
  byte checksum = 0;
  for ( int i = 1; i < 8; i++) {
    checksum += packet[i];
  }
  checksum = 0xff - checksum;
  checksum ++;
  return checksum;
}
 

Cadil

New member
Строка 31. Serial - порт подключения датчика
Закомметировал строку 31. Больше ничего не режет глаз?

Мне кажется, что в твоем коде на хватает функций инициализации портов. Они должны выглядеть примерно так:
#define CO2_TX D8
#define CO2_RX D7
SoftwareSerial co2Serial(CO2_TX, CO2_RX);

если порты организуются библиотекой SoftwareSerial
Посмотри, пожалуйста, как назначены Tx, Rx у тебя?
 
Последнее редактирование:

Ed007

New member
@shuraf подскажите плз, как добавить к Вашей прошивке отправку данных на народмон или thingspeak?
 

shuraf

Member
Закомметировал строку 31. Больше ничего не режет глаз?

Мне кажется, что в твоем коде на хватает функций инициализации портов. Они должны выглядеть примерно так:
#define CO2_TX D8
#define CO2_RX D7
SoftwareSerial co2Serial(CO2_TX, CO2_RX);

если порты организуются библиотекой SoftwareSerial
Посмотри, пожалуйста, как назначены Tx, Rx у тебя?
В примере не используется софтовый сериал-порт.

@shuraf подскажите плз, как добавить к Вашей прошивке отправку данных на народмон или thingspeak?
Извини, я этим не пользуюсь.
 
Сверху Снизу