geektimes

Arduino на службе здоровья — 2

  • среда, 19 ноября 2014 г. в 02:11:19
http://habrahabr.ru/post/243469/

Вдохновленный публикацией «Ардуино на службе здоровья», решил сделать свой «оптимизатор условий» с давлением и влажностями. Разумеется, немного модернизировав его по своему усмотрению.

Были использованы компоненты:

image Arduino Mini;
image Датчик температуры и влажности DHT-22;
image Барометр\альтиметр\термометр BMP180;

image Датчик CO2 с обвязкой;
image Модуль реле;
image Дисплей Nokia 5110.

Сразу хочу предупредить, что статья, аппаратная начинка, компоновка и софт не претендуют на идеальность, посему попрошу меня не пинать. Сильно.

Итак, по моей задумке, на дисплей должны выводиться все показатели, и желательно с анимацией.
Примеров было много, пришлось компоновать все в кучу. Заранее прошу прощения, с русским языком там проблемы.

Итак, скетч

#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <SFE_BMP180.h>
#include <Wire.h>
#include "DHT.h"
#define DHTPIN 2     // what pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302)
DHT dht(DHTPIN, DHTTYPE);
SFE_BMP180 pressure;
// D7 - Serial clock out (CLK oder SCLK)
// D6 - Serial data out (DIN)
// D5 - Data/Command select (DC oder D/C)
// D4 - LCD chip select (CE oder CS)
// D3 - LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);
int n = 0;
int tickstart = 60;
int tickend = 65;
int co2 = 0;
int sensorPin = A0;
String sp = "";
String tp = "";
String vp = "";
String cp = "";

void setup()   {

  // Инициализируем, устанавливаем контраст дисплея, и очищаем экран
  display.begin();
  display.setContrast(50);
  display.clearDisplay();
// Инициализируем датчик давления
  pressure.begin();
  Serial.begin(9600);
// Включаем реле
  pinMode(10, OUTPUT);
  digitalWrite(10, LOW);
// Ждем 20 секунд
  delay(20000);
// Считываем значение и гасим реле
  co2 = analogRead(A1);
  digitalWrite(10, HIGH);
// Инициализируем датчик температуры
  dht.begin();
}

void loop() {

// Блок барометра
  char status;
  double T,P,p0,a;
  char buf[32];
  status = pressure.startTemperature();
  if (status != 0)
  {
    // Wait for the measurement to complete:
    delay(status);
    status = pressure.getTemperature(T);
    if (status != 0)
    {
     status = pressure.startPressure(3);
      if (status != 0)
      {
        // Wait for the measurement to complete:
        delay(status);
        status = pressure.getPressure(P,T);
        if (status != 0)
        {
    //       Serial.println(P,0);
        }
      }
    }
  }
// Блок барометра  

// Блок термометра и датчика влажности
  float h = dht.readHumidity();
  float t = dht.readTemperature();

// Переводим в стринг
 
  P = P*0.75;
  dtostrf(P, 4, 0, buf);  String pres(buf);
  dtostrf(h, 4, 1, buf);  String hum(buf);
  dtostrf(t, 4, 1, buf);  String temp(buf);
  // Секция советов
  
  if (P<=755) {sp="Davlenie nizkoe, vipeyte kofe.";}
  if (P>=765) {sp="Davlenie visokoe, vipeyte analgin ili validol.";}
  if (P>=755 && P<=765) {sp="Davlenie v norme.";}
  
  if (h<=40) {vp="Vlaznost nizkaya, vkluchite uvlaznitel.";}
  if (h>=50) {vp="Vlaznost visokaya, vkluchite otoplenie.";}
  if (h>=40 && h<=50) {vp="Vlaznost v norme.";}
  if (co2<=480) {cp="Provetrite";}
  if (co2>=480) {cp="Vozduh v norme";}
  String sov=sp+vp+cp;
  String bb(n);
  String co2s(co2);
// Выводим на экран показатели
  display.setTextSize(1);
  set_text(1,0,"Pres "+pres+"mm",BLACK);
  set_text(70,0,bb,BLACK);
  set_text(1,8,"Humid "+hum+"%",BLACK);
  set_text(1,16,"Temp  "+temp+"C",BLACK);
  set_text(1,24,"Air   "+co2s+"ppm",BLACK);
  Serial.println(co2);
  display.drawLine(7,33,77,33,BLACK);
  display.display();
// Инкрементируем счетчик минут
  n++;
// Хитрый костыль: при достижении счетчика 60 минут, включаем реле
  if (n==tickstart) {
  digitalWrite(10, LOW);
  int x=0;
  for(int i=0;i<(5.6*8);i++){
    set_text(x,40,"Collecting CO2..",BLACK);
    delay(i==0?1000:300);
    if(i<(5.6*8)-1)set_text(x,40,"Collecting CO2..",WHITE);
    if((i)<(2.74*8))x-=1;else x+=1;
  }
       }
// Между 60-й и 65-й минутой, считываем показания датчика CO2
  if (n >= tickstart) {co2 = analogRead(A1);}
// На 65-й минуте сбрасываем реле.
  if (n==tickend) {digitalWrite(10, HIGH);n=0;}
 
// Движущийся текст с советами
  int x=0;
  for(int i=0;i<(5.6*8);i++){
    set_text(x,40,sov,BLACK);
    delay(i==0?1000:100);
    if(i<(5.6*8)-1)set_text(x,40,sov,WHITE);
    if((i)<(2.74*8))x-=1;else x+=1;
  } 
  
delay(60000); // Пауза примерно минуту
display.clearDisplay();
}
void set_text(int x,int y,String text,int color){
  display.setTextColor(color); 
  display.setCursor(x,y);
  display.println(text);
  display.display();
}


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

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

Переводом в PPM для CO2 я тоже решил не заморачиваться, просто проследив методом проб зависимость между проветренным помещением (650-670 единиц) и помещением после обогревания\горения свеч (400 единиц).

Итак, как оно выглядело в начале.

Датчик давления:



Датчик влажности:



Ардуина:



Реле:



Дисплей:



Так оно выглядит в сборе на соплях.



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



Размышления и сожаления.

Первоначально была идея подключить этот набор к Raspberry Pi. И вот тут выявились все подводные камни Малинки.
Датчик CO2 возвращает аналоговый сигнал. На малинке АЦП нет, подключать датчик не к чему.
Датчик CO2 имеет три пина для вывода цифрового сигнала. Но Малинка не умеет считывать PWM из коробки. Точнее теоретически умеет, но через огромную жопу огромный костыль с погрешностями в виде многократного опроса состояния GPIO программными методами. Упрощенно — считать, сколько раз за секунду было изменено состояние пина. Не ахти, но учитывая что мой датчик почему-то не возвращает цифровой код (хз, может где-то включить надо) — и не надо.
Есть у меня гламурный АЦП, управляемый через I2C, но чем и как его опрашивать с Малинки — мне матан не позволяет знать, посему буду рад за помощь.
На выходных, вытравлю маленькую плату под сугубо атмегу328 с выводом на плате только нужных мне пинов блоками (пин-gnd-vcc).


Видео работы, прошу прощения за качество, на выходных пересниму

Как вы думаете, поможет ли включение датчика СО2 раз в час, сэкономить ему ресурс работы?

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

Проголосовало 142 человека. Воздержалось 116 человек.