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

Вся страна на самоизоляции (ну или не вся) и удалёнке, в Сети обсуждают нашествие печенегов и половцев и то, как мы победим коронавирус, а я продолжаю серию постов #МастеримДома. На третий день работы с датчиком MQ135 я сказал, что для более менее корректной калибровки датчика необходимо учитывать температуру и влажность среды в которой происходит калибровка. И вот на прошлой неделе мне подвезли датчик температуры и влажности DHT22, благодаря использованию которого теперь можно реализовать несколько иной подход к измерению содержания CO2 в помещении и даже собрать что-то типа домашней мини-метеостанции.

Итак, что у нас есть на данный момент:

  1. Скетч для чтения данных с датчика MQ135 (концентрации CO2 и сопротивления R0)
  2. Небольшая программка на Delphi для чтения данных с COM-порта к которому подключается наша Arduino.

Сегодня разберемся как подключить к Arduino датчик температуры и влажности DHT22 и скорректировать по полученным от DHT22 данным показания с датчика MQ135.

Модуль датчика DHT-22

Модуль датчика DHT22 я заказывал вот на этом сайте. В отличие от «голого» датчика DHT-22 модуль уже готов к использованию и оснащен всем необходимым для работы. Выглядит модуль следующим образом:

Модуль имеет три вывода:

  • «+» — подключается к пину «5V» на Arduino
  • ‘-‘ — подключается к пину «GND»
  • «S» — подключается к любому свободному цифровому пину.

Для работы с модулем DHT-22 нам потребуется дополнительная библиотека, которую можно скачать вот по этой ссылке. О том, как подключаются библиотеки в Arduino IDE я рассказывал в третьей части статей про Arduino.

Собственно, сам скетч, демонстрирующий чтение температуры и влажности с DHT-22 выглядит следующим образом:

//Подключение библиотеки для работы с датчиком
#include 
 
//определение постоянных значений
#define DHTPIN 8 //пин получения данных с датчика
#define DHTTYPE DHT22 //Значение типа датчика
 
DHT dhtSensor(DHTPIN, DHTTYPE); //инициализация датчика
 
 
void setup() {
  dhtSensor.begin(); //запуск датчика
 
  Serial.begin(9600); //запуск Serial соединения
}
 
void loop() {
  delay(2000); //время чтобы датчик прогрузился
 
  float h = dhtSensor.readHumidity(); //получение данных по влажности
  float t = dhtSensor.readTemperature(); //получение данных по температуре
 
  if(isnan(h) || isnan(t)) return; //возврат если данные по температуре или влажности некорректно считались
 
  //Вывод значений 
  Serial.print("Temperature: ");
  Serial.print(t);
  Serial.print(" humidity: ");
  Serial.println(h);
 
}

Задержка в две секунды в loop() необходима, так как в соответствии с документацией на датчик, время его отклика составляет как раз те самые две секунды.

Как «подружить» MQ-135 и DHT-22?

В принципе, если использовать библиотеку для MQ-135 о которой я рассказывал, то в этой библиотеке определены следующие методы:

float getPPM();
float getCorrectedPPM(float t, float h);
float getRZero();
float getCorrectedRZero(float t, float h);

Методы «getCorrected…» как раз и учитывают при расчётах температуру и влажность среды. Соответственно, всё, что от нас требуется — это прочитать значения температуры и влажности и передать эти значения в соответствующие функции библиотеки для MQ-135. Выглядеть это может, например, вот так:

#include  //подключаем библиотеку для MQ135
#include  //подключаем библиотеку для DHT22
 
//определение постоянных значений
#define analogPin A0 // аналоговый выход MQ135 подключен к пину A0 Arduino
#define DHTPIN 8 //пин получения данных с датчика
#define DHTTYPE DHT22 //Значение типа датчика
 
//датчики
MQ135 gasSensor = MQ135(analogPin);
DHT dhtSensor(DHTPIN, DHTTYPE); //инициализация датчика
 
