http://habrahabr.ru/post/243469/
Вдохновленный публикацией
«Ардуино на службе здоровья», решил сделать свой «оптимизатор условий» с давлением и влажностями. Разумеется, немного модернизировав его по своему усмотрению.
Были использованы компоненты:
Arduino Mini;
Датчик температуры и влажности DHT-22;
Барометр\альтиметр\термометр BMP180;
Датчик CO2 с обвязкой;
Модуль реле;
Дисплей 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).Видео работы, прошу прощения за качество, на выходных пересниму