Комнатная метеостанция с часами
- Войдите на сайт для отправки комментариев
Вс, 24/03/2013 - 21:26
Предлагаю еще вариант комнатной метеостанции с часами.
Проект скомпилирован из готовых решений, но кнопки установки времени в собственном варианте.
Отличие от многих опубликованных уже подобных решений в его законченности.
Набор стандартный:
Arduino - meduino pro mini mega 328;
DHT11 - влажность;
BMP085 - давление и температура;
DS1307 - часы;
LCD 16x2 - дисплей;
Адаптер 5 вольт miniUSB.
Для тех кто захочет повторить приведена схема со стороны монтажа:
Сторона монтажа:
Текст скетча для программирования устройства:
//----------------------------------------------------
// Домашняя метеостанция с часами
// 23 03 13 - проверено
// RN6LJK
// v 1
//-----------------------------------------------------
#include <LiquidCrystal.h>
#include <DS1307.h>
#include <Wire.h>
#include <dht.h>
#define I2C_ADDRESS 0x77
// DHT:
// Connect pin 1 (on the left) of the sensor to +5V
// Connect pin 2 of the sensor to whatever your DHTPIN is Arduino analog 0
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor
// создаём объект-сенсор
DHT sensor = DHT();
//BMP085:
// интерфейс I2C
// SDA - Arduino analog 4
// SCL - Arduino analog 5
// VCC - VCC
// GND - GROUND
const unsigned char oversampling_setting = 3; //oversamplig (передискретизация)
const unsigned char pressure_waittime[4] = { 5, 8, 14, 26 };
int ac1;
int ac2;
int ac3;
unsigned int ac4;
unsigned int ac5;
unsigned int ac6;
int b1;
int b2;
int mb;
int mc;
int md;
// DS1307:
// SDA pin -> Arduino Digital 2
// SCL pin -> Arduino Digital 3
// VCC - VCC
// GND - в моем случае подключение к GROUND блокирует работу DS1307,
// поэтому GND не подключено, причину так и не выяснил.
DS1307 rtc(2,3);
// Init a Time-data structure
Time t;
// set pin numbers:
const int buttonPin_sh = A1; // Установка ЧАСОВ
const int buttonPin_mn = A2; // Установка МИНУТЫ
const int buttonPin_dn = A3; // Установка ДЕНЬ
const int buttonPin_ms = 4; // Установка МЕСЯЦ
const int buttonPin_gd = 5; // Установка ГОД
const int buttonPin_nu = 12; // Установка МИНУТА СЕКУНДА В НОЛЬ
int sh;
int mn;
int sc;
int dn;
int ms;
int gd;
// LCD:
// VSS -gnd - на левый вывод потенц 15ком
// VDD- +5 wolt - на правый вывод потенц 15ком
// V0- на cредний вывод потенциометра 15ком
// RW - gnd
// DB7 -> Arduino Digital 6
// DB6 -> Arduino Digital 7
// DB5 -> Arduino Digital 8
// DB4 -> Arduino Digital 9
// E -> Arduino Digital 10
// RS -> Arduino Digital 11
// A - +5 wolt через потенц 1 ком
// K - gnd
LiquidCrystal lcd(11, 10, 9, 8, 7, 6);
// светодиод оставил для индикации работы устройства
const int ledPin = 13; // the number of the LED pin
//------------------------------------------------------
void setup()
{
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// LCD:
// Setup LCD to 16x2 characters
lcd.begin(16, 2);
// DS1307:
// Set the clock to run-mode - разрешить установку
rtc.halt(false);
// Программная установка времени для аварийных работ
// rtc.setDate(10,2,2013); // Set the date to October 3th, 2010
// rtc.setTime(22,00, 0); // Set the time to 12:00:00 (24hr format)
// rtc.setDOW(THURSDAY); // Set Day-of-Week to SUNDAY
// Set SQW/Out rate to 1Hz, and enable SQW
// rtc.setSQWRate(SQW_RATE_1);
// rtc.enableSQW(true);
//DHT11:
// методом attach объявляем к какому контакту подключен
// сенсор. В данном случае это нулевой аналоговый контакт
sensor.attach(A0);
//BMP085:
Wire.begin();
bmp085_get_cal_data();
}
void bmp085_read_temperature_and_pressure(int& temperature, long& pressure);
//---------------------------------------------------------
void loop()
{
//-------------У С Т А Н О В К А Д А Т Ы И В Р Е М Е Н И -------
// Ч А С Ы
if (digitalRead(buttonPin_sh) == HIGH) {
// светодиод оставил для индикации работы устройства
digitalWrite(ledPin, HIGH);
goto set_sh;
}
else {
digitalWrite(ledPin, LOW);
}
// М И Н У Т Ы - секунды в нуль
if (digitalRead(buttonPin_mn) == HIGH) {
// светодиод оставил для индикации работы устройства
digitalWrite(ledPin, HIGH);
goto set_mn;
}
else {
digitalWrite(ledPin, LOW);
}
// МИНУТА СЕКУНДА В НОЛЬ
if (digitalRead(buttonPin_nu) == HIGH) {
// светодиод оставил для индикации работы устройства
digitalWrite(ledPin, HIGH);
goto set_nu;
}
else {
digitalWrite(ledPin, LOW);
}
// ДЕНЬ
if (digitalRead(buttonPin_dn) == HIGH) {
// светодиод оставил для индикации работы устройства
digitalWrite(ledPin, HIGH);
goto set_dn;
}
else {
digitalWrite(ledPin, LOW);
}
// М Е С Я Ц
if (digitalRead(buttonPin_ms) == HIGH) {
// светодиод оставил для индикации работы устройства
digitalWrite(ledPin, HIGH);
goto set_ms;
}
else {
digitalWrite(ledPin, LOW);
}
// Г О Д
if (digitalRead(buttonPin_gd) == HIGH) {
// светодиод оставил для индикации работы устройства
digitalWrite(ledPin, HIGH);
goto set_gd;
}
else {
digitalWrite(ledPin, LOW);
}
//--------------------------
goto sen_d;
//----------ЧАСЫ------------------------------------
set_sh:
t = rtc.getTime();
sh=t.hour;
mn=t.min;
sc=t.sec;
sh=sh+1;
if (sh<=23)
{}
else{
sh=0;
}
rtc.setTime(sh,mn,sc); // Set the time to 12:00:00 (24hr format)
goto sen_d;
//-------------МИНУТЫ-----------------
set_mn:
t = rtc.getTime();
sh=t.hour;
mn=t.min;
sc=t.sec;
mn=mn+1;
if (mn<=59)
{}
else{
mn=0;
}
rtc.setTime(sh,mn,sc); // Set the time to 12:00:00 (24hr format)
goto sen_d;
//-------------МИНУТА СЕКУНДА В НОЛЬ-----------------
set_nu:
t = rtc.getTime();
sh=t.hour;
mn=0;
sc=0;
rtc.setTime(sh,mn,sc); // Set the time to 12:00:00 (24hr format)
goto sen_d;
//-------------Д Н И-----------------
set_dn:
t = rtc.getTime();
dn=t.date;
ms=t.mon;
gd=t.year;
dn=dn+1;
if (dn<=31)
{}
else{
dn=1;
}
rtc.setDate(dn, ms, gd); // Set the time to 12:00:00 (24hr format)
goto sen_d;
//-------------М Е С Я Ц Ы-----------------
set_ms:
t = rtc.getTime();
dn=t.date;
ms=t.mon;
gd=t.year;
ms=ms+1;
if (ms<=12)
{}
else{
ms=1;
}
rtc.setDate(dn, ms, gd); // Set the time to 12:00:00 (24hr format)
goto sen_d;
//-------------Г О Д Ы-----------------
set_gd:
t = rtc.getTime();
dn=t.date;
ms=t.mon;
gd=t.year;
gd=gd+1;
if (gd<=2033)
{}
else{
gd=2013;
}
rtc.setDate(dn, ms, gd); // Set the time to 12:00:00 (24hr format)
goto sen_d;
//------------ И Н Д И К А Ц И Я Р Е З У Л Ь Т А Т О В -------------
sen_d:
int temperature = 0;
long pressure = 0;
int temp=0;
float pres=0.0;
bmp085_read_temperature_and_pressure(&temperature,&pressure);
temp=temperature;
temp=temp/10;
pres=pressure;
pres=pres*0.0075;
pressure=pressure*0.0075;
// светодиод оставил для индикации работы устройства
digitalWrite(ledPin, HIGH);
lcd.setCursor(0, 0);
lcd.print(rtc.getTimeStr(FORMAT_SHORT));
lcd.setCursor(8, 0);
lcd.print(rtc.getDateStr(FORMAT_SHORT));
lcd.setCursor(0, 1);
lcd.print(temp);
lcd.print("`C");
// В Л А Ж Н О С Т Ь
// метод update заставляет сенсор выдать текущие измерения
sensor.update();
switch (sensor.getLastError())
{
case DHT_ERROR_OK:
char msg[128];
// данные последнего измерения можно считать соответствующими
// методами
// sprintf(msg, "Temperature = %dC, Humidity = %d%%",
// sensor.getTemperatureInt(), sensor.getHumidityInt());
// sprintf(msg, "%dC,%d%%",
sprintf(msg, "%d%%", sensor.getHumidityInt());
lcd.setCursor(6, 1);
lcd.print(msg);
break;
case DHT_ERROR_START_FAILED_1:
break;
case DHT_ERROR_START_FAILED_2:
break;
case DHT_ERROR_READ_TIMEOUT:
break;
case DHT_ERROR_CHECKSUM_FAILURE:
break;
}
lcd.setCursor(11, 1);
lcd.print(pressure,DEC);
lcd.print("mm");
// светодиод оставил для индикации работы устройства
digitalWrite(ledPin, LOW);
// Wait one second before repeating :)
delay (1000);
}
//------ ОБРАБОТКА РЕЗУЛЬТАТОВ ОТ BMP085 --------------------
void bmp085_read_temperature_and_pressure(int* temperature, long* pressure) {
long ut = bmp085_read_ut();
long up = bmp085_read_up();
long x1, x2, x3, b3, b5, b6, p;
unsigned long b4, b7;
//расчет температуры
x1 = ((long) ut - ac6) * ac5 >> 15;
x2 = ((long) mc << 11) / (x1 + md);
b5 = x1 + x2;
*temperature = (b5 + 8) >> 4;
//расчет давления
b6 = b5 - 4000;
x1 = (b2 * (b6 * b6 >> 12)) >> 11;
x2 = ac2 * b6 >> 11;
x3 = x1 + x2;
if (oversampling_setting == 3) b3 = ((int32_t) ac1 * 4 + x3 + 2) << 1;
if (oversampling_setting == 2) b3 = ((int32_t) ac1 * 4 + x3 + 2);
if (oversampling_setting == 1) b3 = ((int32_t) ac1 * 4 + x3 + 2) >> 1;
if (oversampling_setting == 0) b3 = ((int32_t) ac1 * 4 + x3 + 2) >> 2;
x1 = ac3 * b6 >> 13;
x2 = (b1 * (b6 * b6 >> 12)) >> 16;
x3 = ((x1 + x2) + 2) >> 2;
b4 = (ac4 * (uint32_t) (x3 + 32768)) >> 15;
b7 = ((uint32_t) up - b3) * (50000 >> oversampling_setting);
p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;
x1 = (p >> 8) * (p >> 8);
x1 = (x1 * 3038) >> 16;
x2 = (-7357 * p) >> 16;
*pressure = p + ((x1 + x2 + 3791) >> 4);
}
unsigned int bmp085_read_ut() {
write_register(0xf4,0x2e);
delay(5); //дольше чем 4.5 мс
return read_int_register(0xf6);
}
void bmp085_get_cal_data() {
ac1 = read_int_register(0xAA);
ac2 = read_int_register(0xAC);
ac3 = read_int_register(0xAE);
ac4 = read_int_register(0xB0);
ac5 = read_int_register(0xB2);
ac6 = read_int_register(0xB4);
b1 = read_int_register(0xB6);
b2 = read_int_register(0xB8);
mb = read_int_register(0xBA);
mc = read_int_register(0xBC);
md = read_int_register(0xBE);
}
long bmp085_read_up() {
write_register(0xf4,0x34+(oversampling_setting<<6));
delay(pressure_waittime[oversampling_setting]);
unsigned char msb, lsb, xlsb;
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(0xf6); // register to read
Wire.endTransmission();
Wire.requestFrom(I2C_ADDRESS, 3); // read a byte
while(!Wire.available()) {
// ожидание
}
msb = Wire.read();
while(!Wire.available()) {
// ожидание
}
lsb |= Wire.read();
while(!Wire.available()) {
// ожидание
}
xlsb |= Wire.read();
return (((long)msb<<16) | ((long)lsb<<8) | ((long)xlsb)) >>(8-oversampling_setting);
}
void write_register(unsigned char r, unsigned char v)
{
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(r);
Wire.write(v);
Wire.endTransmission();
}
char read_register(unsigned char r)
{
unsigned char v;
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(r); // register to read
Wire.endTransmission();
Wire.requestFrom(I2C_ADDRESS, 1); // read a byte
while(!Wire.available()) {
// ожидание
}
v = Wire.read();
return v;
}
int read_int_register(unsigned char r)
{
unsigned char msb, lsb;
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(r); // register to read
Wire.endTransmission();
Wire.requestFrom(I2C_ADDRESS, 2); // read a byte
while(!Wire.available()) {
// ожидание
}
msb = Wire.read();
while(!Wire.available()) {
// ожидание
}
lsb = Wire.read();
return (((int)msb<<8) | ((int)lsb));
}
//--------------------------------------------
-------------------------------------------------------
Законченное устройство заняло свое место над зеркалом в прихожей:
Отличная работа , но трудно повтаряемая для пайки. Вот бы печатку в .lay , было бы вообще классно.
Поздравляю! Зачетный проект
Монтаж выполнен на макетной плате. Распайка монтажным проводом.
Я специально показал рисунок со стороны пайки для тех кто захочет повторить.
Лучше не могу ничего предложить.
Если расположить все элементы так как это сделал я, то распайка не покажется такой уж сложной.
RTC-шилд бы еще на 3231 вместо 1307. Последний уж совсем плохую точность имеет. Корректировать время надоедает. А так, да, симпатично.
RTC-шилд бы еще на 3231 вместо 1307. Последний уж совсем плохую точность имеет. Корректировать время надоедает. А так, да, симпатично.
согласен, ds1307 губят плохие внешние кварцы, а в ds3231 он встроенный
но я пошел еще дальше - у меня часы синхронихзируют время по радио с контроллером который синхронизирует время по интернет. в итоге время не то что корректировать не нужно, его даже один раз настраивать не нужно, вот сейас вернут зимнее время, а мои часики все сами переведутся. Да и тогда уже не важно - есть батарейное питание или нет, ds1307 или ds3231 - без разницы. Кстати отлично работает вариант с внешним кварцем на 32768 - у МК есть специальный режим ассинхронного таймера как раз для таких нужд
Когда я занялся построением этой станции меня также смущали отзывы о недостаточной точности 1307.
Штатную батарейку на 3.5 вотльта я заменил 3-х вольтовой т.к. штатная была кривая, а на 3.5 я не нашел.
За время работы станции с февраля 2013 по сегодняшний день время корректировалось один раз, если мне не изменяет память, то где то в октябре. Уход тогда составил около 2.5 - 3 -х минут в сторону отставания. На сегодняшний день часы отстают примерно 1.5 минуты.
да нет, что вы, ds1307 вполне рабочая лошадка и служит миру уже много лет. Это мы брюзжим от того, что сегодня есть фишки лучше)) У ds3231 заявленный уход часов на уровне пары секунд в год
По данным производителя, уход там все же чуть побольше (хотя они могут завышать его величину в паспортных данных), но есть возможность в небольших пределах подстраивать точность хода.
Насчет синхронизации по интернету, оно конечно самое мощное средство контроля точности, но оно же самое сложное и самое дорогое. В свое время я, чтобы не усложнять конструкцию, просто написал скрипт на компе, который выдергивает время по NTP и кидает через ком-порт в часики. В часах прошивка МК корректирует RTC и определяет погрешность, по которой самостоятельно вычисляет необходимую поправку, чтобы впоследствие использовать ее для автономной корректировки часов через определенный промежуток времени. В приницпе, после нескольких ручных синхронизаций, часы начинают ходить весьма точно.
Помимо прочего, я описал этот механизм еще и затем, что бы так ненавязчиво подбросить описанную идею автору топика, а уж он бы смог реализовать ее в своем проекте. :) Кнопки, кстати, после этого можно будет убрать вообще.
Насчет синхронизации по интернету, оно конечно самое мощное средство контроля точности, но оно же самое сложное и самое дорогое.
можно сделать просто и не дорого. Я завершил 4 устройства и во всех есть часы с синхронизаией по интернету, при этом в двух устройствах DS3231, в одном асинхронный режим таймера МК с внешним часовым кварцем, а еще на одном - обычный кварц на 16 Мгц и таймер настроенный на срабатывание раз в секунду. Все ходят точно, пока не нарушена работа контроллера умного дома от которого и запрашивается время. Вот здесь описывал http://arduino.ru/forum/proekty/umnyi-dom-s-tsentralnym-kontrollerom-ot-.... Все что нужно новому устройству - радиомодуль nrf24 и пара вызовов внутри основного цикла, вот так просим дать нам новое время:
а так ловим ответ и используем результат:
код немного "выдран" из контекста, но тут вся логика синхронизации, если кому будет интересно - поясню
Проект отличный! Только дайте, плиз, ссылку на библиотеки DS1307 и DHT11, которые использовалась в проекте.
Сообщите свой E-mail или напишите мне на sokolova_o@mail.ru я вышлю Вам библиотеки из моего проекта. Мне так проще, т.к. библиотек на самом деле существует несколько и откуда я скачивал свои не помню.
mit551@rambler.ru
Спасибо!
На схеме DHT11 странно подключен. 1 и 2 ножки к питанию притянуты и с него же на А0 контроллера.
Спасибо за замечание. Действительно это ошибка в чертеже. Лишняя точка на пересечении с VCC
Добрый день!!! Проект отличный !!! А можно мне тоже все библиотеки выслать на yuraivan10@ukr.net
Здравствуйте! Понравился ваш проект, не угостите библиотеками на avk.yugs@gmail.com
Спасибо за проект!
Повторил один в один на макетке, только вместо датчика BMP085 использовал BMP180, все работает!
Еще раз спасибо!
Проект достойный уважения!
Будьте любезны, пришлите пожалуйста библиотеки.
strim2@gmail.com
Спасибо.
Спасибо за внимание к проекту.
Библиотеки отправил.
А вот моя метео станция + часы
Loginkr , на 2-ух МАХ7219?
Да
Будьте любезны, и мне пришлите пожалуйста библиотеки.
samoilga(собака)yandex.ru
Заранее Спасибо!
Пожалуйста.
Отправил.
To RN6LJK. Спасибо, получил. А почему DS-1307 подключен без земли ?
Я вроде выше писал. А может хотел написать. Короче говоря с землей у меня это модуль не заработал. Разбираться не стал.
Здравствуйте. Что-то никак Ваш проект не идет у меня. Пожалуйста пришлите Ваши библиотеки, если не трудно.
Почта krava62@mail.ru Заранее благодарю.
Добрый день.
Отправил.
у меня часы синхронихзируют время по радио с контроллером который синхронизирует время по интернет. в итоге время не то что корректировать не нужно, его даже один раз настраивать не нужно, вот сейас вернут зимнее время, а мои часики все сами переведутся.
доброго времени суток.
а можно схему и код для того чтоб время и дату брать с инета и передавать на другие устрайства.
Спасибо за библиотеки. Все равно ничгео не показывает... А какая у Вас марка дисплея?
Проблемой синхронизации через интернет я не занимался.
На схеме указан тип - дисплей LCD 16x2. Штука стандартная, добавит ничего не могу. Попробуйте кправлять своим дисплеем при помощи простых процедур вне данного проекта. В приложении к библиотекам есть масса примеров.
Если на дисплее ничего не видно, то вполне допускаю ошибку в монтаже или отсутствие напряжения на управляющих яркостью ножках устройства. Попробуйте просто покрутить потенциометр упраления яркостью, может он просто задавлен и вы ничего не видите.
Lexel я отправил на krava62@mail.ru стандартные библиотеки для LCD попробуйте отсюда взять примеры
Вот хорошая ссылка с примером для подключения LCD - http://cxem.net/arduino/arduino12.php
Еще классика для LCD http://arduino.cc/en/Tutorial/LiquidCrystal - вообще разжевано
Для lexel
Все получится, только будьте внимательнее.
Самое обидное, что все Ваши примеры прекрасно работают...
В чудеса не верю. Надо искать ошибку. Кстати вы учли вышеуказанное замечание от Umka
На схеме DHT11 странно подключен. 1 и 2 ножки к питанию притянуты и с него же на А0 контроллера.
Лишняя точка на пересечении с VCC
???
Сейчас вообще все отключено, кроме дисплея. И никак.
Фотографию дисплея со стороны платы опубликуйте. У меня уже коллекция библиотек под разных китайцев собрана.
Не пойму. Ведь опубликованные снимки и сделаны со стороны платы.
Извините, я писал для lexel.
Все нашел косяк! Датчик глючный был, причем в другой схеме работал.
Мои поздравления!
Спасибо, думал крыша стечет!
Хорошая работа. Хочу повторить под другой LCD. Из-за моих библиотек компилируется с ошибками. Сбросьте на viazelenko@rambler. ru библиотеки проекта.
Ваш адрес viazelenko@rambler. ru воспринимается как ошибочный??? Попоробуйте исправить.
пробел перед ру убрать :)
Пардон, не заметил. Отправил.