//переменные для работы
bool Zero = false;
bool Conc = true;
String ComStr = "C";
float Value = 0;  //значение без учёта температуры и влажности
float Value2 = 0; //значение с учётом температуры и влажности
float h = 0;      //температура
float t = 0;      //относительная влажность
 
void setup() {
  Serial.setTimeout(1000);
  Serial.begin(9600); // инициализация последовательного порта
  pinMode(analogPin, INPUT);  // режим работы аналогового пина
  dhtSensor.begin(); //запуск датчика
  delay(1000); // даём датчикам небольшое время на разогрев
}
 
void loop() {
 delay(2000); // задержка перед выводом следующего значения
 
 h = dhtSensor.readHumidity(); //получение данных по влажности
 t = dhtSensor.readTemperature(); //получение данных по температуре
 
 if(isnan(h) || isnan(t)) return; //возврат если данные по температуре или влажности некорректно считались
 
 
 if (Serial.available() > 0) {  //если есть доступные данные
        // считываем строку
        String incomingStr = Serial.readString();
        //определяем какая команды пришла
        int Command = incomingStr.toInt();
        switch (Command) {
           case 1: Zero = true;
                   Conc = false;
                   ComStr = "R";
                   break;
           case 2: Zero = false;
                   Conc = false;
                   ComStr = "";
                   break;
           default:
                  Zero = false; 
                  Conc = true;
                  ComStr = "C";
       }
    }
 
if (Zero) 
{
   Value = gasSensor.getCorrectedRZero(t, h); // чтение R0
   Value2 =gasSensor.getRZero();   
}
else if (Conc)
{
   Value = gasSensor.getCorrectedPPM(t,h); 
   Value2 =gasSensor.getPPM(); 
}
 if (Zero || Conc)
 {
  //вывод в порт
   Serial.print(ComStr);
   Serial.print("|");
   Serial.print(Value); 
   Serial.print("|"); 
   Serial.print(Value2); 
   Serial.print("|");
   Serial.print(t);
   Serial.print("|");
   Serial.print(h);
   Serial.println("#");
 }

Разберемся, что здесь и как работает. Итак, подключены датчики следующим образом:

  • MQ-135 подключен к аналоговому пину A0. Цифровой пин не используется
  • DHT-22 подключен к цифровому пину 8.

Вся эта адова конструкция в натуре выглядит вот так:

Далее работа строится следующим образом:

  1. пробуем считать с датчика DHT-22 значения температуры и влажности;
  2. если чтение прошло успешно — смотрим, какие данные должны передать (об этом — смотри тут);
  3. если надо передать значения сопротивления ил концентрации, то в порт передается следующая строка:

Команда|корректное_значение|обычное_значение|температура|влажность#

где

  • Команда — один из двух символов: R — чтение сопротивления; C — чтение концентрации;
  • корректное_значение — это значение с датчика MQ-135 с учётом температуры и влажности;
  • обычное_значение — это, соответственно, значения без учёта температуры и влажности
  • температура и влажность — это данные с датчика DHT-22.

Теперь, учитывая произведенные в скетче Arduino изменения, нам необходимо немного переписать приложение для работы с Arduino в Delphi.

Дописываем Delphi-приложение для работы с Arduino

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

function TfrmMain.ParseString(const AStr: string; var ADataType: TArduinoData; var AValue, AValue2, AT, AH: double): boolean;
var List: TStringList;
    S: string;
begin
  //R|корректное_значение|обычное_значение|температура|влажность
  S:=Trim(AStr);
  if not EndsText('#', S) then
    exit(False);
  List:=TStringList.Create;
  try
    List.Delimiter:='|';
    List.DelimitedText:=Copy(S, 1, length(S)-2);
    if List[0]='C' then
      ADataType:=adPPM
    else
      if List[0]='R' then
        ADataType:=adRo
      else
        ADataType:=adNone;
    AValue:=StrToFloat(List[1], FS);
    AValue2:=StrToFloat(List[2], FS);
    AT:=StrToFloat(List[3], FS);
    AH:=StrToFloat(List[4], FS);
    Result:=True;
  finally
    FreeAndNil(List)
  end;
end;

Соответственно, немного изменится и подсчёт средних значений. Для этой цели я, опять же, написал простенькую функцию, которая на входе принимает предыдущее среднее значение и количество итераций, а на выходе выдает очередное среднее значение:

function GetAvgValue(const PredAvg, NextVal: double; var Count: integer):double;
begin
  if Count=0 then
     Result:=NextVal
  else
     Result:=PredAvg*(Count/(Count+1))+NextVal/(Count+1);
  inc(Count);
end;

Изменился немного и интерфейс приложения:
При работе с COM-портом обновление данных осуществляется теперь следующим образом:

type
  TfrmMain = class(TForm)
    [...]
  private
    FS: TFormatSettings;
    DataType: TArduinoData; Value, Value2, T, H: double;
    aCount: integer;
    aAvgVal: double;
    aAvgVal2: double;
    procedure UpdateForm;
    function ParseString(const AStr: string; var ADataType: TArduinoData; var AValue, AValue2, AT, AH: double): boolean;
  public
    { Public declarations }
  end;
 
procedure TfrmMain.ArduinoComRxChar(Sender: TObject; Count: Integer);
var Str: string;
    aNext: double;
begin
  ArduinoCom.ReadStr(Str, Count);
  memData.Text:=memData.Text+Str;
  if ParseString(Str, DataType, Value, Value2, T, H) then
    begin
      aAvgVal:=GetAvgValue(aAvgVal, Value, aCount);
      aAvgVal2:=GetAvgValue(aAvgVal2, Value2, aCount);
      UpdateForm;
    end;
end;
 
procedure TfrmMain.UpdateForm;
const
  cValStr = '%s (без корректировки: %s)';
begin
  lbAvg.Caption:=Format(cValStr, [FloatToStrF(aAvgVal, fffixed, 6,2),
                                  FloatToStrF(aAvgVal2, fffixed, 6,2)]);
  lbCount.Caption:=IntToStr(aCount);
  lbTemp.Caption:=FloatToStrF(T, fffixed, 6,1);
  lbHum.Caption:=FloatToStrF(H, fffixed, 6,1);
end;

Таким образом, теперь можно получать данные по температуре и влажности в помещении, откалибровать датчик с учётом этих значений и попытаться получить хоть какое-то более менее точное значение концентрации CO2 в доме.

Новые калибровочные данные с датчика MQ-135

Для получения новых калибровочных данных с MQ-135 я сделал следующее: установил драйвер для Arduino на ноутбук, прицепил к ноуту всю получившуюся конструкцию и вытащил всё это богатство на балкон на 20 минут. В результате я получил следующие калибровочные данные:

R0 = 251,35 (без корректировки 242,62)

В прошлый раз значение R0 (без учёта температуры и влажности) было равно 70,83. Различие более чем в три раза нового значения и предыдущего заставляет задуматься…При этом стоит отметить, что датчик температуры и влажности DHT-22 точно не лажал, по крайней мере с температурой — показания датчика и обычного термометра на балконе полностью совпали и показывали 190С.

Что ж, вносим изменения в библиотеку для MQ-135, как это делалось в прошлый раз и смотрим, что теперь будет показывать MQ-135 у меня в комнате, опять же, усредняя показатели за 20-ти минутный интервал времени.

Показания датчика MQ-135: концентрация CO2 в помещении: 576,3 ppm. Опять же, следуя имеющейся статистике, показания датчика вроде бы соответствуют реальности. Но как знать, как знать…Видимо придётся где-то искать газоанализатор на CO2 и проверять работу датчика более детально.

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

Теперь интерфейс программы можно настраивать «под себя» и баловаться с Arduino дальше.

5 1 голос
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
0 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии