Пользователь
0,0
рейтинг
6 ноября 2014 в 17:46

Ардуино на службе здоровья из песочницы

В статье описан путь от идеи до создания домашнего портативного анализатора качества воздуха (CO2, влажность, температура, давление).

Вступление


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

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

В интернетах так же была найдена такая табличка допустимых концентраций СО2 в воздухе:

Сводная таблица допустимых значений концентрации СО2 в воздухе

Итак, нам понадобится:
  • 1. Arduino Pro Mini цена 2.15$
  • 2. Датчик влажности и температуры DHT-22 он же AM2302 (улучшенная точность по сравнению с DHT-11), цена 4$
  • 3. Датчик давления BMP180, цена 2.98$
  • 4. Модуль с датчиком углекислого газа TGS4161, цена 60$
  • 5. Дисплей типа Nokia 5110, цена 2,35$


Итого: 71.48$ (промышленные приборы с похожим набором датчиков стоят от 300$)

Компоненты для сборки

Датчик углекислого газа

На датчике углекислого газа следует остановиться отдельно. В то время как датчик давления и влажности выдают показания уже в цифре, имеют какие-никакие цепи стабилизации по питанию, то стоимость полностью цифрового датчика СО2 начинается от 120$, многовато как «для поиграться». Самый дешевый в виде модуля к Ардуине китайцы предлагают на базе MG811 за 36$. Посмотрел я на его характеристики, а там дикая зависимость от влажности, наличия посторонних газов в воздухе и решил, что нужно поискать что-то более точное и таким оказался TGS4161, привожу его характеристики:

MG811

Успокоившись на счет стабильности показаний, оформил покупку и датчик приехал через две недели.

Сборка устройства

Когда модуль ко мне приехал, у меня уже все было собрано на макетной плате, не хватало только его. Вооружившись паяльником я обратил свой взор к рекламной картинке (см. выше), мол как его подключать? Вот тут пришлось немного опешить, надежда, что Dout это цифровой выход, не оправдалась, документации на этот модуль вообще нет никакой и нигде, модуль делают китайцы штучно. Что же делать? Пришлось тыкать в ноги модуля тестером, дуть на датчик, привлекать такую-то мать, писать кролику… Методом тыка установлено что модуль содержит два операционных усилителя. Первый из них имеет входное сопротивление 1,5 ТОм (Вы не ошиблись именно тера-Ом, т.е. 1500 гиг-Ом, тогда как обычный цифровой мультиметр имеет входное сопротивление не более 20 мега-Ом), второй сдвоенный ОУ работает как компаратор и повторитель. Aout некий аналоговый сигнал с повторителя, Dout – сигнал с компаратора (активен если СО2 зашкаливает). Назначение вывода TCM установить не удалось.

Как же датчик работает?

Датчик представляет собой электрохимическую ячейку для работы которой нужна высокая температура. Температура обеспечивается встроенным в датчик нагревателем мощностью примерно 0,2Вт. Напряжение на ячейке при концентрации СО2 350ppm и ниже имеет некое стабильное значение, а когда концентрация СО2 растет, напряжение на ячейке тоже изменяется (падает). Для согласования высокого выходного сопротивления ячейки и с целью усиления напряжения применены ОУ.

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

Это первый блин, сильно не ругать

Внутри прибора - лапша

Чувствительность свеже-откалиброванного датчика была такой что он мог достоверно отличать более свежий воздух в парку от загазованного проспекта за 300 метров.

По остальным датчикам: влажность меряет отлично, взяв в руки прибор сразу можно заметить рост влажности, прям таки скачек (еще бы, когда в квартире сейчас влажность всего 29%); давление тоже меряет отлично, как абсолютное так и относительное, подняв и опустив прибор можно заметить разницу в давлении.

Далее следует...

На этом история не закончилась, а все только начиналось, потому что когда прибор перешел на автономное питание ему резко поплохело и история его лечения заслуживает отдельного топика, вот осциллограмма из истории болезни:

И это только начало

UPD:
Схема подключения типичная для указанных датчиков, более детально о распиновке в скетче.
Рабочий скетч для Arduino UNO
Скетч собирался (копипастился) с разных кусков, так что сильно не ругайте, надеюсь разобраться в нем можно
#include <SFE_BMP180.h>
#include <Wire.h>
#include "DHT.h"

#define PIN_SCE   7  // LCD CS  .... Pin 2
#define PIN_RESET 6  // LCD RST .... Pin 1
#define PIN_DC    5  // LCD Dat/Com. Pin 3
#define PIN_SDIN  4  // LCD SPIDat . Pin 4
#define PIN_SCLK  3  // LCD SPIClk . Pin 5
                     // LCD Gnd .... Pin 8
                     // LCD Vcc .... Pin 6
                     // LCD Vlcd ... Pin 7

#define LCD_C     LOW
#define LCD_D     HIGH

#define LCD_X     84
#define LCD_Y     48
#define LCD_CMD   0
SFE_BMP180 pressure;

#define DHTPIN 10
#define DHTTYPE DHT22 

DHT dht(DHTPIN, DHTTYPE);

#define ALTITUDE 113.0 // Altitude of SparkFun's HQ in Boulder, CO. in meters

int a = 0;
int sensorPin = A0;    // вход подключается к Aout модуля с датчиком СО2
int vBattPin = A1;    // вход используется для мониторинга за состояние батареи
int sensorValue = 0;  // variable to store the value coming from the sensor
float adc_step=5/1024.0f; //шаг измерения АЦП 
float a_k=5.0894E-7; //магическая константа модели датчика СО2
float b_k=6.7303E-4;//еще одна магическая константа модели датчика СО2
float v_0=1.09; //напряжение на выходе датчика на свежем воздухе
int ledPin=13;


static const byte ASCII[][5] =
{
 {0x00, 0x00, 0x00, 0x00, 0x00} // 20  
 ,{0xff, 0xff, 0xff, 0xff, 0xff} // 21 !
//,{0x00, 0x00, 0x5f, 0x00, 0x00} // 21 !
,{0x00, 0x07, 0x00, 0x07, 0x00} // 22 "
,{0x14, 0x7f, 0x14, 0x7f, 0x14} // 23 #
,{0x24, 0x2a, 0x7f, 0x2a, 0x12} // 24 $
,{0x23, 0x13, 0x08, 0x64, 0x62} // 25 %
,{0x36, 0x49, 0x55, 0x22, 0x50} // 26 &
,{0x00, 0x05, 0x03, 0x00, 0x00} // 27 '
,{0x00, 0x1c, 0x22, 0x41, 0x00} // 28 (
,{0x00, 0x41, 0x22, 0x1c, 0x00} // 29 )
,{0x14, 0x08, 0x3e, 0x08, 0x14} // 2a *
,{0x08, 0x08, 0x3e, 0x08, 0x08} // 2b +
,{0x00, 0x50, 0x30, 0x00, 0x00} // 2c ,
,{0x08, 0x08, 0x08, 0x08, 0x08} // 2d -
,{0x00, 0x60, 0x60, 0x00, 0x00} // 2e .
,{0x20, 0x10, 0x08, 0x04, 0x02} // 2f /
,{0x3e, 0x51, 0x49, 0x45, 0x3e} // 30 0
,{0x00, 0x42, 0x7f, 0x40, 0x00} // 31 1
,{0x42, 0x61, 0x51, 0x49, 0x46} // 32 2
,{0x21, 0x41, 0x45, 0x4b, 0x31} // 33 3
,{0x18, 0x14, 0x12, 0x7f, 0x10} // 34 4
,{0x27, 0x45, 0x45, 0x45, 0x39} // 35 5
,{0x3c, 0x4a, 0x49, 0x49, 0x30} // 36 6
,{0x01, 0x71, 0x09, 0x05, 0x03} // 37 7
,{0x36, 0x49, 0x49, 0x49, 0x36} // 38 8
,{0x06, 0x49, 0x49, 0x29, 0x1e} // 39 9
,{0x00, 0x36, 0x36, 0x00, 0x00} // 3a :
,{0x00, 0x56, 0x36, 0x00, 0x00} // 3b ;
,{0x08, 0x14, 0x22, 0x41, 0x00} // 3c <
,{0x14, 0x14, 0x14, 0x14, 0x14} // 3d =
,{0x00, 0x41, 0x22, 0x14, 0x08} // 3e >
,{0x02, 0x01, 0x51, 0x09, 0x06} // 3f ?
,{0x32, 0x49, 0x79, 0x41, 0x3e} // 40 @
,{0x7e, 0x11, 0x11, 0x11, 0x7e} // 41 A
,{0x7f, 0x49, 0x49, 0x49, 0x36} // 42 B
,{0x3e, 0x41, 0x41, 0x41, 0x22} // 43 C
,{0x7f, 0x41, 0x41, 0x22, 0x1c} // 44 D
,{0x7f, 0x49, 0x49, 0x49, 0x41} // 45 E
,{0x7f, 0x09, 0x09, 0x09, 0x01} // 46 F
,{0x3e, 0x41, 0x49, 0x49, 0x7a} // 47 G
,{0x7f, 0x08, 0x08, 0x08, 0x7f} // 48 H
,{0x00, 0x41, 0x7f, 0x41, 0x00} // 49 I
,{0x20, 0x40, 0x41, 0x3f, 0x01} // 4a J
,{0x7f, 0x08, 0x14, 0x22, 0x41} // 4b K
,{0x7f, 0x40, 0x40, 0x40, 0x40} // 4c L
,{0x7f, 0x02, 0x0c, 0x02, 0x7f} // 4d M
,{0x7f, 0x04, 0x08, 0x10, 0x7f} // 4e N
,{0x3e, 0x41, 0x41, 0x41, 0x3e} // 4f O
,{0x7f, 0x09, 0x09, 0x09, 0x06} // 50 P
,{0x3e, 0x41, 0x51, 0x21, 0x5e} // 51 Q
,{0x7f, 0x09, 0x19, 0x29, 0x46} // 52 R
,{0x46, 0x49, 0x49, 0x49, 0x31} // 53 S
,{0x01, 0x01, 0x7f, 0x01, 0x01} // 54 T
,{0x3f, 0x40, 0x40, 0x40, 0x3f} // 55 U
,{0x1f, 0x20, 0x40, 0x20, 0x1f} // 56 V
,{0x3f, 0x40, 0x38, 0x40, 0x3f} // 57 W
,{0x63, 0x14, 0x08, 0x14, 0x63} // 58 X
,{0x07, 0x08, 0x70, 0x08, 0x07} // 59 Y
,{0x61, 0x51, 0x49, 0x45, 0x43} // 5a Z
,{0x00, 0x7f, 0x41, 0x41, 0x00} // 5b [
,{0x02, 0x04, 0x08, 0x10, 0x20} // 5c ¥
,{0x00, 0x41, 0x41, 0x7f, 0x00} // 5d ]
,{0x04, 0x02, 0x01, 0x02, 0x04} // 5e ^
,{0x40, 0x40, 0x40, 0x40, 0x40} // 5f _
,{0x00, 0x01, 0x02, 0x04, 0x00} // 60 `
,{0x20, 0x54, 0x54, 0x54, 0x78} // 61 a
,{0x7f, 0x48, 0x44, 0x44, 0x38} // 62 b
,{0x38, 0x44, 0x44, 0x44, 0x20} // 63 c
,{0x38, 0x44, 0x44, 0x48, 0x7f} // 64 d
,{0x38, 0x54, 0x54, 0x54, 0x18} // 65 e
,{0x08, 0x7e, 0x09, 0x01, 0x02} // 66 f
,{0x0c, 0x52, 0x52, 0x52, 0x3e} // 67 g
,{0x7f, 0x08, 0x04, 0x04, 0x78} // 68 h
,{0x00, 0x44, 0x7d, 0x40, 0x00} // 69 i
,{0x20, 0x40, 0x44, 0x3d, 0x00} // 6a j 
,{0x7f, 0x10, 0x28, 0x44, 0x00} // 6b k
,{0x00, 0x41, 0x7f, 0x40, 0x00} // 6c l
,{0x7c, 0x04, 0x18, 0x04, 0x78} // 6d m
,{0x7c, 0x08, 0x04, 0x04, 0x78} // 6e n
,{0x38, 0x44, 0x44, 0x44, 0x38} // 6f o
,{0x7c, 0x14, 0x14, 0x14, 0x08} // 70 p
,{0x08, 0x14, 0x14, 0x18, 0x7c} // 71 q
,{0x7c, 0x08, 0x04, 0x04, 0x08} // 72 r
,{0x48, 0x54, 0x54, 0x54, 0x20} // 73 s
,{0x04, 0x3f, 0x44, 0x40, 0x20} // 74 t
,{0x3c, 0x40, 0x40, 0x20, 0x7c} // 75 u
,{0x1c, 0x20, 0x40, 0x20, 0x1c} // 76 v
,{0x3c, 0x40, 0x30, 0x40, 0x3c} // 77 w
,{0x44, 0x28, 0x10, 0x28, 0x44} // 78 x
,{0x0c, 0x50, 0x50, 0x50, 0x3c} // 79 y
,{0x44, 0x64, 0x54, 0x4c, 0x44} // 7a z
,{0x00, 0x08, 0x36, 0x41, 0x00} // 7b {
,{0x00, 0x00, 0x7f, 0x00, 0x00} // 7c |
,{0x00, 0x41, 0x36, 0x08, 0x00} // 7d }
,{0x10, 0x08, 0x08, 0x10, 0x08} // 7e ←
,{0x00, 0x06, 0x09, 0x09, 0x06} // 7f →
};




void LcdCharacter(char character)
{
  LcdWrite(LCD_D, 0x00);
  for (int index = 0; index < 5; index++)
  {
    LcdWrite(LCD_D, ASCII[character - 0x20][index]);
  }
  LcdWrite(LCD_D, 0x00);
}

void LcdClear(void)
{
  for (int index = 0; index < LCD_X * LCD_Y / 8; index++)
  {
    LcdWrite(LCD_D, 0x00);
  }
}

void LcdInitialise(void)
{
  pinMode(PIN_SCE,   OUTPUT);
  pinMode(PIN_RESET, OUTPUT);
  pinMode(PIN_DC,    OUTPUT);
  pinMode(PIN_SDIN,  OUTPUT);
  pinMode(PIN_SCLK,  OUTPUT);

  digitalWrite(PIN_RESET, LOW);
 // delay(1);
  digitalWrite(PIN_RESET, HIGH);

  LcdWrite( LCD_CMD, 0x21 );  // LCD Extended Commands.
  LcdWrite( LCD_CMD, 0xBf );  // Set LCD Vop (Contrast). //B1
  LcdWrite( LCD_CMD, 0x04 );  // Set Temp coefficent. //0x04
  LcdWrite( LCD_CMD, 0x14 );  // LCD bias mode 1:48. //0x13
  LcdWrite( LCD_CMD, 0x0C );  // LCD in normal mode. 0x0d for inverse
  LcdWrite(LCD_C, 0x20);
  LcdWrite(LCD_C, 0x0C);
}

void LcdString(char *characters)
{
  while (*characters)
  {
    LcdCharacter(*characters++);
  }
}

void LcdWrite(byte dc, byte data)
{
  digitalWrite(PIN_DC, dc);
  digitalWrite(PIN_SCE, LOW);
  shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data);
  digitalWrite(PIN_SCE, HIGH);
}

// gotoXY routine to position cursor 
// x - range: 0 to 84
// y - range: 0 to 5

void gotoXY(int x, int y)
{
  LcdWrite( 0, 0x80 | x);  // Column.
  LcdWrite( 0, 0x40 | y);  // Row.  

}


char * floatToString(char * outstr, double val, byte precision, byte widthp){
  char temp[16];
  byte i;

  // compute the rounding factor and fractional multiplier
  double roundingFactor = 0.5;
  unsigned long mult = 1;
  for (i = 0; i < precision; i++)
  {
    roundingFactor /= 10.0;
    mult *= 10;
  }
  
  temp[0]='\0';
  outstr[0]='\0';

  if(val < 0.0){
    strcpy(outstr,"-\0");
    val = -val;
  }

  val += roundingFactor;

  strcat(outstr, itoa(int(val),temp,10));  //prints the int part
  if( precision > 0) {
    strcat(outstr, ".\0"); // print the decimal point
    unsigned long frac;
    unsigned long mult = 1;
    byte padding = precision -1;
    while(precision--)
      mult *=10;

    if(val >= 0)
      frac = (val - int(val)) * mult;
    else
      frac = (int(val)- val ) * mult;
    unsigned long frac1 = frac;

    while(frac1 /= 10)
      padding--;

    while(padding--)
      strcat(outstr,"0\0");

    strcat(outstr,itoa(frac,temp,10));
  }

  // generate space padding 
  if ((widthp != 0)&&(widthp >= strlen(outstr))){
    byte J=0;
    J = widthp - strlen(outstr);
    
    for (i=0; i< J; i++) {
      temp[i] = ' ';
    }

    temp[i++] = '\0';
    strcat(temp,outstr);
    strcpy(outstr,temp);
  }
  
  return outstr;
}


void drawLine(void)
{
  unsigned char  j;  
   for(j=0; j<84; j++) // top
	{
          gotoXY (j,0);
	  LcdWrite (1,0x01);
  } 	
  for(j=0; j<84; j++) //Bottom
	{
          gotoXY (j,5);
	  LcdWrite (1,0x80);
  } 	

  for(j=0; j<6; j++) // Right
	{
          gotoXY (83,j);
	  LcdWrite (1,0xff);
  } 	
	for(j=0; j<6; j++) // Left
	{
          gotoXY (0,j);
	  LcdWrite (1,0xff);
  }

}

float VoltageToPPM(float voltage)
{
  return pow(b_k, voltage)/a_k;
}


void setup(void)
{
//analogReference(INTERNAL);
 LcdInitialise();
  LcdClear();
  gotoXY(0,0);
    if (pressure.begin())
    LcdString("BMP180 init success");
  else
  {
    // Oops, something went wrong, this is usually a connection problem,
    // see the comments at the top of this sketch for the proper connections.

   LcdString("BMP180 init fail\n\n");
    while(1); // Pause forever.
  }
  dht.begin(); 

}

void loop(void)
{
  sensorValue = analogRead(sensorPin);
  delay(50);
  sensorValue = analogRead(sensorPin);
  delay(50);
  char buf[20];
  float value=sensorValue*adc_step;
  gotoXY(0,0);
  LcdString("CO2:");
  LcdString(floatToString(buf, VoltageToPPM(value),1,5));
  LcdString("ppm");
  gotoXY(0,1);
   LcdString("CO2 V:");
  LcdString(floatToString(buf, value,4,5));
  
   gotoXY(0,2);
   delay(50);
  sensorValue = analogRead(vBattPin);
  delay(50);
  sensorValue = analogRead(vBattPin);
  value=sensorValue*adc_step;
  LcdString("V batt:");
  LcdString(floatToString(buf, value,3,4));
  
//  static bool led_on_off=true;
//    digitalWrite(ledPin, led_on_off);
//  led_on_off=!led_on_off;
  
    char status;
  double T,P,p0,a;

  // Loop here getting pressure readings every 10 seconds.

  // If you want sea-level-compensated pressure, as used in weather reports,
  // you will need to know the altitude at which your measurements are taken.
  // We're using a constant called ALTITUDE in this sketch:
 

  
  // If you want to measure altitude, and not pressure, you will instead need
  // to provide a known baseline pressure. This is shown at the end of the sketch.

  // You must first get a temperature measurement to perform a pressure reading.
  
  // Start a temperature measurement:
  // If request is successful, the number of ms to wait is returned.
  // If request is unsuccessful, 0 is returned.

  status = pressure.startTemperature();
  if (status != 0)
  {
    // Wait for the measurement to complete:
    delay(status);

    // Retrieve the completed temperature measurement:
    // Note that the measurement is stored in the variable T.
    // Function returns 1 if successful, 0 if failure.

    status = pressure.getTemperature(T);
    if (status != 0)
    {
      // Print out the measurement:
      //gotoXY(0,3);
     // LcdString("temp: ");
      //LcdString(floatToString(buf, T,1,4));
     // LcdString(" C");
      
      // Start a pressure measurement:
      // The parameter is the oversampling setting, from 0 to 3 (highest res, longest wait).
      // If request is successful, the number of ms to wait is returned.
      // If request is unsuccessful, 0 is returned.

      status = pressure.startPressure(2);
      if (status != 0)
      {
        // Wait for the measurement to complete:
        delay(status);

        // Retrieve the completed pressure measurement:
        // Note that the measurement is stored in the variable P.
        // Note also that the function requires the previous temperature measurement (T).
        // (If temperature is stable, you can do one temperature measurement for a number of pressure measurements.)
        // Function returns 1 if successful, 0 if failure.

        status = pressure.getPressure(P,T);
        if (status != 0)
        {
          // Print out the measurement:
          gotoXY(0,5);
          //lcd.print("ap ");
          LcdString(floatToString(buf, P*0.7501,1,4));
          //lcd.print(" mb");

          // The pressure sensor returns abolute pressure, which varies with altitude.
          // To remove the effects of altitude, use the sealevel function and your current altitude.
          // This number is commonly used in weather reports.
          // Parameters: P = absolute pressure in mb, ALTITUDE = current altitude in m.
          // Result: p0 = sea-level compensated pressure in mb

          p0 = pressure.sealevel(P,ALTITUDE); // we're at 1655 meters (Boulder, CO)
          LcdString("-");
          LcdString(floatToString(buf, p0*0.7501,1,4));
          //Serial.print(" mb, ");
          //Serial.print(p0*0.0295333727,2);
          //Serial.println(" inHg");

          // On the other hand, if you want to determine your altitude from the pressure reading,
          // use the altitude function along with a baseline pressure (sea-level or other).
          // Parameters: P = absolute pressure in mb, p0 = baseline pressure in mb.
          // Result: a = altitude in m.

          a = pressure.altitude(P,p0);

        }
        else LcdString("error retrieving pressure measurement\n");
      }
      else LcdString("error starting pressure measurement\n");
    }
    else LcdString("error retrieving temperature measurement\n");
  }
  else LcdString("error starting temperature measurement\n");

  float h = dht.readHumidity();
  float t = dht.readTemperature();
  gotoXY(0,4);
  if (isnan(t) || isnan(h)) {
   LcdString("Failed to read from DHT");
  } 
  else{
    LcdString(floatToString(buf, h,1,4));
    LcdString("%");
  }
     gotoXY(0,3);
     LcdString("temp: ");
     LcdString(floatToString(buf, t,1,4));
     LcdString(" C");
  delay(1000);
  
}

@St007
карма
0,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое

Комментарии (37)

  • +1
    Посмотрел на спеки MG811, зависимость есть, но она не настолько страшная и прекрасно корректируется, особенно имея остальной обвес (и температура и влажность). Зато датчик известный (мне сейчас такой едет), есть огромное число примеров, плюс огромная точность в вашем случае не нужна — частая ошибка гнаться за сотыми когда 10% ошибка ни на что не вляет. И стоит в два раза меньше. :)
    • +1
      Для себя я сделал вывод, что такого рода электрохимические датчики в радиолюбительской практике могут успешно применятся только как показометр относительного изменения концентрации СО2 при прочих не изменяемых факторах. Т.е. можно достоверно судить, что концентрация газа низкая или высокая, увеличилась или уменьшилась.

      Важно так же обратить внимание что выходное сопротивление датчика сотни и тысячи гига-Ом. Это на столько большое сопротивление, что хороший мультиметр для такого датчика будет как короткое замыкание. Как следствие играет роль проводимость текстолита, статические заряды, выходное напряжение будет меняться если протереть плату спиртом или если случайно коснуться контактов руками.

      Еще забавный момент, что применямый ОУ в первичной цепи усиления (в моем случае это CA3140 аналог μA741 ) имеет тера-омное входное сопротивление и был изобретен в далеком 1969 году.
      • +1
        На обычном операционнике вроде 140УД1 тоже можно собрать повторитель с входным сопротивлением в десятки сотни гигаом. Это лишь хитрая схемотехника.
        Если посмотреть схемотехнические решения измерительных приборов 60-х 70-х годов там можно набраться очень много интересных схемотехнических решений как из неидеальных деталей сделать идеальные измерительные приборы.
        Ещё тогда приборы умели измерять пикоамперы.
  • +7
    Спасибо) CO2 очень интересует, но с точки зрения профессионального применения. Сегодня прямо день Arduino на Хабре.
  • +1
    Выложите пожалуйста итоговую схему устройства и и сходный код
  • +3
    Ерундой вы товарищи занимаетесь! Хотя… Я же сам такой же девайс сделал на прошлых выходных :-P
    Собрал на базе Arduino Uno:

    • CO2 sensor: K-30 ($85)
    • Temp/Humidity: DHT-22
    • LCD 20x4 (I2C)

    Выбрал K-30 не случайно, точность у него ± 30 ppm ± 3 %. Срок службы больше 15 лет. Никакого обслуживания.
    Добавил пищалку к нему и светодиод. Светодиод начинает мигать после 700ppm. Количество миганий указывает на сколько сотен ppm значение больше нормы. После 1200ppm начинает пищать каждые 30 секунд.
    Почему это удобно? Краткий экскурс в историю… На улице иногда может быть прохладно, вариант постоянно открывать все окна на максимум — не вариант, иначе отопление бесполезное (деньги на ветер). Закрывать все тоже не вариант — два человека могут «надышать» уровень больше 1200ppm очень быстро. Поэтому приходится искать какой-то компромисс в количестве поступаемого воздуха с улицы.
    Данный девайс очень хорошо в этом помогает.
    Я могу смотреть телевизор и увидеть мигающий сигнал красного цвета с каким-то интервалом (на расстоянии 2-3 метра экран не прочитать). Если количество последовательных миганий 1-2 (800-900ppm) я в большинстве случаев ничего не делаю если знаю, что окна уже открыли сильнее или это кратковременный всплеск (кто-то рядом стоит). Если к-тво моргагий учащается или слышен сигнал — нужно бежать увеличить проветривание.

    Так выглядит мой девайс
    • 0
      Да, о таком датчике была публикация на хабре Тыц, но на али такого китайцы не продают, да и дороговато

      Если к-тво моргагий учащается или слышен сигнал — нужно бежать увеличить проветривание

      А представляете если в квартире еще газ-плита? Вот раньше не знал о реальной концентрации СО2 — жил спокойно, а теперь морока :) Для себя решил вопрос путем установки слабенькой принудительной вытяжки.

      Кстати, СО2 в комнатных условиях опускается или подымается? Как правильно говорить? А то судя по показаниям своего прибора так углекислый газ подымается (либо это приток свежего воздуха холодный и вытесняет теплый воздух)
    • 0
      Подскажите, где можно купить K-30.
      • 0
        Высылают по всему миру: CO2Meter.
        Но я бы возможно сейчас взял S8. Он за ту же цену но меньшего размера.
        • 0
          Вчитался в даташиты, сравнил точность:
          S8 — ±70ppm +5%
          К-30 — ± 30 ppm ± 3 %
          MH-Z14 — ±50ppm±5%
          и только через несколько недель работы компенсирующего алгоритма. Некоторые указывают, что будет дополнительная погрешность от давления, некоторые, что есть компенсация зависимости от температуры (а у остальных непонятно). Плюс это accuracy, к нему нужно ещё добавить precision для определения максимального отклонения. Плюс потеря точности, если использовать не цифровые выходы.
        • 0
          А какая доставка? Что-то к нам в Беларусь шлют только всякими UPS'ами за 90$ О_о
        • 0
          Нет, не по всему миру. Ответили что не высылают в Россию. После того как я возмутился, что я в Украине, ответили что и в Украину тоже.
        • 0
          И ценник конский.
          Я взял себе MG811.
          • 0
            Таки купил K30, т.к. MG811 вообще фигню какую-то выдаёт, либо я не умею его готовить.

            K30 сейчас тоже фигню показывает, но намного ближе к истине. Непонятно только, когда он откалибруется. Вроде как через 7.5 дней, я надеюсь.
  • 0
    Неужели проветривание время от времени дает результат? Я тоже заморочился померить и результаты оказались выше нормы.
    Причем в окне постоянно сифонит клапан, а сегодня всю ночь окно было приоткрыто, но все равно только к утру содержание углекислого газа упало ниже 1000. cloud.mail.ru/public/9a8662088df2/c02.png
    Задумался об установке проветривателей в комнаты.
    • 0
      Может, это в следствие пожаров в округе? или ветерок подул с загазованых участков…
      • 0
        Как вариант. Помониторю недельку и тогда буду думать как решать проблему, если она есть.
        • 0
          Тогда нужен еще флюгер с энкодером положения и анемометр. или подгружать данные по погоде с соответствующего сайта с направлением и силой ветра.
  • 0
    Кроме СО2 в воздухе могут находится и другие не менее вредные газы. Есть более дешевый датчик который реагирует на несколько газов сразу, его называют «датчик чистоты воздуха» и применяется он в кондиционерах. Может, лучше его использовать?

    Датчики конкретно для одного газа CO2 довольно дорогие и используют их в производственных помещениях — в котельнях например где есть опасность появления высоких концентраций. В быту ИМХО лучше использовать многофункциональный датчик, реагирующий на целый перечень газов. Он собственно и дешевле выходит.
    • 0
      какой именно датчик вы рекоммендуете, какова точность его работы?
      • 0
        Датчик MQ-135. Про точность данных не нашел.
        • 0
          Мне кажется, что для такого типа датчиков точность — бессмысленный параметр.
  • +1
    Чёрт бы побрал этот планшет. промахнулся и попал по минусу :((( Извините. Статья интересная.
  • 0
    А собственно, осциллограмма с какого участка цепи?
  • 0
    Штангенциркуль, дрель, надфиль и терпение помогли бы вам сделать окно под дисплей более эстетичным.
    На будущее обязательно используйте термоусадочные кембрики (dht-22 оголён).
    Провода используйте многожильные монтажные, мне лично нравятся мгтф.
    • 0
      Принято.
      То что на фото довольно криворукое поделие и я задумывался, выкладывать фото или нет. Но это лишь набросок готового устройства, первая итерация.
    • 0
      Не всегда помогает… Вот что помогает, так это наличие фрезерного станка или лазерной резки в пределах досягаемости.
  • 0
    А какой смысл в датчике, если зимой ничего нельзя сделать всё равно — центральное отопление шпарит так, что стрелка у прибора, меряющего влажность, просто падает вниз.
    • 0
      Значит есть смысл задуматься над покупкой увлажнителя. Плюс по прибору потом можно будет контролировать эффективность работы этого увлажнителя.
      • 0
        Есть простой аналоговый прибор, измеряющий влажность.
        • 0
          Есть простой увлажнитель с датчиком влажности.
          Зачем усложнять?

          P.S. в большинстве увлажнителей встроен датчик влажности и есть режим «Работать до влажности ХХ%»
  • 0
    Спасибо!
    а где TGS4161 вы покупали?
    На ибее чтоже нет и один датчик около 70$ а с платой вообще нет…
    • 0
      Я брал на Aliexpress, ситуация комичная: датчики вроде производят в США компания Figaro, а продают китайцы. О самой компании Figaro пару дней назад встречал хорошие отзывы: производитель одной DIY штуковины сигнализатора опасных газов упомянул что использует как раз датчики TGS от Figaro, мол они хоть и ощутимо повышают цену на готовое устройство, но зарекомендовали себя исключительно с положительно стороны.
  • 0
    Прочитав эту статью заказал китайский модуль на базе TGS4161
    С калибровкой очень сложно как-то у меня получаеться.

    Действительно, как описал автор для калибровки имеет значение некоторое НАЧАЛЬНОЕ НАПРЯЖЕНИЕ. Но вот этот показатель за моими наблюдениями меняется даже от незначительных механических сотрясений сенсора. (Еще его можно изменять с помощью правого потенциометра, но я его просто выставил в среднее значение, чтоб еще больше не запутаться). Вот думаю нет ли дефекта в моем модуле? Вобщем-то напрягает тот факт, что начальное напряжение очень нестабильное, может Tcm както может помочь стабилизировать?
    В моем случае четко видно, что напряжение падает при интенсивном дышании на сенсор, потом возвращаеться назад. При дышании напряжение падает максимум на 0.15 вольт.
    Заметил еще один момент — когда ставлю на форточку, напряжение падает, хотя я ожидал что оно должно расти, возможно так сильно влияет сквозняк или низкая температура.
    Я с помощью LEDKeypad Shield сделал небольшую системку для калибровки.

    Вот моя схемка подключения к ардуине. Ардуино питаеться от USB компьютера.
    image
    • 0
      Вот как раз как получит стабильные показатели с датчика это отдельная тема. Есть планы написать статью, но скорей всего руки дойдут только после НГ. На данный момент мне удалось все достаточно застабилизоровать, от температуры показания не зависят (выносил устройство с собой на улицу, температура была +5 градусов, ветер). На стабильность больше всего в моем случае влияло 1) самовозбуждение усилителя на плате с датчиком (решается установкой электролитического конденсатора на 1 мкФ на аналоговый выход платы с датчиком, если же поставить керамический конденсатор меньшей емкости, то амплитуда колебаний может только увеличиться). Второе это стабилизация питающего напряжения, оно должно быть в переделах плюс/минус 10 мВ без пульсаций, ну и третье это в Ардуине нужно делать подряд два три измерения и потом усреднять или брать последнее.
      Апроксимирующую кривую для вычислений концентрации СО2 я строил свою, и там важны калибровочные точки, не знаю на сколько правильно я сделал, но похоже можно матаппарат взять от MG811
      • 0
        Я чайник в электронике. Поэтому не совсем понял как можна стабилизировать напряжение? У меня есть стабилизатор L7805, он подейдет?

        С нетерпением жду статтю о том, как заставить этот модуль работать.
        • 0
          Открываем даташит на L7805 и смотрим на график зависимости напряжения от температуры. Делаем выводы. Для комнатных условий пойдет, но не более.
          А пульсации убираются только быстрой ОС и хорошими фильтрами(обычно это только конденсатор на выходе, но может быть и LC фильтр и на основе гираторов) но тут надо аккуратно — подобный стабилизатор напряжения надо рассматривать как САР и произвести расчет его устойчивости и хотябы определить границы устойчивости. Но наверно это всё НЕНУЖНЫЕ сложности, обычного электролитического/танталового конденсатора хватит + правильная разводка печатного монтажа(10мВ пульсаций под действием тока нагрузки получить за счет дорожек на плате от стабилизатора к нагрузке как нефиг делать даже на маленьких токах).

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.